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

feat: add Infoblox role permissions with permission and resource type tables

Introduces ib_permission_types, ib_resource_types, and ib_role_permissions
tables with full CRUD endpoints nested under role access. Migration seeds
default RO/RW permissions for all existing network and domain access rows.
parent ba31b678
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
using Cals.Visor.Infrastructure.Contexts;
using Cals.Visor.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Cals.Visor.Api.Controllers;

[Route("infoblox/permission-types")]
[ApiController]
public class InfobloxPermissionTypesController : ControllerBase
{
    private readonly ApplicationDbContext _context;

    public InfobloxPermissionTypesController(ApplicationDbContext context) => _context = context;

    // GET: /infoblox/permission-types
    [ProducesResponseType<IList<InfobloxPermissionType>>(StatusCodes.Status200OK)]
    [HttpGet(Name = "GetAllInfobloxPermissionTypes")]
    public async Task<IActionResult> GetAllAsync()
    {
        List<InfobloxPermissionType> result = await _context.InfobloxPermissionTypes
            .OrderBy(e => e.Name)
            .ToListAsync();

        return Ok(result);
    }

    // GET: /infoblox/permission-types/1
    [ProducesResponseType<InfobloxPermissionType>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{permissionTypeId:long}", Name = "GetInfobloxPermissionTypeById")]
    public async Task<IActionResult> GetByIdAsync(long permissionTypeId)
    {
        InfobloxPermissionType? result = await _context.InfobloxPermissionTypes
            .Where(e => e.InfobloxPermissionTypeId == permissionTypeId)
            .FirstOrDefaultAsync();

        if (result == null)
            return NotFound();

        return Ok(result);
    }
}
+44 −0
Original line number Diff line number Diff line
using Cals.Visor.Infrastructure.Contexts;
using Cals.Visor.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Cals.Visor.Api.Controllers;

[Route("infoblox/resource-types")]
[ApiController]
public class InfobloxResourceTypesController : ControllerBase
{
    private readonly ApplicationDbContext _context;

    public InfobloxResourceTypesController(ApplicationDbContext context) => _context = context;

    // GET: /infoblox/resource-types
    [ProducesResponseType<IList<InfobloxResourceType>>(StatusCodes.Status200OK)]
    [HttpGet(Name = "GetAllInfobloxResourceTypes")]
    public async Task<IActionResult> GetAllAsync()
    {
        List<InfobloxResourceType> result = await _context.InfobloxResourceTypes
            .OrderBy(e => e.Name)
            .ToListAsync();

        return Ok(result);
    }

    // GET: /infoblox/resource-types/1
    [ProducesResponseType<InfobloxResourceType>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{resourceTypeId:long}", Name = "GetInfobloxResourceTypeById")]
    public async Task<IActionResult> GetByIdAsync(long resourceTypeId)
    {
        InfobloxResourceType? result = await _context.InfobloxResourceTypes
            .Where(e => e.InfobloxResourceTypeId == resourceTypeId)
            .FirstOrDefaultAsync();

        if (result == null)
            return NotFound();

        return Ok(result);
    }
}
+163 −0
Original line number Diff line number Diff line
@@ -252,4 +252,167 @@ public class InfobloxRolesController : ControllerBase

        return NoContent();
    }

