Commit 23569331 authored by Eric Dieckman's avatar Eric Dieckman
Browse files

feat: enforce unique person+contact-type per WiscNic group member

A person may hold multiple contact-type roles (e.g., Admin and Tech) in
the same group, but the same (person, group, contact type) triple should
not repeat. AddMemberAsync now returns 409 on duplicates, and a unique
composite index on wn_group_members enforces it at the DB level.
parent dfcc1201
Loading
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ public class WiscNicGroupsController : ControllerBase
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<WiscNicGroupMember>(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [HttpPost("{groupId:long}/members", Name = "AddWiscNicGroupMember")]
    public async Task<IActionResult> AddMemberAsync(long groupId, [FromBody] WiscNicGroupMember data)
    {
@@ -111,6 +112,15 @@ public class WiscNicGroupsController : ControllerBase
            return NotFound();

        data.GroupId = groupId;

        bool exists = await _context.WiscNicGroupMembers.AnyAsync(m =>
            m.GroupId == groupId
            && m.PersonId == data.PersonId
            && m.ContactTypeId == data.ContactTypeId);

        if (exists)
            return Conflict("Person is already assigned to this group with that contact type.");

        _context.WiscNicGroupMembers.Add(data);
        await _context.SaveChangesAsync();

+4 −0
Original line number Diff line number Diff line
@@ -36,5 +36,9 @@ public class WiscNicGroupMemberEntityTypeConfiguration : IEntityTypeConfiguratio
        builder.HasOne(e => e.ContactType)
            .WithMany()
            .HasForeignKey(e => e.ContactTypeId);

        builder.HasIndex(e => new { e.PersonId, e.GroupId, e.ContactTypeId })
            .IsUnique()
            .HasDatabaseName("wn_group_members_unique_person_group_type");
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
    <None Remove="scripts\20260430_1000_WiscNicContactTypes.sql" />
    <None Remove="scripts\20260430_1315_ChangeNetIdField.sql" />
    <None Remove="scripts\20260514_1200_WiscNicSubnetContacts.sql" />
    <None Remove="scripts\20260514_1500_WiscNicGroupMemberUniqueIndex.sql" />
  </ItemGroup>

  <ItemGroup>
@@ -40,6 +41,7 @@
    <EmbeddedResource Include="scripts\20260430_1000_WiscNicContactTypes.sql" />
    <EmbeddedResource Include="scripts\20260430_1315_ChangeNetIdField.sql" />
    <EmbeddedResource Include="scripts\20260514_1200_WiscNicSubnetContacts.sql" />
    <EmbeddedResource Include="scripts\20260514_1500_WiscNicGroupMemberUniqueIndex.sql" />
  </ItemGroup>

  <ItemGroup>
+5 −0
Original line number Diff line number Diff line
-- Enforce uniqueness: a person can hold many contact-type roles in a group,
-- but not the same role twice.
ALTER TABLE `wn_group_members`
  ADD UNIQUE INDEX `wn_group_members_unique_person_group_type`
    (`person_id`, `wn_group_id`, `wn_contact_type_id`);