feat(ministry): add Ministry entity, seed (10), and read endpoint

This commit is contained in:
Chris Chen
2026-05-29 18:03:28 -07:00
parent 50e518095e
commit f6f06d841c
9 changed files with 150 additions and 0 deletions
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ROLAC.API.Services;
namespace ROLAC.API.Controllers;
[ApiController]
[Route("api/ministries")]
[Authorize]
public class MinistriesController : ControllerBase
{
private readonly IMinistryService _svc;
public MinistriesController(IMinistryService svc) => _svc = svc;
[HttpGet]
public async Task<IActionResult> GetAll([FromQuery] bool includeInactive = false)
=> Ok(await _svc.GetAllAsync(includeInactive));
}
@@ -0,0 +1,10 @@
namespace ROLAC.API.DTOs.Ministry;
public class MinistryDto
{
public int Id { get; set; }
public string Name_en { get; set; } = "";
public string? Name_zh { get; set; }
public int SortOrder { get; set; }
public bool IsActive { get; set; }
}
+8
View File
@@ -14,6 +14,7 @@ public class AppDbContext : IdentityDbContext<AppUser, AppRole, string>
public DbSet<GivingCategory> GivingCategories => Set<GivingCategory>();
public DbSet<OfferingSession> OfferingSessions => Set<OfferingSession>();
public DbSet<Giving> Givings => Set<Giving>();
public DbSet<Ministry> Ministries => Set<Ministry>();
protected override void OnModelCreating(ModelBuilder builder)
{
@@ -142,5 +143,12 @@ public class AppDbContext : IdentityDbContext<AppUser, AppRole, string>
entity.HasOne(e => e.OfferingSession).WithMany(s => s.Givings)
.HasForeignKey(e => e.OfferingSessionId).OnDelete(DeleteBehavior.Cascade);
});
// ── Ministry ─────────────────────────────────────────────────────────
builder.Entity<Ministry>(entity =>
{
entity.Property(e => e.Name_en).HasMaxLength(200).IsRequired();
entity.Property(e => e.Name_zh).HasMaxLength(200);
});
}
}
+25
View File
@@ -15,6 +15,20 @@ public static class DbSeeder
("Mission", "宣教奉獻", 5),
];
private static readonly (string En, string Zh, int Sort)[] MinistrySeed =
[
("Administration", "行政", 1),
("Preaching", "講道", 2),
("Emcee", "司會", 3),
("Worship", "敬拜", 4),
("PPT/Media", "PPT/影音", 5),
("Sound", "音控", 6),
("Facility", "場地組", 7),
("Hospitality", "招待", 8),
("Children", "兒牧", 9),
("Catering", "餐飲", 10),
];
private static readonly (string Name, string Description)[] Roles =
[
("super_admin", "System administrator — full access"),
@@ -66,6 +80,16 @@ public static class DbSeeder
await db.SaveChangesAsync();
}
public static async Task SeedMinistriesAsync(AppDbContext db)
{
foreach (var (en, zh, sort) in MinistrySeed)
{
if (!await db.Ministries.AnyAsync(m => m.Name_en == en))
db.Ministries.Add(new Ministry { Name_en = en, Name_zh = zh, SortOrder = sort, IsActive = true });
}
await db.SaveChangesAsync();
}
/// <summary>
/// Seeds roles and (in Development) the default admin account.
/// Called once on application startup after migrations have been applied.
@@ -80,6 +104,7 @@ public static class DbSeeder
var db = services.GetRequiredService<AppDbContext>();
await SeedGivingCategoriesAsync(db);
await SeedMinistriesAsync(db);
if (env.IsDevelopment())
await SeedAdminUserAsync(userManager);
+12
View File
@@ -0,0 +1,12 @@
namespace ROLAC.API.Entities;
public class Ministry
{
public int Id { get; set; }
public string Name_en { get; set; } = null!;
public string? Name_zh { get; set; }
public string? Description_en { get; set; }
public string? Description_zh { get; set; }
public int SortOrder { get; set; }
public bool IsActive { get; set; } = true;
}
+1
View File
@@ -121,6 +121,7 @@ builder.Services.AddScoped<IUserManagementService, UserManagementService>();
builder.Services.AddScoped<IGivingCategoryService, GivingCategoryService>();
builder.Services.AddScoped<IGivingService, GivingService>();
builder.Services.AddScoped<IOfferingSessionService, OfferingSessionService>();
builder.Services.AddScoped<IMinistryService, MinistryService>();
// ---------------------------------------------------------------------------
// Swagger / MVC
@@ -0,0 +1,7 @@
using ROLAC.API.DTOs.Ministry;
namespace ROLAC.API.Services;
public interface IMinistryService
{
Task<List<MinistryDto>> GetAllAsync(bool includeInactive);
}
+25
View File
@@ -0,0 +1,25 @@
using Microsoft.EntityFrameworkCore;
using ROLAC.API.Data;
using ROLAC.API.DTOs.Ministry;
namespace ROLAC.API.Services;
public class MinistryService : IMinistryService
{
private readonly AppDbContext _db;
public MinistryService(AppDbContext db) => _db = db;
public async Task<List<MinistryDto>> GetAllAsync(bool includeInactive)
{
var query = _db.Ministries.AsNoTracking().AsQueryable();
if (!includeInactive) query = query.Where(m => m.IsActive);
return await query
.OrderBy(m => m.SortOrder).ThenBy(m => m.Name_en)
.Select(m => new MinistryDto
{
Id = m.Id, Name_en = m.Name_en, Name_zh = m.Name_zh,
SortOrder = m.SortOrder, IsActive = m.IsActive,
})
.ToListAsync();
}
}