    // GET: /infoblox/roles/1/access/5/permissions
    [ProducesResponseType<IList<InfobloxRolePermission>>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{roleId:long}/access/{roleAccessId:long}/permissions", Name = "GetInfobloxRolePermissions")]
    public async Task<IActionResult> GetPermissionsAsync(long roleId, long roleAccessId)
    {
        bool accessExists = await _context.InfobloxRoleAccess
            .AnyAsync(e => e.RoleId == roleId && e.InfobloxRoleAccessId == roleAccessId);

        if (!accessExists)
            return NotFound();

        List<InfobloxRolePermission> result = await _context.InfobloxRolePermissions
            .Where(e => e.RoleAccessId == roleAccessId)
            .ToListAsync();

        return Ok(result);
    }

    // GET: /infoblox/roles/1/access/5/permissions/7
    [ProducesResponseType<InfobloxRolePermission>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{roleId:long}/access/{roleAccessId:long}/permissions/{permissionId:long}", Name = "GetInfobloxRolePermissionById")]
    public async Task<IActionResult> GetPermissionByIdAsync(long roleId, long roleAccessId, long permissionId)
    {
        bool accessBelongsToRole = await _context.InfobloxRoleAccess
            .AnyAsync(e => e.RoleId == roleId && e.InfobloxRoleAccessId == roleAccessId);

        if (!accessBelongsToRole)
            return NotFound();

        InfobloxRolePermission? result = await _context.InfobloxRolePermissions
            .Where(e => e.RoleAccessId == roleAccessId && e.InfobloxRolePermissionId == permissionId)
            .FirstOrDefaultAsync();

        if (result == null)
            return NotFound();

        return Ok(result);
    }

    // POST: /infoblox/roles/1/access/5/permissions
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<InfobloxRolePermission>(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpPost("{roleId:long}/access/{roleAccessId:long}/permissions", Name = "AddInfobloxRolePermission")]
    public async Task<IActionResult> AddPermissionAsync(long roleId, long roleAccessId, InfobloxRolePermission data)
    {
        bool accessExists = await _context.InfobloxRoleAccess
            .AnyAsync(e => e.RoleId == roleId && e.InfobloxRoleAccessId == roleAccessId);

        if (!accessExists)
            return NotFound();

        bool permissionTypeExists = await _context.InfobloxPermissionTypes
            .AnyAsync(e => e.InfobloxPermissionTypeId == data.PermissionTypeId);

        if (!permissionTypeExists)
            return NotFound();

        bool resourceTypeExists = await _context.InfobloxResourceTypes
            .AnyAsync(e => e.InfobloxResourceTypeId == data.ResourceTypeId);

        if (!resourceTypeExists)
            return NotFound();

        if (data.Permission != "RO" && data.Permission != "RW")
            return BadRequest("Permission must be 'RO' or 'RW'.");

        data.RoleAccessId = roleAccessId;

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

        return CreatedAtRoute(
            "GetInfobloxRolePermissions",
            new { roleId, roleAccessId },
            data);
    }

    // PUT: /infoblox/roles/1/access/5/permissions/7
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<InfobloxRolePermission>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpPut("{roleId:long}/access/{roleAccessId:long}/permissions/{permissionId:long}", Name = "UpdateInfobloxRolePermission")]
    public async Task<IActionResult> UpdatePermissionAsync(long roleId, long roleAccessId, long permissionId, InfobloxRolePermission data)
    {
        bool accessBelongsToRole = await _context.InfobloxRoleAccess
            .AnyAsync(e => e.RoleId == roleId && e.InfobloxRoleAccessId == roleAccessId);

        if (!accessBelongsToRole)
            return NotFound();

        InfobloxRolePermission? entity = await _context.InfobloxRolePermissions
            .Where(e => e.RoleAccessId == roleAccessId && e.InfobloxRolePermissionId == permissionId)
            .FirstOrDefaultAsync();

        if (entity == null)
            return NotFound();

        if (data.PermissionTypeId != null && data.PermissionTypeId != entity.PermissionTypeId)
        {
            bool permissionTypeExists = await _context.InfobloxPermissionTypes
                .AnyAsync(e => e.InfobloxPermissionTypeId == data.PermissionTypeId);

            if (!permissionTypeExists)
                return NotFound();

            entity.PermissionTypeId = data.PermissionTypeId;
        }

        if (data.ResourceTypeId != null && data.ResourceTypeId != entity.ResourceTypeId)
        {
            bool resourceTypeExists = await _context.InfobloxResourceTypes
                .AnyAsync(e => e.InfobloxResourceTypeId == data.ResourceTypeId);

            if (!resourceTypeExists)
                return NotFound();

            entity.ResourceTypeId = data.ResourceTypeId;
        }

        if (data.Permission != null)
        {
            if (data.Permission != "RO" && data.Permission != "RW")
                return BadRequest("Permission must be 'RO' or 'RW'.");

            entity.Permission = data.Permission;
        }

        await _context.SaveChangesAsync();

        return Ok(entity);
    }

    // DELETE: /infoblox/roles/1/access/5/permissions/7
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpDelete("{roleId:long}/access/{roleAccessId:long}/permissions/{permissionId:long}", Name = "DeleteInfobloxRolePermission")]
    public async Task<IActionResult> DeletePermissionAsync(long roleId, long roleAccessId, long permissionId)
    {
        InfobloxRolePermission? entity = await _context.InfobloxRolePermissions
            .Where(e => e.RoleAccessId == roleAccessId && e.InfobloxRolePermissionId == permissionId)
            .FirstOrDefaultAsync();

        if (entity == null)
            return NotFound();

        bool accessBelongsToRole = await _context.InfobloxRoleAccess
            .AnyAsync(e => e.RoleId == roleId && e.InfobloxRoleAccessId == roleAccessId);

        if (!accessBelongsToRole)
            return NotFound();

        _context.InfobloxRolePermissions.Remove(entity);
        await _context.SaveChangesAsync();

        return NoContent();
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -26,9 +26,12 @@ public class ApplicationDbContext : DbContext
    public DbSet<InfobloxDomain> InfobloxDomains => Set<InfobloxDomain>();
    public DbSet<InfobloxGroup> InfobloxGroups => Set<InfobloxGroup>();
    public DbSet<InfobloxNetwork> InfobloxNetworks => Set<InfobloxNetwork>();
    public DbSet<InfobloxPermissionType> InfobloxPermissionTypes => Set<InfobloxPermissionType>();
    public DbSet<InfobloxResourceType> InfobloxResourceTypes => Set<InfobloxResourceType>();
    public DbSet<InfobloxRole> InfobloxRoles => Set<InfobloxRole>();
    public DbSet<InfobloxRoleAccess> InfobloxRoleAccess => Set<InfobloxRoleAccess>();
    public DbSet<InfobloxRoleGroup> InfobloxRoleGroups => Set<InfobloxRoleGroup>();
    public DbSet<InfobloxRolePermission> InfobloxRolePermissions => Set<InfobloxRolePermission>();
    public DbSet<Location> Locations => Set<Location>();
    public DbSet<LocationVlan> LocationVlans => Set<LocationVlan>();
    public DbSet<PaloAltoAccessDomain> PaloAltoAccessDomains => Set<PaloAltoAccessDomain>();
+3 −0
Original line number Diff line number Diff line
@@ -33,9 +33,12 @@ internal sealed class ColumnNames
        internal const string DomainId = "ib_domain_id";
        internal const string GroupID = "ib_group_id";
        internal const string NetworkId = "ib_network_id";
        internal const string PermissionTypeId = "ib_permission_type_id";
        internal const string ResourceTypeId = "ib_resource_type_id";
        internal const string RoleId = "ib_role_id";
        internal const string RoleAccessId = "ib_role_access_id";
        internal const string RoleGroupId = "ib_role_group_id";
        internal const string RolePermissionId = "ib_role_permission_id";
    }

    internal sealed class WiscNic
Loading