refactor(P2): standardize API responses + fix migrations + cleanup DI
Wave 3 — 3 parallel agents fixing P2 code quality issues:
Response format standardization (30 controllers across 8 services):
- Wrapped all raw DTO returns with { success: true, data: result }
- Standardized error responses with { success: false, error: { code, message } }
- Services: chat, social, membership, ads-manager, ads-serving,
ads-billing, ads-tracking, ads-analytics
- booking-service already compliant (skipped)
Migration fixes:
- ads-billing: Fixed InvoiceId1 spurious FK (explicit HasMany navigation)
- Removed unused IRequestManager DI from: ads-analytics, ads-serving,
booking, mkt-facebook (classes preserved for future use)
Unused dependencies:
- No Redis/Dapper DI registrations found (only NuGet refs, kept as-is)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -74,7 +74,7 @@ public class AdminMetricsController : ControllerBase
|
||||
|
||||
_logger.LogInformation("Generated platform overview for period {Start} to {End}", start, end);
|
||||
|
||||
return Ok(overview);
|
||||
return Ok(new { success = true, data = overview });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,7 +89,7 @@ public class AdminMetricsController : ControllerBase
|
||||
{
|
||||
var validMetrics = new[] { "spend", "impressions", "clicks", "revenue", "roas" };
|
||||
if (!validMetrics.Contains(metric.ToLower()))
|
||||
return BadRequest(new { message = $"Invalid metric. Valid options: {string.Join(", ", validMetrics)}" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = $"Invalid metric. Valid options: {string.Join(", ", validMetrics)}" } });
|
||||
|
||||
// EN: Get metrics from last 30 days
|
||||
// VI: Lấy metrics 30 ngày gần nhất
|
||||
@@ -129,7 +129,7 @@ c.TotalClicks, "Clicks")).ToList(),
|
||||
|
||||
_logger.LogInformation("Generated top {Limit} campaigns by {Metric}", limit, metric);
|
||||
|
||||
return Ok(topCampaigns);
|
||||
return Ok(new { success = true, data = topCampaigns });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -142,6 +142,6 @@ c.TotalClicks, "Clicks")).ToList(),
|
||||
{
|
||||
_logger.LogWarning("GetAnomalies not yet implemented");
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { message = "Anomaly detection will be implemented in future version with ML models" });
|
||||
new { success = false, error = new { code = "NOT_IMPLEMENTED", message = "Anomaly detection will be implemented in future version with ML models" } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class AdminReportsController : ControllerBase
|
||||
|
||||
_logger.LogInformation("Admin retrieved {Count} reports", reports.Count);
|
||||
|
||||
return Ok(reports);
|
||||
return Ok(new { success = true, data = reports });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +68,7 @@ public class AdminReportsController : ControllerBase
|
||||
var report = await _context.Reports.FindAsync(id);
|
||||
|
||||
if (report == null)
|
||||
return NotFound(new { message = $"Report {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Report {id} not found" } });
|
||||
|
||||
_context.Reports.Remove(report);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@@ -37,11 +37,11 @@ public class BreakdownController : ControllerBase
|
||||
[FromQuery] DateTime? endDate = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(by))
|
||||
return BadRequest(new { message = "Breakdown dimension 'by' is required" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Breakdown dimension 'by' is required" } });
|
||||
|
||||
var validDimensions = new[] { "age", "gender", "device", "placement" };
|
||||
if (!validDimensions.Contains(by.ToLower()))
|
||||
return BadRequest(new { message = $"Invalid dimension. Valid options: {string.Join(", ", validDimensions)}" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = $"Invalid dimension. Valid options: {string.Join(", ", validDimensions)}" } });
|
||||
|
||||
// EN: Return mock data (full implementation requires event tracking data)
|
||||
// VI: Trả về mock data (triển khai đầy đủ cần dữ liệu tracking)
|
||||
@@ -50,7 +50,7 @@ public class BreakdownController : ControllerBase
|
||||
_logger.LogInformation("Generated mock breakdown data for campaign {CampaignId} by {Dimension}",
|
||||
id, by);
|
||||
|
||||
return Ok(mockBreakdown);
|
||||
return Ok(new { success = true, data = mockBreakdown });
|
||||
}
|
||||
|
||||
private CampaignBreakdownDto GenerateMockBreakdown(Guid campaignId, string dimension)
|
||||
|
||||
@@ -46,7 +46,7 @@ public class InsightsController : ControllerBase
|
||||
|
||||
_logger.LogInformation("Generated audience insights for campaign {CampaignId}", campaignId);
|
||||
|
||||
return Ok(insights);
|
||||
return Ok(new { success = true, data = insights });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,6 +83,6 @@ public class InsightsController : ControllerBase
|
||||
|
||||
_logger.LogInformation("Generated performance insights for advertiser {AdvertiserId}", advertiserId);
|
||||
|
||||
return Ok(insights);
|
||||
return Ok(new { success = true, data = insights });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ public class MetricsController : ControllerBase
|
||||
var metrics = await _mediator.Send(query);
|
||||
|
||||
if (metrics == null)
|
||||
return NotFound(new { message = $"No metrics found for campaign {id}" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"No metrics found for campaign {id}" } });
|
||||
|
||||
return Ok(metrics);
|
||||
return Ok(new { success = true, data = metrics });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,8 +71,8 @@ public class MetricsController : ControllerBase
|
||||
public IActionResult GetAdSetMetrics(Guid id)
|
||||
{
|
||||
_logger.LogWarning("AdSet metrics not yet implemented");
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { message = "AdSet metrics endpoint not yet implemented" });
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { success = false, error = new { code = "NOT_IMPLEMENTED", message = "AdSet metrics endpoint not yet implemented" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -84,7 +84,7 @@ public class MetricsController : ControllerBase
|
||||
public IActionResult GetAdMetrics(Guid id)
|
||||
{
|
||||
_logger.LogWarning("Ad metrics not yet implemented");
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { message = "Ad metrics endpoint not yet implemented" });
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { success = false, error = new { code = "NOT_IMPLEMENTED", message = "Ad metrics endpoint not yet implemented" } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ReportsController : ControllerBase
|
||||
};
|
||||
|
||||
var reports = await _mediator.Send(query);
|
||||
return Ok(reports);
|
||||
return Ok(new { success = true, data = reports });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -63,10 +63,10 @@ public class ReportsController : ControllerBase
|
||||
[FromQuery] Guid advertiserId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
return BadRequest(new { message = "Report name is required" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Report name is required" } });
|
||||
|
||||
if (!Enum.TryParse<ReportType>(request.ReportType, out var reportType))
|
||||
return BadRequest(new { message = "Invalid report type" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Invalid report type" } });
|
||||
|
||||
var command = new CreateReportCommand
|
||||
{
|
||||
@@ -79,7 +79,7 @@ public class ReportsController : ControllerBase
|
||||
|
||||
var reportId = await _mediator.Send(command);
|
||||
|
||||
return CreatedAtAction(nameof(GetReportById), new { id = reportId }, reportId);
|
||||
return CreatedAtAction(nameof(GetReportById), new { id = reportId }, new { success = true, data = reportId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -92,7 +92,7 @@ public class ReportsController : ControllerBase
|
||||
{
|
||||
_logger.LogWarning("GetReportById not yet fully implemented");
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { message = "Get report by ID endpoint not yet implemented" });
|
||||
new { success = false, error = new { code = "NOT_IMPLEMENTED", message = "Get report by ID endpoint not yet implemented" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +105,7 @@ public class ReportsController : ControllerBase
|
||||
{
|
||||
_logger.LogWarning("ScheduleReport not yet implemented");
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { message = "Schedule report endpoint will be implemented in future version" });
|
||||
new { success = false, error = new { code = "NOT_IMPLEMENTED", message = "Schedule report endpoint will be implemented in future version" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -118,6 +118,6 @@ public class ReportsController : ControllerBase
|
||||
{
|
||||
_logger.LogWarning("ExportReport not yet implemented");
|
||||
return StatusCode(StatusCodes.Status501NotImplemented,
|
||||
new { message = "Export report endpoint will be implemented in future version" });
|
||||
new { success = false, error = new { code = "NOT_IMPLEMENTED", message = "Export report endpoint will be implemented in future version" } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using AdsAnalyticsService.Infrastructure.Idempotency;
|
||||
|
||||
namespace AdsAnalyticsService.Infrastructure;
|
||||
|
||||
@@ -30,7 +29,9 @@ public static class DependencyInjection
|
||||
}
|
||||
});
|
||||
|
||||
services.AddScoped<IRequestManager, RequestManager>();
|
||||
// EN: Idempotency services not registered — no handler uses IRequestManager
|
||||
// VI: Idempotency services không được đăng ký — không có handler nào dùng IRequestManager
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class BillingAccountsController : ControllerBase
|
||||
|
||||
var accountId = await _mediator.Send(command);
|
||||
|
||||
return CreatedAtAction(nameof(GetBillingAccount), new { id = accountId }, accountId);
|
||||
return CreatedAtAction(nameof(GetBillingAccount), new { id = accountId }, new { success = true, data = accountId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,10 +57,10 @@ public class BillingAccountsController : ControllerBase
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
return NotFound(new { message = $"Billing account {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Billing account {id} not found" } });
|
||||
}
|
||||
|
||||
return Ok(account);
|
||||
return Ok(new { success = true, data = account });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,7 +77,7 @@ public class BillingAccountsController : ControllerBase
|
||||
|
||||
if (request.Amount <= 0)
|
||||
{
|
||||
return BadRequest(new { message = "Amount must be positive" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Amount must be positive" } });
|
||||
}
|
||||
|
||||
var command = new AddFundsCommand(id, request.Amount);
|
||||
@@ -85,10 +85,10 @@ public class BillingAccountsController : ControllerBase
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return NotFound(new { message = $"Billing account {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Billing account {id} not found" } });
|
||||
}
|
||||
|
||||
return Ok(new { accountId = id, amountAdded = request.Amount });
|
||||
return Ok(new { success = true, data = new { accountId = id, amountAdded = request.Amount } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,10 +107,10 @@ public class BillingAccountsController : ControllerBase
|
||||
|
||||
if (balance == null)
|
||||
{
|
||||
return NotFound(new { message = $"Billing account {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Billing account {id} not found" } });
|
||||
}
|
||||
|
||||
return Ok(new { accountId = id, balance = balance.Value });
|
||||
return Ok(new { success = true, data = new { accountId = id, balance = balance.Value } });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,14 +43,14 @@ public class CreditLinesController : ControllerBase
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
return NotFound(new { message = $"Billing account for advertiser {advertiserId} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Billing account for advertiser {advertiserId} not found" } });
|
||||
}
|
||||
|
||||
var availableCredit = account.CreditLimit <= 0
|
||||
? 0m
|
||||
: Math.Max(0m, account.CreditLimit - account.Balance);
|
||||
|
||||
return Ok(new
|
||||
return Ok(new { success = true, data = new
|
||||
{
|
||||
advertiserId,
|
||||
accountId = account.Id,
|
||||
@@ -59,7 +59,7 @@ public class CreditLinesController : ControllerBase
|
||||
availableCredit,
|
||||
paymentMethod = account.PaymentMethod.ToString(),
|
||||
status = account.Status.ToString()
|
||||
});
|
||||
} });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ public class CreditLinesController : ControllerBase
|
||||
|
||||
if (request.RequestedAmount <= 0)
|
||||
{
|
||||
return BadRequest(new { message = "Requested amount must be positive" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Requested amount must be positive" } });
|
||||
}
|
||||
|
||||
var account = await _context.BillingAccounts
|
||||
@@ -86,14 +86,14 @@ public class CreditLinesController : ControllerBase
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
return NotFound(new { message = $"Billing account for advertiser {request.AdvertiserId} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Billing account for advertiser {request.AdvertiserId} not found" } });
|
||||
}
|
||||
|
||||
var oldCreditLimit = account.CreditLimit;
|
||||
account.SetCreditLimit(oldCreditLimit + request.RequestedAmount);
|
||||
await _context.SaveEntitiesAsync(cancellationToken);
|
||||
|
||||
return Accepted(new
|
||||
return Accepted(new { success = true, data = new
|
||||
{
|
||||
advertiserId = request.AdvertiserId,
|
||||
accountId = account.Id,
|
||||
@@ -102,7 +102,7 @@ public class CreditLinesController : ControllerBase
|
||||
newCreditLimit = account.CreditLimit,
|
||||
status = account.Status.ToString(),
|
||||
message = "Credit limit increased successfully"
|
||||
});
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,13 +42,13 @@ public class InvoicesController : ControllerBase
|
||||
var query = new GetInvoicesQuery(billingAccountId, status, pageNumber, pageSize);
|
||||
var invoices = await _mediator.Send(query);
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
return Ok(new { success = true, data = new
|
||||
{
|
||||
pageNumber,
|
||||
pageSize,
|
||||
total = invoices.Count,
|
||||
data = invoices
|
||||
});
|
||||
items = invoices
|
||||
} });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,10 +67,10 @@ public class InvoicesController : ControllerBase
|
||||
|
||||
if (invoice == null)
|
||||
{
|
||||
return NotFound(new { message = $"Invoice {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Invoice {id} not found" } });
|
||||
}
|
||||
|
||||
return Ok(invoice);
|
||||
return Ok(new { success = true, data = invoice });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,7 +90,7 @@ public class InvoicesController : ControllerBase
|
||||
|
||||
if (invoice == null)
|
||||
{
|
||||
return NotFound(new { message = $"Invoice {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Invoice {id} not found" } });
|
||||
}
|
||||
|
||||
var lineItemsContent = invoice.LineItems.Any()
|
||||
|
||||
@@ -67,14 +67,15 @@ public class InvoiceEntityTypeConfiguration : IEntityTypeConfiguration<Invoice>
|
||||
.HasColumnType("decimal(18,2)")
|
||||
.IsRequired();
|
||||
|
||||
// EN: Line items as collection / VI: Các dòng chi tiết
|
||||
builder.HasMany<InvoiceLineItem>()
|
||||
// EN: Line items as owned collection via navigation property
|
||||
// VI: Các dòng chi tiết qua navigation property
|
||||
// NOTE: Must use the navigation expression to avoid EF creating a shadow InvoiceId1 FK
|
||||
var navigation = builder.Metadata.FindNavigation(nameof(Invoice.LineItems))!;
|
||||
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
|
||||
|
||||
builder.HasMany(i => i.LineItems)
|
||||
.WithOne()
|
||||
.HasForeignKey("InvoiceId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// EN: Metadata / VI: Ignore navigation property for EF Core
|
||||
builder.Metadata.FindNavigation(nameof(Invoice.LineItems))!
|
||||
.SetPropertyAccessMode(PropertyAccessMode.Field);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class AdSetsController : ControllerBase
|
||||
|
||||
var adSetId = await _mediator.Send(command);
|
||||
|
||||
return CreatedAtAction(nameof(GetAdSetById), new { id = adSetId }, adSetId);
|
||||
return CreatedAtAction(nameof(GetAdSetById), new { id = adSetId }, new { success = true, data = adSetId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,8 +53,8 @@ public class AdSetsController : ControllerBase
|
||||
var adSet = await _mediator.Send(new GetAdSetByIdQuery { AdSetId = id });
|
||||
|
||||
if (adSet == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Ad set not found" } });
|
||||
|
||||
return Ok(adSet);
|
||||
return Ok(new { success = true, data = adSet });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class AdminAdsController : ControllerBase
|
||||
PageSize = pageSize
|
||||
});
|
||||
|
||||
return Ok(ads);
|
||||
return Ok(new { success = true, data = ads });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,7 +58,7 @@ public class AdminAdsController : ControllerBase
|
||||
var result = await _mediator.Send(new ApproveAdCommand { AdId = id });
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Ad not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class AdminAdsController : ControllerBase
|
||||
});
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Ad not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class AdminCampaignsController : ControllerBase
|
||||
};
|
||||
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,7 +55,7 @@ public class AdminCampaignsController : ControllerBase
|
||||
public async Task<ActionResult<CampaignStatsDto>> GetCampaignStats()
|
||||
{
|
||||
var stats = await _mediator.Send(new GetCampaignStatsQuery());
|
||||
return Ok(stats);
|
||||
return Ok(new { success = true, data = stats });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class AdminReportsController : ControllerBase
|
||||
public async Task<ActionResult<List<TopAdvertiserDto>>> GetTopAdvertisers([FromQuery] int limit = 10)
|
||||
{
|
||||
var advertisers = await _mediator.Send(new GetTopAdvertisersQuery { Limit = limit });
|
||||
return Ok(advertisers);
|
||||
return Ok(new { success = true, data = advertisers });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,7 +51,7 @@ public class AdminReportsController : ControllerBase
|
||||
EndDate = endDate
|
||||
});
|
||||
|
||||
return Ok(analytics);
|
||||
return Ok(new { success = true, data = analytics });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class AdsController : ControllerBase
|
||||
|
||||
var adId = await _mediator.Send(command);
|
||||
|
||||
return CreatedAtAction(nameof(GetAdById), new { id = adId }, adId);
|
||||
return CreatedAtAction(nameof(GetAdById), new { id = adId }, new { success = true, data = adId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,9 +53,9 @@ public class AdsController : ControllerBase
|
||||
var ad = await _mediator.Send(new GetAdByIdQuery { AdId = id });
|
||||
|
||||
if (ad == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Ad not found" } });
|
||||
|
||||
return Ok(ad);
|
||||
return Ok(new { success = true, data = ad });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,7 +72,7 @@ public class AdsController : ControllerBase
|
||||
var result = await _mediator.Send(new SubmitAdForReviewCommand { AdId = id });
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Ad not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class AudiencesController : ControllerBase
|
||||
|
||||
var audiences = await _mediator.Send(new ListAudiencesQuery { AdvertiserId = advertiserId });
|
||||
|
||||
return Ok(audiences);
|
||||
return Ok(new { success = true, data = audiences });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,9 +51,9 @@ public class AudiencesController : ControllerBase
|
||||
var audience = await _mediator.Send(new GetAudienceByIdQuery { AudienceId = id });
|
||||
|
||||
if (audience == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Audience not found" } });
|
||||
|
||||
return Ok(audience);
|
||||
return Ok(new { success = true, data = audience });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class CampaignsController : ControllerBase
|
||||
|
||||
var campaignId = await _mediator.Send(command);
|
||||
|
||||
return CreatedAtAction(nameof(GetCampaignById), new { id = campaignId }, campaignId);
|
||||
return CreatedAtAction(nameof(GetCampaignById), new { id = campaignId }, new { success = true, data = campaignId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,7 +66,7 @@ public class CampaignsController : ControllerBase
|
||||
};
|
||||
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,9 +81,9 @@ public class CampaignsController : ControllerBase
|
||||
var campaign = await _mediator.Send(new GetCampaignByIdQuery { CampaignId = id });
|
||||
|
||||
if (campaign == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });
|
||||
|
||||
return Ok(campaign);
|
||||
return Ok(new { success = true, data = campaign });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +105,7 @@ public class CampaignsController : ControllerBase
|
||||
var result = await _mediator.Send(command);
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class CampaignsController : ControllerBase
|
||||
var result = await _mediator.Send(new ActivateCampaignCommand { CampaignId = id });
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public class CampaignsController : ControllerBase
|
||||
var result = await _mediator.Send(new PauseCampaignCommand { CampaignId = id });
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public class CampaignsController : ControllerBase
|
||||
var result = await _mediator.Send(new DeleteCampaignCommand { CampaignId = id });
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class AdminAuctionsController : ControllerBase
|
||||
};
|
||||
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,6 +62,6 @@ public class AdminAuctionsController : ControllerBase
|
||||
{
|
||||
_logger.LogInformation("Auction statistics requested");
|
||||
var statistics = await _mediator.Send(new GetAuctionStatisticsQuery());
|
||||
return Ok(statistics);
|
||||
return Ok(new { success = true, data = statistics });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class AdminBudgetController : ControllerBase
|
||||
};
|
||||
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,9 +78,9 @@ public class AdminBudgetController : ControllerBase
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (pacer == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Budget pacer not found for this campaign" } });
|
||||
|
||||
return Ok(pacer);
|
||||
return Ok(new { success = true, data = pacer });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,13 +97,13 @@ public class AdminBudgetController : ControllerBase
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (pacer == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Budget pacer not found for this campaign" } });
|
||||
|
||||
pacer.ResetDailySpend();
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("Manual budget reset for Campaign {CampaignId}", campaignId);
|
||||
return Ok();
|
||||
return Ok(new { success = true, data = new { message = "Budget reset successfully" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,6 +132,6 @@ public class AdminBudgetController : ControllerBase
|
||||
CampaignsExceeded = stats.Count(s => s.Utilization >= 100)
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AdminFrequencyController : ControllerBase
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(caps);
|
||||
return Ok(new { success = true, data = caps });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,9 +72,9 @@ public class AdminFrequencyController : ControllerBase
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (cap == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Frequency cap not found" } });
|
||||
|
||||
return Ok(cap);
|
||||
return Ok(new { success = true, data = cap });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,7 +87,7 @@ public class AdminFrequencyController : ControllerBase
|
||||
public async Task<ActionResult<FrequencyCapDto>> CreateFrequencyCap([FromBody] CreateFrequencyCapRequest request)
|
||||
{
|
||||
if (!Enum.TryParse<FrequencyWindow>(request.Window, out var window))
|
||||
return BadRequest("Invalid frequency window");
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Invalid frequency window" } });
|
||||
|
||||
var cap = new FrequencyCap(request.AdId, request.MaxImpressionsPerUser, window);
|
||||
|
||||
@@ -104,7 +104,7 @@ public class AdminFrequencyController : ControllerBase
|
||||
|
||||
_logger.LogInformation("Created frequency cap {Id} for Ad {AdId}", cap.Id, request.AdId);
|
||||
|
||||
return CreatedAtAction(nameof(GetFrequencyCap), new { id = cap.Id }, dto);
|
||||
return CreatedAtAction(nameof(GetFrequencyCap), new { id = cap.Id }, new { success = true, data = dto });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +119,7 @@ public class AdminFrequencyController : ControllerBase
|
||||
var cap = await _context.FrequencyCaps.FindAsync(id);
|
||||
|
||||
if (cap == null)
|
||||
return NotFound();
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Frequency cap not found" } });
|
||||
|
||||
_context.FrequencyCaps.Remove(cap);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@@ -51,7 +51,7 @@ public class AdsController : ControllerBase
|
||||
if (result == null)
|
||||
return NoContent();
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,7 +73,7 @@ public class AdsController : ControllerBase
|
||||
},
|
||||
HttpContext.RequestAborted);
|
||||
|
||||
return Accepted();
|
||||
return Accepted(new { success = true, data = new { message = "Impression tracked" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -95,7 +95,7 @@ public class AdsController : ControllerBase
|
||||
},
|
||||
HttpContext.RequestAborted);
|
||||
|
||||
return Accepted();
|
||||
return Accepted(new { success = true, data = new { message = "Click tracked" } });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using AdsServingService.Infrastructure.Idempotency;
|
||||
|
||||
namespace AdsServingService.Infrastructure;
|
||||
|
||||
@@ -41,8 +40,8 @@ public static class DependencyInjection
|
||||
// Register repositories (when needed)
|
||||
// services.AddScoped<IAuctionRepository, AuctionRepository>();
|
||||
|
||||
// Register idempotency services
|
||||
services.AddScoped<IRequestManager, RequestManager>();
|
||||
// EN: Idempotency services not registered — no handler uses IRequestManager
|
||||
// VI: Idempotency services không được đăng ký — không có handler nào dùng IRequestManager
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class AdminAttributionController : ControllerBase
|
||||
);
|
||||
|
||||
_logger.LogInformation("Admin: Retrieved attribution stats");
|
||||
return Ok(stats);
|
||||
return Ok(new { success = true, data = stats });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ public class AdminAttributionController : ControllerBase
|
||||
);
|
||||
|
||||
_logger.LogInformation("Admin: Retrieved attribution report for campaign {CampaignId}", campaignId);
|
||||
return Ok(report);
|
||||
return Ok(new { success = true, data = report });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class AdminConversionsController : ControllerBase
|
||||
var result = await _mediator.Send(query, ct);
|
||||
|
||||
_logger.LogInformation("Admin: Listed {Count} conversions", result.Count());
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ public class AdminConversionsController : ControllerBase
|
||||
);
|
||||
|
||||
_logger.LogInformation("Admin: Retrieved conversion stats");
|
||||
return Ok(stats);
|
||||
return Ok(new { success = true, data = stats });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,7 +107,7 @@ public class AdminConversionsController : ControllerBase
|
||||
);
|
||||
|
||||
_logger.LogInformation("Admin: Retrieved conversion details for {ConversionId}", id);
|
||||
return Ok(detail);
|
||||
return Ok(new { success = true, data = detail });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ public class AdminPixelsController : ControllerBase
|
||||
};
|
||||
|
||||
_logger.LogInformation("Admin: Listed {Count} pixels", pixels.Count);
|
||||
return Ok(pixels);
|
||||
return Ok(new { success = true, data = pixels });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -63,7 +63,7 @@ public class AdminPixelsController : ControllerBase
|
||||
{
|
||||
var events = new List<PixelEventDto>();
|
||||
_logger.LogInformation("Admin: Listed events for pixel {PixelId}", pixelId);
|
||||
return Ok(events);
|
||||
return Ok(new { success = true, data = events });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,7 +90,7 @@ public class AdminPixelsController : ControllerBase
|
||||
);
|
||||
|
||||
_logger.LogInformation("Admin: Retrieved stats for pixel {PixelId}", pixelId);
|
||||
return Ok(stats);
|
||||
return Ok(new { success = true, data = stats });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +105,7 @@ public class AdminPixelsController : ControllerBase
|
||||
// EN: Would implement activation logic via Command
|
||||
// VI: Sẽ implement logic kích hoạt qua Command
|
||||
_logger.LogInformation("Admin: Activated pixel {PixelId}", pixelId);
|
||||
return Ok(new { Message = "Pixel activated successfully" });
|
||||
return Ok(new { success = true, data = new { message = "Pixel activated successfully" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,7 +120,7 @@ public class AdminPixelsController : ControllerBase
|
||||
// EN: Would implement deactivation logic via Command
|
||||
// VI: Sẽ implement logic vô hiệu hóa qua Command
|
||||
_logger.LogInformation("Admin: Deactivated pixel {PixelId}", pixelId);
|
||||
return Ok(new { Message = "Pixel deactivated successfully" });
|
||||
return Ok(new { success = true, data = new { message = "Pixel deactivated successfully" } });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public class ConversionsController : ControllerBase
|
||||
var query = new GetConversionsQuery(campaignId, userId, from, to, skip, take);
|
||||
var result = await _mediator.Send(query, ct);
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -92,10 +92,10 @@ public class ConversionsController : ControllerBase
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound(new { Message = "Attribution not found for this conversion" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Attribution not found for this conversion" } });
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@ public class EventsController : ControllerBase
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return BadRequest(new { Message = "Invalid pixel code or pixel is not active" });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = "Invalid pixel code or pixel is not active" } });
|
||||
}
|
||||
|
||||
return Accepted(new { Message = "Event tracked successfully" });
|
||||
return Accepted(new { success = true, data = new { message = "Event tracked successfully" } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -84,7 +84,7 @@ public class EventsController : ControllerBase
|
||||
"Server-side event tracked: AdId={AdId}, UserId={UserId}, EventType={EventType}",
|
||||
request.AdId, request.UserId, request.EventType);
|
||||
|
||||
return Accepted(new { Message = "Server-side event tracked successfully" });
|
||||
return Accepted(new { success = true, data = new { message = "Server-side event tracked successfully" } });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,10 +41,10 @@ public class PixelsController : ControllerBase
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound(new { Message = "Pixel not found for this advertiser" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Pixel not found for this advertiser" } });
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +68,7 @@ public class PixelsController : ControllerBase
|
||||
return CreatedAtAction(
|
||||
nameof(GetPixelCode),
|
||||
new { advertiserId = request.AdvertiserId },
|
||||
result);
|
||||
new { success = true, data = result });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using BookingService.Domain.AggregatesModel.AppointmentAggregate;
|
||||
using BookingService.Domain.AggregatesModel.TherapistAggregate;
|
||||
using BookingService.Infrastructure.Idempotency;
|
||||
using BookingService.Infrastructure.Repositories;
|
||||
|
||||
namespace BookingService.Infrastructure;
|
||||
@@ -53,8 +52,8 @@ public static class DependencyInjection
|
||||
services.AddScoped<IStaffScheduleRepository, StaffScheduleRepository>();
|
||||
services.AddScoped<ITherapistRepository, TherapistRepository>();
|
||||
|
||||
// EN: Register idempotency services / VI: Đăng ký idempotency services
|
||||
services.AddScoped<IRequestManager, RequestManager>();
|
||||
// EN: Idempotency services not registered — no handler uses IRequestManager
|
||||
// VI: Idempotency services không được đăng ký — không có handler nào dùng IRequestManager
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@ public class ConversationsController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(ex.Message);
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class ConversationsController : ControllerBase
|
||||
{
|
||||
var query = new GetConversationsQuery(userId, page, pageSize);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -82,10 +82,10 @@ public class ConversationsController : ControllerBase
|
||||
var conversation = result.Conversations.FirstOrDefault(c => c.Id == conversationId);
|
||||
if (conversation == null)
|
||||
{
|
||||
return NotFound($"Conversation {conversationId} not found");
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Conversation {conversationId} not found" } });
|
||||
}
|
||||
|
||||
return Ok(conversation);
|
||||
return Ok(new { success = true, data = conversation });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class KeysController : ControllerBase
|
||||
|
||||
if (string.IsNullOrEmpty(identityUserId))
|
||||
{
|
||||
return Unauthorized("User ID not found in token");
|
||||
return Unauthorized(new { success = false, error = new { code = "UNAUTHORIZED", message = "User ID not found in token" } });
|
||||
}
|
||||
|
||||
var command = new RegisterUserKeysCommand(
|
||||
@@ -52,7 +52,7 @@ public class KeysController : ControllerBase
|
||||
);
|
||||
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,11 +74,11 @@ public class KeysController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return NotFound(ex.Message);
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,11 +100,11 @@ public class KeysController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return NotFound(ex.Message);
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +122,10 @@ public class KeysController : ControllerBase
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound($"Key bundle not found for user {userId}");
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Key bundle not found for user {userId}" } });
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -142,7 +142,7 @@ public class KeysController : ControllerBase
|
||||
|
||||
if (string.IsNullOrEmpty(identityUserId))
|
||||
{
|
||||
return Unauthorized("User ID not found in token");
|
||||
return Unauthorized(new { success = false, error = new { code = "UNAUTHORIZED", message = "User ID not found in token" } });
|
||||
}
|
||||
|
||||
var query = new GetMyKeyBundleQuery(identityUserId);
|
||||
@@ -150,10 +150,10 @@ public class KeysController : ControllerBase
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound("Key bundle not registered. Please register your keys first.");
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Key bundle not registered. Please register your keys first." } });
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,11 +47,11 @@ public class MessagesController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return NotFound(ex.Message);
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class MessagesController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
@@ -100,11 +100,11 @@ public class MessagesController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return NotFound(ex.Message);
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class LevelsController : ControllerBase
|
||||
{
|
||||
var query = new GetLevelDefinitionsQuery { IncludeInactive = includeInactive };
|
||||
var levels = await _mediator.Send(query);
|
||||
return Ok(levels);
|
||||
return Ok(new { success = true, data = levels });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,20 +62,20 @@ public class LevelsController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return CreatedAtAction(nameof(GetAll), new { }, result);
|
||||
return CreatedAtAction(nameof(GetAll), new { }, new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex) when (ex.Message.Contains("already exists"))
|
||||
{
|
||||
return Conflict(new { message = ex.Message });
|
||||
return Conflict(new { success = false, error = new { code = "CONFLICT", message = ex.Message } });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = ex.Message } });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error creating level definition");
|
||||
return StatusCode(500, new { message = "An error occurred while creating level definition" });
|
||||
return StatusCode(500, new { success = false, error = new { code = "INTERNAL_ERROR", message = "An error occurred while creating level definition" } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,20 +100,20 @@ public class LevelsController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = ex.Message } });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error updating level definition {LevelId}", id);
|
||||
return StatusCode(500, new { message = "An error occurred while updating level definition" });
|
||||
return StatusCode(500, new { success = false, error = new { code = "INTERNAL_ERROR", message = "An error occurred while updating level definition" } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,16 +137,16 @@ public class LevelsController : ControllerBase
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = ex.Message } });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error deactivating level definition {LevelId}", id);
|
||||
return StatusCode(500, new { message = "An error occurred while deactivating level definition" });
|
||||
return StatusCode(500, new { success = false, error = new { code = "INTERNAL_ERROR", message = "An error occurred while deactivating level definition" } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,9 @@ public class MembersController : ControllerBase
|
||||
var member = await _mediator.Send(new GetMemberByIdQuery(id));
|
||||
if (member == null)
|
||||
{
|
||||
return NotFound(new { message = $"Member {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Member {id} not found" } });
|
||||
}
|
||||
return Ok(member);
|
||||
return Ok(new { success = true, data = member });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,9 +67,9 @@ public class MembersController : ControllerBase
|
||||
var member = await _mediator.Send(new GetMemberByIdQuery(userId.Value));
|
||||
if (member == null)
|
||||
{
|
||||
return NotFound(new { message = "Member profile not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Member profile not found" } });
|
||||
}
|
||||
return Ok(member);
|
||||
return Ok(new { success = true, data = member });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,7 +91,7 @@ public class MembersController : ControllerBase
|
||||
PageSize = pageSize,
|
||||
SearchTerm = search
|
||||
});
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -109,11 +109,11 @@ public class MembersController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.MemberId }, result);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.MemberId }, new { success = true, data = result });
|
||||
}
|
||||
catch (InvalidOperationException ex) when (ex.Message.Contains("already exists"))
|
||||
{
|
||||
return Conflict(new { message = ex.Message });
|
||||
return Conflict(new { success = false, error = new { code = "CONFLICT", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,11 +136,11 @@ public class MembersController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,15 +163,15 @@ public class MembersController : ControllerBase
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +189,9 @@ public class MembersController : ControllerBase
|
||||
var progress = await _mediator.Send(new GetMemberProgressQuery(id));
|
||||
if (progress == null)
|
||||
{
|
||||
return NotFound(new { message = $"Member {id} not found" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Member {id} not found" } });
|
||||
}
|
||||
return Ok(progress);
|
||||
return Ok(new { success = true, data = progress });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -208,7 +208,7 @@ public class MembersController : ControllerBase
|
||||
[FromQuery] int pageSize = 20)
|
||||
{
|
||||
var result = await _mediator.Send(new GetExperienceHistoryQuery(id, pageIndex, pageSize));
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
private Guid? GetCurrentUserId()
|
||||
|
||||
@@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using FacebookService.Domain.AggregatesModel.CustomerAggregate;
|
||||
using FacebookService.Domain.AggregatesModel.ConversationAggregate;
|
||||
using FacebookService.Domain.AggregatesModel.ChatbotAggregate;
|
||||
using FacebookService.Infrastructure.Idempotency;
|
||||
using FacebookService.Infrastructure.Repositories;
|
||||
using FacebookService.Infrastructure.ExternalServices;
|
||||
using Polly;
|
||||
@@ -57,8 +56,8 @@ public static class DependencyInjection
|
||||
services.AddScoped<IChatbotFlowRepository, ChatbotFlowRepository>();
|
||||
services.AddScoped<IAIChatbotConfigRepository, AIChatbotConfigRepository>();
|
||||
|
||||
// EN: Register idempotency services / VI: Đăng ký idempotency services
|
||||
services.AddScoped<IRequestManager, RequestManager>();
|
||||
// EN: Idempotency services not registered — no handler uses IRequestManager
|
||||
// VI: Idempotency services không được đăng ký — không có handler nào dùng IRequestManager
|
||||
|
||||
// EN: Register Facebook Messenger client / VI: Đăng ký Facebook Messenger client
|
||||
services.AddHttpClient<IFacebookMessengerClient, FacebookMessengerClient>()
|
||||
|
||||
@@ -40,7 +40,7 @@ public class AdminController : ControllerBase
|
||||
{
|
||||
var query = new GetAllRelationshipsQuery(skip, take, status, type);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,9 +56,9 @@ public class AdminController : ControllerBase
|
||||
var result = await _mediator.Send(query);
|
||||
|
||||
if (result == null)
|
||||
return NotFound(new { error = "Relationship not found" });
|
||||
|
||||
return Ok(result);
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Relationship not found" } });
|
||||
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,9 +74,9 @@ public class AdminController : ControllerBase
|
||||
var result = await _mediator.Send(command);
|
||||
|
||||
if (!result)
|
||||
return NotFound(new { error = "Relationship not found" });
|
||||
|
||||
return Ok(new { success = true, message = "Relationship deleted successfully" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Relationship not found" } });
|
||||
|
||||
return Ok(new { success = true, data = new { message = "Relationship deleted successfully" } });
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -95,7 +95,7 @@ public class AdminController : ControllerBase
|
||||
{
|
||||
var query = new GetAllBlocksQuery(skip, take);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,9 +111,9 @@ public class AdminController : ControllerBase
|
||||
var result = await _mediator.Send(command);
|
||||
|
||||
if (!result)
|
||||
return NotFound(new { error = "Block not found" });
|
||||
|
||||
return Ok(new { success = true, message = "Block deleted successfully" });
|
||||
return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Block not found" } });
|
||||
|
||||
return Ok(new { success = true, data = new { message = "Block deleted successfully" } });
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -130,7 +130,7 @@ public class AdminController : ControllerBase
|
||||
{
|
||||
var query = new GetSocialStatisticsQuery();
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -34,7 +34,7 @@ public class BlocksController : ControllerBase
|
||||
{
|
||||
var command = new BlockUserCommand(request.BlockerId, request.BlockedId, request.Reason);
|
||||
var result = await _mediator.Send(command);
|
||||
return CreatedAtAction(nameof(GetBlockedUsers), new { userId = request.BlockerId }, result);
|
||||
return CreatedAtAction(nameof(GetBlockedUsers), new { userId = request.BlockerId }, new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -48,7 +48,7 @@ public class BlocksController : ControllerBase
|
||||
{
|
||||
var command = new UnblockUserCommand(request.BlockerId, request.BlockedId);
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(new { success = result });
|
||||
return Ok(new { success = true, data = new { unblocked = result } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -61,7 +61,7 @@ public class BlocksController : ControllerBase
|
||||
{
|
||||
var query = new GetBlockedUsersQuery(userId, skip, take);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var query = new GetFriendsQuery(userId, skip, take);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,7 +50,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var command = new SendFriendRequestCommand(request.RequesterId, request.AddresseeId);
|
||||
var result = await _mediator.Send(command);
|
||||
return CreatedAtAction(nameof(GetFriends), new { userId = request.RequesterId }, result);
|
||||
return CreatedAtAction(nameof(GetFriends), new { userId = request.RequesterId }, new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,7 +65,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var command = new RespondToFriendRequestCommand(relationshipId, request.UserId, request.Accept);
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(new { success = result });
|
||||
return Ok(new { success = true, data = new { accepted = result } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var query = new GetMutualFriendsQuery(userId1, userId2);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,7 +91,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var query = new GetFriendSuggestionsQuery(userId, limit);
|
||||
var result = await _mediator.Send(query);
|
||||
return Ok(result);
|
||||
return Ok(new { success = true, data = result });
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -109,7 +109,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var command = new FollowUserCommand(request.FollowerId, request.FolloweeId);
|
||||
var result = await _mediator.Send(command);
|
||||
return CreatedAtAction(nameof(GetFriends), new { userId = request.FollowerId }, result);
|
||||
return CreatedAtAction(nameof(GetFriends), new { userId = request.FollowerId }, new { success = true, data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,7 +123,7 @@ public class RelationshipsController : ControllerBase
|
||||
{
|
||||
var command = new UnfollowUserCommand(request.FollowerId, request.FolloweeId);
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(new { success = result });
|
||||
return Ok(new { success = true, data = new { unfollowed = result } });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user