Commit 4a91d44c authored by Eric Dieckman's avatar Eric Dieckman
Browse files

feat: add Infoblox permission templates with full CRUD endpoints

Introduces ib_permission_templates and ib_permission_template_entries tables with a migration that seeds four default templates (Network IPv4, Network IPv6, Reverse Zone, Zone) matching the standard Infoblox permission groupings.
parent 39bd0b44
Loading
Loading
Loading
Loading
Loading
+227 −0
Original line number Diff line number Diff line
using Cals.Visor.Api.Authorization;
using Cals.Visor.Infrastructure.Contexts;
using Cals.Visor.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Cals.Visor.Api.Controllers;

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

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

    // GET: /infoblox/permission-templates
    [ProducesResponseType<IList<InfobloxPermissionTemplate>>(StatusCodes.Status200OK)]
    [HttpGet(Name = "GetAllInfobloxPermissionTemplates")]
    public async Task<IActionResult> GetAllAsync()
    {
        List<InfobloxPermissionTemplate> result = await _context.InfobloxPermissionTemplates
            .Include(e => e.Entries)
            .OrderBy(e => e.Name)
            .ToListAsync();

        return Ok(result);
    }

    // GET: /infoblox/permission-templates/1
    [ProducesResponseType<InfobloxPermissionTemplate>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{templateId:long}", Name = "GetInfobloxPermissionTemplateById")]
    public async Task<IActionResult> GetByIdAsync(long templateId)
    {
        InfobloxPermissionTemplate? result = await _context.InfobloxPermissionTemplates
            .Include(e => e.Entries)
            .Where(e => e.InfobloxPermissionTemplateId == templateId)
            .FirstOrDefaultAsync();

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

        return Ok(result);
    }

    // POST: /infoblox/permission-templates
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<InfobloxPermissionTemplate>(StatusCodes.Status201Created)]
    [HttpPost(Name = "CreateNewInfobloxPermissionTemplate")]
    public async Task<IActionResult> CreateNewAsync(InfobloxPermissionTemplate data)
    {
        _context.InfobloxPermissionTemplates.Add(data);
        await _context.SaveChangesAsync();

        return CreatedAtRoute("GetInfobloxPermissionTemplateById", new { templateId = data.InfobloxPermissionTemplateId }, data);
    }

    // PUT: /infoblox/permission-templates/1
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<InfobloxPermissionTemplate>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpPut("{templateId:long}", Name = "UpdateInfobloxPermissionTemplate")]
    public async Task<IActionResult> UpdateAsync(long templateId, InfobloxPermissionTemplate data)
    {
        InfobloxPermissionTemplate? entity = await _context.InfobloxPermissionTemplates
            .Where(e => e.InfobloxPermissionTemplateId == templateId)
            .FirstOrDefaultAsync();

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

        entity.Name = data.Name;

        await _context.SaveChangesAsync();

        return Ok(entity);
    }

    // DELETE: /infoblox/permission-templates/1
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpDelete("{templateId:long}", Name = "DeleteInfobloxPermissionTemplate")]
    public async Task<IActionResult> DeleteAsync(long templateId)
    {
        InfobloxPermissionTemplate? entity = await _context.InfobloxPermissionTemplates
            .Where(e => e.InfobloxPermissionTemplateId == templateId)
            .FirstOrDefaultAsync();

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

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

        return NoContent();
    }

    // GET: /infoblox/permission-templates/1/entries
    [ProducesResponseType<IList<InfobloxPermissionTemplateEntry>>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet("{templateId:long}/entries", Name = "GetInfobloxPermissionTemplateEntries")]
    public async Task<IActionResult> GetEntriesAsync(long templateId)
    {
        bool templateExists = await _context.InfobloxPermissionTemplates
            .AnyAsync(e => e.InfobloxPermissionTemplateId == templateId);

        if (!templateExists)
            return NotFound();

        List<InfobloxPermissionTemplateEntry> result = await _context.InfobloxPermissionTemplateEntries
            .Where(e => e.TemplateId == templateId)
            .ToListAsync();

        return Ok(result);
    }

    // POST: /infoblox/permission-templates/1/entries
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<InfobloxPermissionTemplateEntry>(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpPost("{templateId:long}/entries", Name = "AddInfobloxPermissionTemplateEntry")]
    public async Task<IActionResult> AddEntryAsync(long templateId, InfobloxPermissionTemplateEntry data)
    {
        bool templateExists = await _context.InfobloxPermissionTemplates
            .AnyAsync(e => e.InfobloxPermissionTemplateId == templateId);

        if (!templateExists)
            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.TemplateId = templateId;

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

        return CreatedAtRoute("GetInfobloxPermissionTemplateEntries", new { templateId }, data);
    }

    // PUT: /infoblox/permission-templates/1/entries/3
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType<InfobloxPermissionTemplateEntry>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpPut("{templateId:long}/entries/{entryId:long}", Name = "UpdateInfobloxPermissionTemplateEntry")]
    public async Task<IActionResult> UpdateEntryAsync(long templateId, long entryId, InfobloxPermissionTemplateEntry data)
    {
        InfobloxPermissionTemplateEntry? entity = await _context.InfobloxPermissionTemplateEntries
            .Where(e => e.TemplateId == templateId && e.InfobloxPermissionTemplateEntryId == entryId)
            .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/permission-templates/1/entries/3
    [Authorize(Policy = Policies.CanEdit)]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpDelete("{templateId:long}/entries/{entryId:long}", Name = "DeleteInfobloxPermissionTemplateEntry")]
    public async Task<IActionResult> DeleteEntryAsync(long templateId, long entryId)
    {
        InfobloxPermissionTemplateEntry? entity = await _context.InfobloxPermissionTemplateEntries
            .Where(e => e.TemplateId == templateId && e.InfobloxPermissionTemplateEntryId == entryId)
            .FirstOrDefaultAsync();

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

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

        return NoContent();
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ public class ApplicationDbContext : DbContext
    public DbSet<InfobloxDomain> InfobloxDomains => Set<InfobloxDomain>();
    public DbSet<InfobloxGroup> InfobloxGroups => Set<InfobloxGroup>();
    public DbSet<InfobloxNetwork> InfobloxNetworks => Set<InfobloxNetwork>();
    public DbSet<InfobloxPermissionTemplate> InfobloxPermissionTemplates => Set<InfobloxPermissionTemplate>();
    public DbSet<InfobloxPermissionTemplateEntry> InfobloxPermissionTemplateEntries => Set<InfobloxPermissionTemplateEntry>();
    public DbSet<InfobloxPermissionType> InfobloxPermissionTypes => Set<InfobloxPermissionType>();
    public DbSet<InfobloxResourceType> InfobloxResourceTypes => Set<InfobloxResourceType>();
    public DbSet<InfobloxRole> InfobloxRoles => Set<InfobloxRole>();
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ 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 PermissionTemplateId = "ib_permission_template_id";
        internal const string PermissionTemplateEntryId = "ib_permission_template_entry_id";
        internal const string PermissionTypeId = "ib_permission_type_id";
        internal const string ResourceTypeId = "ib_resource_type_id";
        internal const string RoleId = "ib_role_id";
+2 −0
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ internal sealed class TableNames
    internal const string InfobloxDomains = "ib_domains";
    internal const string InfobloxGroups = "ib_groups";
    internal const string InfobloxNetworks = "ib_networks";
    internal const string InfobloxPermissionTemplates = "ib_permission_templates";
    internal const string InfobloxPermissionTemplateEntries = "ib_permission_template_entries";
    internal const string InfobloxPermissionTypes = "ib_permission_types";
    internal const string InfobloxResourceTypes = "ib_resource_types";
    internal const string InfobloxRoleAccess = "ib_role_access";
+23 −0
Original line number Diff line number Diff line
using Cals.Visor.Infrastructure.Database;
using Cals.Visor.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Cals.Visor.Infrastructure.Models;

public class InfobloxPermissionTemplateEntityTypeConfiguration : IEntityTypeConfiguration<InfobloxPermissionTemplate>
{
    public void Configure(EntityTypeBuilder<InfobloxPermissionTemplate> builder)
    {
        builder.ToTable(TableNames.InfobloxPermissionTemplates);

        builder.HasKey(e => e.InfobloxPermissionTemplateId);

        builder.Property(e => e.InfobloxPermissionTemplateId)
            .HasColumnName(ColumnNames.Infoblox.PermissionTemplateId);

        builder.HasMany(e => e.Entries)
            .WithOne(e => e.Template)
            .HasForeignKey(e => e.TemplateId);
    }
}
Loading