This commit is contained in:
Chris Chen
2026-06-24 18:45:22 -07:00
parent e908e35530
commit 9dbb1d38d8
14 changed files with 312 additions and 0 deletions
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ROLAC.API.Authorization;
using ROLAC.API.DTOs.Ministry;
using ROLAC.API.Services;
namespace ROLAC.API.Controllers;
@@ -13,6 +15,31 @@ public class MinistriesController : ControllerBase
public MinistriesController(IMinistryService svc) => _svc = svc;
[HttpGet]
[HasPermission(Modules.Ministries, PermissionActions.Read)]
public async Task<IActionResult> GetAll([FromQuery] bool includeInactive = false)
=> Ok(await _svc.GetAllAsync(includeInactive));
[HttpPost]
[HasPermission(Modules.Ministries, PermissionActions.Write)]
public async Task<IActionResult> Create([FromBody] CreateMinistryRequest request)
{
var id = await _svc.CreateAsync(request);
return CreatedAtAction(nameof(GetAll), new { id }, new { id });
}
[HttpPut("{id:int}")]
[HasPermission(Modules.Ministries, PermissionActions.Write)]
public async Task<IActionResult> Update(int id, [FromBody] UpdateMinistryRequest request)
{
try { await _svc.UpdateAsync(id, request); return NoContent(); }
catch (KeyNotFoundException) { return NotFound(); }
}
[HttpDelete("{id:int}")]
[HasPermission(Modules.Ministries, PermissionActions.Delete)]
public async Task<IActionResult> Deactivate(int id)
{
try { await _svc.DeactivateAsync(id); return NoContent(); }
catch (KeyNotFoundException) { return NotFound(); }
}
}
@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace ROLAC.API.DTOs.Ministry;
public class CreateMinistryRequest
{
[Required, MaxLength(200)] public string Name_en { get; set; } = "";
[MaxLength(200)] public string? Name_zh { get; set; }
[MaxLength(500)] public string? Description_en { get; set; }
[MaxLength(500)] public string? Description_zh { get; set; }
public int SortOrder { get; set; }
}
@@ -5,6 +5,8 @@ public class MinistryDto
public int Id { get; set; }
public string Name_en { get; set; } = "";
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; }
}
@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace ROLAC.API.DTOs.Ministry;
public class UpdateMinistryRequest
{
[Required, MaxLength(200)] public string Name_en { get; set; } = "";
[MaxLength(200)] public string? Name_zh { get; set; }
[MaxLength(500)] public string? Description_en { get; set; }
[MaxLength(500)] public string? Description_zh { get; set; }
public bool IsActive { get; set; } = true;
public int SortOrder { get; set; }
}
+16
View File
@@ -94,6 +94,22 @@ public static class DbSeeder
("pastor", Modules.AuditLogs, true, false, false, false),
("finance", Modules.AuditLogs, true, false, false, false),
("board_member", Modules.AuditLogs, true, false, false, false),
// Ministries — secretary maintains the list; coworker_chair edits; ministry
// leaders and pastor read.
("secretary", Modules.Ministries, true, true, true, false),
("coworker_chair", Modules.Ministries, true, true, false, false),
("ministry_leader", Modules.Ministries, true, false, false, false),
("pastor", Modules.Ministries, true, false, false, false),
// Meal attendance — secretary and coworkers record; finance and pastor read.
("secretary", Modules.MealAttendance, true, true, false, false),
("coworker", Modules.MealAttendance, true, true, false, false),
("finance", Modules.MealAttendance, true, false, false, false),
("pastor", Modules.MealAttendance, true, false, false, false),
// Users, Permissions, and Settings are intentionally super_admin-only:
// super_admin bypasses all checks, so no seed rows are needed here.
];
public static async Task SeedRolePermissionsAsync(AppDbContext db)
@@ -4,4 +4,7 @@ namespace ROLAC.API.Services;
public interface IMinistryService
{
Task<List<MinistryDto>> GetAllAsync(bool includeInactive);
Task<int> CreateAsync(CreateMinistryRequest request);
Task UpdateAsync(int id, UpdateMinistryRequest request);
Task DeactivateAsync(int id); // soft-disable: IsActive = false
}
+33
View File
@@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using ROLAC.API.Data;
using ROLAC.API.DTOs.Ministry;
using ROLAC.API.Entities;
namespace ROLAC.API.Services;
@@ -18,8 +19,40 @@ public class MinistryService : IMinistryService
.Select(m => new MinistryDto
{
Id = m.Id, Name_en = m.Name_en, Name_zh = m.Name_zh,
Description_en = m.Description_en, Description_zh = m.Description_zh,
SortOrder = m.SortOrder, IsActive = m.IsActive,
})
.ToListAsync();
}
public async Task<int> CreateAsync(CreateMinistryRequest r)
{
var entity = new Ministry
{
Name_en = r.Name_en, Name_zh = r.Name_zh,
Description_en = r.Description_en, Description_zh = r.Description_zh,
SortOrder = r.SortOrder, IsActive = true,
};
_db.Ministries.Add(entity);
await _db.SaveChangesAsync();
return entity.Id;
}
public async Task UpdateAsync(int id, UpdateMinistryRequest r)
{
var m = await _db.Ministries.FindAsync(id)
?? throw new KeyNotFoundException($"Ministry {id} not found.");
m.Name_en = r.Name_en; m.Name_zh = r.Name_zh;
m.Description_en = r.Description_en; m.Description_zh = r.Description_zh;
m.IsActive = r.IsActive; m.SortOrder = r.SortOrder;
await _db.SaveChangesAsync();
}
public async Task DeactivateAsync(int id)
{
var m = await _db.Ministries.FindAsync(id)
?? throw new KeyNotFoundException($"Ministry {id} not found.");
m.IsActive = false;
await _db.SaveChangesAsync();
}
}