Commit 51ae44da authored by Eric Dieckman's avatar Eric Dieckman
Browse files

feat: add VLAN lookup endpoints for WiscNic people and groups

Add GET /people/{personId}/vlans returning a federated list of VLAN
assignments from both direct person contacts and group memberships,
with a source discriminator so duplicates are preserved when a person
is both. Add GET /wiscnic/groups/{groupId}/vlans returning the group's
direct VLAN contact rows. Introduces PersonVlanAssignment response
model for the federated shape.
parent 3b3b61e8
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -79,4 +79,45 @@ public class PeopleController : ControllerBase

        return Ok(entity);
    }

    // GET: /people/1/vlans
    [ProducesResponseType<IList<PersonVlanAssignment>>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{personId:long}/vlans", Name = "GetPersonVlans")]
    public async Task<IActionResult> GetVlansAsync(long personId)
    {
        if (!await _context.People.AnyAsync(p => p.PersonId == personId))
            return NotFound();

        List<PersonVlanAssignment> direct = await _context.WiscNicVlanPersonContacts
            .Where(c => c.PersonId == personId)
            .Select(c => new PersonVlanAssignment
            {
                VlanId = c.VlanId!.Value,
                Vlan = c.Vlan,
                Source = "direct",
                ContactTypeId = c.ContactTypeId,
                ContactType = c.ContactType,
            })
            .ToListAsync();

        List<PersonVlanAssignment> viaGroup = await _context.WiscNicGroupMembers
            .Where(m => m.PersonId == personId)
            .Join(
                _context.WiscNicVlanGroupContacts,
                m => m.GroupId,
                gc => gc.GroupId,
                (m, gc) => new { gc, m.Group })
            .Select(x => new PersonVlanAssignment
            {
                VlanId = x.gc.VlanId!.Value,
                Vlan = x.gc.Vlan,
                Source = "group",
                GroupId = x.gc.GroupId,
                Group = x.Group,
            })
            .ToListAsync();

        return Ok(direct.Concat(viaGroup).ToList());
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -132,4 +132,20 @@ public class WiscNicGroupsController : ControllerBase

        return NoContent();
    }

    // GET: /wiscnic/groups/1/vlans
    [ProducesResponseType<IList<WiscNicVlanGroupContact>>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{groupId:long}/vlans", Name = "GetWiscNicGroupVlans")]
    public async Task<IActionResult> GetVlansAsync(long groupId)
    {
        if (!await _context.WiscNicGroups.AnyAsync(g => g.WiscNicGroupId == groupId))
            return NotFound();

        List<WiscNicVlanGroupContact> result = await _context.WiscNicVlanGroupContacts
            .Where(c => c.GroupId == groupId)
            .ToListAsync();

        return Ok(result);
    }
}
+18 −0
Original line number Diff line number Diff line
namespace Cals.Visor.Models;

public class PersonVlanAssignment
{
    public long VlanId { get; set; }

    public Vlan? Vlan { get; set; }

    public string Source { get; set; } = default!;

    public long? ContactTypeId { get; set; }

    public WiscNicContactType? ContactType { get; set; }

    public long? GroupId { get; set; }

    public WiscNicGroup? Group { get; set; }
}