feat(content+admin): home-events CRUD + comments moderation
Build backend images / build content-svc (push) Failing after 45s
Build backend images / build file-svc (push) Failing after 1m3s
Build backend images / build gateway (push) Failing after 0s
Build backend images / build identity-svc (push) Failing after 0s
Build backend images / build notification-svc (push) Failing after 1s
Build backend images / build render-svc (push) Failing after 1s
Build backend images / build studio-svc (push) Failing after 0s

- content-svc: home-events gains Create/Update/Delete + includeInactive list
  (POST/PUT/DELETE /v1/home-events, admin-gated; dates coerced to UTC)
- admin /admin/home-events: full CRUD for homepage hero event banners
- admin /admin/comments: list + approve/unapprove + delete (moderation)
- AdminResource: optional listQuery to fetch inactive rows for admin views

Fills the remaining legacy-admin gaps (home events, comments).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-02 22:24:56 +03:30
parent 3acd366fda
commit 0b538e1b1e
10 changed files with 173 additions and 15 deletions
@@ -172,16 +172,55 @@ public class CmsService(ContentDbContext db)
// ── Home Page Events ──────────────────────────────────────────────────────
public async Task<List<HomePageEventResponse>> GetHomePageEventsAsync(Guid? tenantId)
public async Task<List<HomePageEventResponse>> GetHomePageEventsAsync(Guid? tenantId, bool includeInactive = false)
{
return await db.HomePageEvents
.Where(x => x.IsActive && (x.TenantId == null || x.TenantId == tenantId))
.OrderBy(x => x.Sort)
.Select(e => new HomePageEventResponse(
e.Id, e.Title, e.Subtitle, e.Description, e.Badge, e.BadgeClass,
e.ButtonText, e.ButtonUrl, e.ButtonClass, e.Color, e.BackgroundColor,
e.TextColor, e.Image, e.IsActive, e.Sort, e.StartsAt, e.EndsAt
)).ToListAsync();
var q = db.HomePageEvents.Where(x => x.TenantId == null || x.TenantId == tenantId);
if (!includeInactive) q = q.Where(x => x.IsActive);
return await q.OrderBy(x => x.Sort).Select(e => MapHomeEvent(e)).ToListAsync();
}
private static HomePageEventResponse MapHomeEvent(HomePageEvent e) => new(
e.Id, e.Title, e.Subtitle, e.Description, e.Badge, e.BadgeClass,
e.ButtonText, e.ButtonUrl, e.ButtonClass, e.Color, e.BackgroundColor,
e.TextColor, e.Image, e.IsActive, e.Sort, e.StartsAt, e.EndsAt);
private static DateTime? Utc(DateTime? d) => d.HasValue ? DateTime.SpecifyKind(d.Value, DateTimeKind.Utc) : null;
public async Task<HomePageEventResponse> CreateHomeEventAsync(UpsertHomeEventRequest req)
{
var e = new HomePageEvent();
ApplyHomeEvent(e, req);
db.HomePageEvents.Add(e);
await db.SaveChangesAsync();
return MapHomeEvent(e);
}
public async Task<HomePageEventResponse> UpdateHomeEventAsync(Guid id, UpsertHomeEventRequest req)
{
var e = await db.HomePageEvents.FindAsync(id)
?? throw new KeyNotFoundException($"Home event {id} not found");
ApplyHomeEvent(e, req);
e.UpdatedAt = DateTime.UtcNow;
await db.SaveChangesAsync();
return MapHomeEvent(e);
}
public async Task DeleteHomeEventAsync(Guid id)
{
var e = await db.HomePageEvents.FindAsync(id)
?? throw new KeyNotFoundException($"Home event {id} not found");
db.HomePageEvents.Remove(e);
await db.SaveChangesAsync();
}
private static void ApplyHomeEvent(HomePageEvent e, UpsertHomeEventRequest r)
{
e.Title = r.Title; e.Subtitle = r.Subtitle; e.Description = r.Description;
e.Badge = r.Badge; e.BadgeClass = r.BadgeClass;
e.ButtonText = r.ButtonText; e.ButtonUrl = r.ButtonUrl; e.ButtonClass = r.ButtonClass;
e.Color = r.Color; e.BackgroundColor = r.BackgroundColor; e.TextColor = r.TextColor;
e.Image = r.Image; e.IsActive = r.IsActive; e.Sort = r.Sort;
e.StartsAt = Utc(r.StartsAt); e.EndsAt = Utc(r.EndsAt);
}
// ── Website Settings ──────────────────────────────────────────────────────
@@ -103,8 +103,26 @@ public class SlidesController(CmsService svc) : ControllerBase
public class HomePageEventsController(CmsService svc) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> Get([FromQuery] Guid? tenantId = null) =>
Ok(await svc.GetHomePageEventsAsync(tenantId));
public async Task<IActionResult> Get([FromQuery] Guid? tenantId = null, [FromQuery] bool includeInactive = false) =>
Ok(await svc.GetHomePageEventsAsync(tenantId, includeInactive));
[Authorize(Roles = "Admin")]
[HttpPost]
public async Task<IActionResult> Create([FromBody] UpsertHomeEventRequest req) =>
Ok(await svc.CreateHomeEventAsync(req));
[Authorize(Roles = "Admin")]
[HttpPut("{id:guid}")]
public async Task<IActionResult> Update(Guid id, [FromBody] UpsertHomeEventRequest req) =>
Ok(await svc.UpdateHomeEventAsync(id, req));
[Authorize(Roles = "Admin")]
[HttpDelete("{id:guid}")]
public async Task<IActionResult> Delete(Guid id)
{
await svc.DeleteHomeEventAsync(id);
return NoContent();
}
}
[ApiController]
@@ -95,6 +95,25 @@ public record CreateMusicTrackRequest(
int Sort
);
public record UpsertHomeEventRequest(
string? Title,
string? Subtitle,
string? Description,
string? Badge,
string? BadgeClass,
string? ButtonText,
string? ButtonUrl,
string? ButtonClass,
string? Color,
string? BackgroundColor,
string? TextColor,
string? Image,
bool IsActive = true,
int Sort = 0,
DateTime? StartsAt = null,
DateTime? EndsAt = null
);
public record UpdateMusicTrackRequest(
string Name,
string? Caption,