Edit Records
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
using DiunaBI.API.Services;
|
||||
using DiunaBI.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DiunaBI.API.Controllers;
|
||||
|
||||
[AllowAnonymous]
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class AuthController(
|
||||
|
||||
@@ -9,6 +9,7 @@ using DiunaBI.Application.DTOModels.Common;
|
||||
|
||||
namespace DiunaBI.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class DataInboxController : Controller
|
||||
|
||||
@@ -12,6 +12,7 @@ using DiunaBI.Infrastructure.Services;
|
||||
|
||||
namespace DiunaBI.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class LayersController : Controller
|
||||
@@ -727,4 +728,209 @@ public class LayersController : Controller
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Record CRUD operations
|
||||
[HttpPost]
|
||||
[Route("{layerId:guid}/records")]
|
||||
public IActionResult CreateRecord(Guid layerId, [FromBody] RecordDto recordDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = Request.Headers["UserId"].ToString();
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
_logger.LogWarning("CreateRecord: No UserId in request headers");
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var layer = _db.Layers.FirstOrDefault(x => x.Id == layerId && !x.IsDeleted);
|
||||
if (layer == null)
|
||||
{
|
||||
_logger.LogWarning("CreateRecord: Layer {LayerId} not found", layerId);
|
||||
return NotFound("Layer not found");
|
||||
}
|
||||
|
||||
if (layer.Type != Domain.Entities.LayerType.Dictionary && layer.Type != Domain.Entities.LayerType.Administration)
|
||||
{
|
||||
_logger.LogWarning("CreateRecord: Layer {LayerId} is not editable (type: {LayerType})", layerId, layer.Type);
|
||||
return BadRequest("Only Dictionary and Administration layers can be edited");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(recordDto.Code))
|
||||
{
|
||||
return BadRequest("Code is required");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(recordDto.Desc1))
|
||||
{
|
||||
return BadRequest("Desc1 is required");
|
||||
}
|
||||
|
||||
var record = new Record
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Code = recordDto.Code,
|
||||
Desc1 = recordDto.Desc1,
|
||||
LayerId = layerId,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ModifiedAt = DateTime.UtcNow,
|
||||
CreatedById = Guid.Parse(userId),
|
||||
ModifiedById = Guid.Parse(userId),
|
||||
IsDeleted = false
|
||||
};
|
||||
|
||||
_db.Records.Add(record);
|
||||
|
||||
// Update layer modified info
|
||||
layer.ModifiedAt = DateTime.UtcNow;
|
||||
layer.ModifiedById = Guid.Parse(userId);
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
_logger.LogInformation("CreateRecord: Created record {RecordId} in layer {LayerId}", record.Id, layerId);
|
||||
|
||||
return Ok(new RecordDto
|
||||
{
|
||||
Id = record.Id,
|
||||
Code = record.Code,
|
||||
Desc1 = record.Desc1,
|
||||
LayerId = record.LayerId,
|
||||
CreatedAt = record.CreatedAt,
|
||||
ModifiedAt = record.ModifiedAt,
|
||||
CreatedById = record.CreatedById,
|
||||
ModifiedById = record.ModifiedById
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "CreateRecord: Error creating record in layer {LayerId}", layerId);
|
||||
return BadRequest(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("{layerId:guid}/records/{recordId:guid}")]
|
||||
public IActionResult UpdateRecord(Guid layerId, Guid recordId, [FromBody] RecordDto recordDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = Request.Headers["UserId"].ToString();
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
_logger.LogWarning("UpdateRecord: No UserId in request headers");
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var layer = _db.Layers.FirstOrDefault(x => x.Id == layerId && !x.IsDeleted);
|
||||
if (layer == null)
|
||||
{
|
||||
_logger.LogWarning("UpdateRecord: Layer {LayerId} not found", layerId);
|
||||
return NotFound("Layer not found");
|
||||
}
|
||||
|
||||
if (layer.Type != Domain.Entities.LayerType.Dictionary && layer.Type != Domain.Entities.LayerType.Administration)
|
||||
{
|
||||
_logger.LogWarning("UpdateRecord: Layer {LayerId} is not editable (type: {LayerType})", layerId, layer.Type);
|
||||
return BadRequest("Only Dictionary and Administration layers can be edited");
|
||||
}
|
||||
|
||||
var record = _db.Records.FirstOrDefault(x => x.Id == recordId && x.LayerId == layerId);
|
||||
if (record == null)
|
||||
{
|
||||
_logger.LogWarning("UpdateRecord: Record {RecordId} not found in layer {LayerId}", recordId, layerId);
|
||||
return NotFound("Record not found");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(recordDto.Code))
|
||||
{
|
||||
return BadRequest("Code is required");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(recordDto.Desc1))
|
||||
{
|
||||
return BadRequest("Desc1 is required");
|
||||
}
|
||||
|
||||
record.Desc1 = recordDto.Desc1;
|
||||
record.ModifiedAt = DateTime.UtcNow;
|
||||
record.ModifiedById = Guid.Parse(userId);
|
||||
|
||||
// Update layer modified info
|
||||
layer.ModifiedAt = DateTime.UtcNow;
|
||||
layer.ModifiedById = Guid.Parse(userId);
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
_logger.LogInformation("UpdateRecord: Updated record {RecordId} in layer {LayerId}", recordId, layerId);
|
||||
|
||||
return Ok(new RecordDto
|
||||
{
|
||||
Id = record.Id,
|
||||
Code = record.Code,
|
||||
Desc1 = record.Desc1,
|
||||
LayerId = record.LayerId,
|
||||
CreatedAt = record.CreatedAt,
|
||||
ModifiedAt = record.ModifiedAt,
|
||||
CreatedById = record.CreatedById,
|
||||
ModifiedById = record.ModifiedById
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "UpdateRecord: Error updating record {RecordId} in layer {LayerId}", recordId, layerId);
|
||||
return BadRequest(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Route("{layerId:guid}/records/{recordId:guid}")]
|
||||
public IActionResult DeleteRecord(Guid layerId, Guid recordId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = Request.Headers["UserId"].ToString();
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
_logger.LogWarning("DeleteRecord: No UserId in request headers");
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var layer = _db.Layers.FirstOrDefault(x => x.Id == layerId && !x.IsDeleted);
|
||||
if (layer == null)
|
||||
{
|
||||
_logger.LogWarning("DeleteRecord: Layer {LayerId} not found", layerId);
|
||||
return NotFound("Layer not found");
|
||||
}
|
||||
|
||||
if (layer.Type != Domain.Entities.LayerType.Dictionary && layer.Type != Domain.Entities.LayerType.Administration)
|
||||
{
|
||||
_logger.LogWarning("DeleteRecord: Layer {LayerId} is not editable (type: {LayerType})", layerId, layer.Type);
|
||||
return BadRequest("Only Dictionary and Administration layers can be edited");
|
||||
}
|
||||
|
||||
var record = _db.Records.FirstOrDefault(x => x.Id == recordId && x.LayerId == layerId);
|
||||
if (record == null)
|
||||
{
|
||||
_logger.LogWarning("DeleteRecord: Record {RecordId} not found in layer {LayerId}", recordId, layerId);
|
||||
return NotFound("Record not found");
|
||||
}
|
||||
|
||||
_db.Records.Remove(record);
|
||||
|
||||
// Update layer modified info
|
||||
layer.ModifiedAt = DateTime.UtcNow;
|
||||
layer.ModifiedById = Guid.Parse(userId);
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
_logger.LogInformation("DeleteRecord: Deleted record {RecordId} from layer {LayerId}", recordId, layerId);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "DeleteRecord: Error deleting record {RecordId} from layer {LayerId}", recordId, layerId);
|
||||
return BadRequest(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,26 +177,67 @@ else
|
||||
|
||||
pluginManager.LoadPluginsFromDirectory(pluginsPath);
|
||||
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var token = context.Request.Headers.Authorization.ToString();
|
||||
if (token.Length > 0
|
||||
&& !context.Request.Path.ToString().Contains("getForPowerBI")
|
||||
&& !context.Request.Path.ToString().Contains("getConfiguration")
|
||||
&& !context.Request.Path.ToString().Contains("DataInbox/Add"))
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var data = handler.ReadJwtToken(token.Split(' ')[1]);
|
||||
context.Request.Headers.Append("UserId", new Microsoft.Extensions.Primitives.StringValues(data.Subject));
|
||||
}
|
||||
await next(context);
|
||||
});
|
||||
|
||||
app.UseCors("CORSPolicy");
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
// Middleware to extract UserId from JWT token AFTER authentication
|
||||
// This must run after UseAuthentication() so the JWT is already validated
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
|
||||
logger.LogInformation("🔍 UserId Extraction Middleware - Path: {Path}, Method: {Method}",
|
||||
context.Request.Path, context.Request.Method);
|
||||
|
||||
var token = context.Request.Headers.Authorization.ToString();
|
||||
logger.LogInformation("🔍 Authorization header: {Token}",
|
||||
string.IsNullOrEmpty(token) ? "NULL/EMPTY" : $"{token[..Math.Min(30, token.Length)]}...");
|
||||
|
||||
if (!string.IsNullOrEmpty(token) && token.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jwtToken = handler.ReadJwtToken(token.Split(' ')[1]);
|
||||
|
||||
// Try to get UserId from Subject claim first, then fall back to NameIdentifier
|
||||
var userId = jwtToken.Subject;
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
// Try NameIdentifier claim (ClaimTypes.NameIdentifier)
|
||||
var nameIdClaim = jwtToken.Claims.FirstOrDefault(c =>
|
||||
c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" ||
|
||||
c.Type == "nameid");
|
||||
userId = nameIdClaim?.Value;
|
||||
}
|
||||
|
||||
logger.LogInformation("🔍 JWT UserId: {UserId}", userId ?? "NULL");
|
||||
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
// Use indexer to set/replace header value instead of Append
|
||||
context.Request.Headers["UserId"] = userId;
|
||||
logger.LogInformation("✅ Set UserId header to: {UserId}", userId);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("❌ UserId not found in JWT claims");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "❌ Failed to extract UserId from JWT token");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("❌ No valid Bearer token found");
|
||||
}
|
||||
|
||||
await next(context);
|
||||
});
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.MapGet("/health", () => Results.Ok(new { status = "OK", timestamp = DateTime.UtcNow }))
|
||||
|
||||
Reference in New Issue
Block a user