Compare commits
87 Commits
537891b8c5
...
feat/profi
| Author | SHA1 | Date | |
|---|---|---|---|
| c10f3c1b58 | |||
| b71e451121 | |||
| d4ea68fc0e | |||
| 142a1a4faa | |||
| 66fe515518 | |||
| f54329ecd3 | |||
| 9b7475bb56 | |||
| 1d0ded0e84 | |||
| 9332a9161d | |||
| 6a04f36388 | |||
| 581bd22c24 | |||
| eafdc17b70 | |||
| c952df5bb4 | |||
| 8c6202d7c0 | |||
| 288f8f98bd | |||
| 659a402555 | |||
| 6288312c01 | |||
| 91679180ec | |||
| bdc773d8ed | |||
| cfbd0f013d | |||
| d4b33d4b9a | |||
| 4e5cb91967 | |||
| b859391ab1 | |||
| 26300d8653 | |||
| 9d07b1e71c | |||
| ec975a2bc3 | |||
| f10f5af541 | |||
| 7d07fc58e9 | |||
| 7e82f688ad | |||
| c325b2122b | |||
| 63adb51263 | |||
| 363606dc61 | |||
| bc192e99a7 | |||
| 69d417616d | |||
| a3cbe69fd6 | |||
| c2e8b335e0 | |||
| 7ed86f18d7 | |||
| 2fd64cb616 | |||
| b89a69b0f3 | |||
| bb29b1563a | |||
| ad023b01d3 | |||
| 7309b968fe | |||
| 1159f3f575 | |||
| 8f2261f0fa | |||
| c779dd4a47 | |||
| 709ebea097 | |||
| 63df235943 | |||
| 78f2788388 | |||
| 13acf6de08 | |||
| 5466b35b95 | |||
| d0e306b7e4 | |||
| 4fcc0a08b8 | |||
| 904536bd09 | |||
| 6c0f39e3ed | |||
| 8ceaa9cb21 | |||
| 27e4b4b2ef | |||
| 82eb03b420 | |||
| 559127a931 | |||
|
|
87857862e4 | ||
| 8655f78c8c | |||
| 168a4b0791 | |||
| dd4cd1b39e | |||
| 8eb8801c41 | |||
| eb7ed81cac | |||
| b7c6477ec2 | |||
| b7f9efa9b6 | |||
| bf5566cefc | |||
| f8e51e02a0 | |||
| ad1fd3163e | |||
| bed5fae01c | |||
| a378862791 | |||
| dd2dbee037 | |||
| b24f518bba | |||
| dd5babfdbe | |||
| dc7da91872 | |||
| fe358623da | |||
| c08c5aacf3 | |||
| 14f5c73d43 | |||
| b25d4eb028 | |||
| 8c08beba4e | |||
| 30bb3ffa11 | |||
| a9faf74803 | |||
| 22e4b4f54f | |||
| a954a24888 | |||
| a78c117a47 | |||
| 07e16f8aca | |||
| 0b70016ab6 |
@@ -5,6 +5,7 @@ VisualStudioVersion = 17.9.34622.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
scripts\GetProfile.sql = scripts\GetProfile.sql
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
||||
4
scripts/GetProfile.sql
Normal file
4
scripts/GetProfile.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
--PROFILES
|
||||
select * from FNMWF_GET_PROFILES (1) --USER_ID
|
||||
--PROFILE_OBJECTS
|
||||
SELECT * FROM [FNMWF_GET_PROFILE_OBJECTS] (1,1) --USERID, PROFILE_ID
|
||||
12
src/WorkFlow.API/Base64File.cs
Normal file
12
src/WorkFlow.API/Base64File.cs
Normal file
File diff suppressed because one or more lines are too long
@@ -1,20 +0,0 @@
|
||||
using DigitalData.Core.API;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Config;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ConfigController : CRUDControllerBaseWithErrorHandling<IConfigService, ConfigCreateDto, ConfigDto, ConfigUpdateDto, Config, int>
|
||||
{
|
||||
public ConfigController(ILogger<ConfigController> logger, IConfigService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,96 +1,74 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Claims;
|
||||
using WorkFlow.API.Attributes;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[APIKeyAuth]
|
||||
public static class ControllerExtensions
|
||||
{
|
||||
[APIKeyAuth]
|
||||
public static class ControllerExtensions
|
||||
public static bool TryGetUserId(this ClaimsPrincipal user, out int id) => int.TryParse(user.FindFirstValue(ClaimTypes.NameIdentifier), out id);
|
||||
|
||||
public static bool TryGetUsername(this ClaimsPrincipal user, out string username)
|
||||
{
|
||||
public static bool TryGetUserId(this ControllerBase controller, out int? id)
|
||||
var value = user.FindFirstValue(ClaimTypes.Name);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
id = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(int.TryParse(value, out int id_int))
|
||||
{
|
||||
id = id_int;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = null;
|
||||
return false;
|
||||
}
|
||||
username = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetUsername(this ControllerBase controller, out string username)
|
||||
else
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.Name);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
username = string.Empty;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
username = value;
|
||||
return true;
|
||||
}
|
||||
username = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetName(this ControllerBase controller, out string name)
|
||||
public static bool TryGetName(this ClaimsPrincipal user, out string name)
|
||||
{
|
||||
var value = user.FindFirstValue(ClaimTypes.Surname);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.Surname);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
name = string.Empty;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = value;
|
||||
return true;
|
||||
}
|
||||
name = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetPrename(this ControllerBase controller, out string prename)
|
||||
else
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.GivenName);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
prename = string.Empty;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
prename = value;
|
||||
return true;
|
||||
}
|
||||
name = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetEmail(this ControllerBase controller, out string email)
|
||||
public static bool TryGetPrename(this ClaimsPrincipal user, out string prename)
|
||||
{
|
||||
var value = user.FindFirstValue(ClaimTypes.GivenName);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.Email);
|
||||
prename = string.Empty;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
prename = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
email = string.Empty;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
email = value;
|
||||
return true;
|
||||
}
|
||||
public static bool TryGetEmail(this ClaimsPrincipal user, out string email)
|
||||
{
|
||||
var value = user.FindFirstValue(ClaimTypes.Email);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
email = string.Empty;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
email = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/WorkFlow.API/Controllers/FileController.cs
Normal file
57
src/WorkFlow.API/Controllers/FileController.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Web;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class FileController : ControllerBase
|
||||
{
|
||||
[HttpGet("{path}")]
|
||||
public IActionResult GetFile([FromRoute] string path, [FromQuery] bool icon = false)
|
||||
{
|
||||
string dPath = HttpUtility.UrlDecode(path);
|
||||
|
||||
byte[]? fileBytes = null;
|
||||
string? contentType = null;
|
||||
|
||||
if (dPath == "docs/doc1.pdf" && !icon)
|
||||
{
|
||||
fileBytes = Convert.FromBase64String(Base64File.Doc1Base64);
|
||||
contentType = "application/pdf";
|
||||
}
|
||||
else if (dPath == "icons/icon1.png" && icon)
|
||||
{
|
||||
fileBytes = Convert.FromBase64String(Base64File.Icon1Base64);
|
||||
contentType = "image/png";
|
||||
}
|
||||
else
|
||||
{
|
||||
string fullPath = Path.Combine(AppContext.BaseDirectory, "files", dPath);
|
||||
if (!System.IO.File.Exists(fullPath))
|
||||
return NotFound();
|
||||
|
||||
fileBytes = System.IO.File.ReadAllBytes(fullPath);
|
||||
contentType = GetContentType(fullPath);
|
||||
}
|
||||
|
||||
return File(fileBytes, contentType ?? "application/octet-stream");
|
||||
}
|
||||
|
||||
private string GetContentType(string path)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLowerInvariant();
|
||||
return ext switch
|
||||
{
|
||||
".pdf" => "application/pdf",
|
||||
".png" => "image/png",
|
||||
".jpg" => "image/jpeg",
|
||||
".jpeg" => "image/jpeg",
|
||||
".txt" => "text/plain",
|
||||
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
_ => "application/octet-stream",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace WorkFlow.API.Controllers;
|
||||
public class PlaceholderAuthController : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public IActionResult CreateTokenViaBody([FromBody] Login login)
|
||||
public IActionResult CreateToken([FromBody] Login login)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using DigitalData.Core.API;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Application.Profiles;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
@@ -12,9 +10,28 @@ namespace WorkFlow.API.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ProfileController : CRUDControllerBaseWithErrorHandling<IProfileService, ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>
|
||||
public class ProfileController : ControllerBase
|
||||
{
|
||||
public ProfileController(ILogger<ProfileController> logger, IProfileService service) : base(logger, service)
|
||||
private readonly ILogger<ProfileController> _logger;
|
||||
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public ProfileController(ILogger<ProfileController> logger, IMediator mediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAsync()
|
||||
{
|
||||
if (!User.TryGetUserId(out var userId))
|
||||
{
|
||||
_logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return Unauthorized("Failed to retrieve user identity.");
|
||||
}
|
||||
|
||||
var profile = await _mediator.ReadProfileAsync(userId);
|
||||
return Ok(profile);
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ProfileControlsTFController : CRUDControllerBase<IProfileControlsTFService, ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTFUpdateDto, ProfileControlsTF, int>
|
||||
{
|
||||
private readonly ILogger<ProfileControlsTFController> logger;
|
||||
|
||||
public ProfileControlsTFController(ILogger<ProfileControlsTFController> logger, IProfileControlsTFService service) : base(logger, service)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Update(ProfileControlsTFUpdateDto updateDto) => base.Update(updateDto);
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAsync(
|
||||
bool withProfile = true, bool withUser = false,
|
||||
int? profileId = null, int? objId = null, bool? profileActive = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if (id is null)
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
|
||||
return await _service.ReadAsync(
|
||||
withProfile: withProfile, withUser: withUser,
|
||||
userId: id,
|
||||
profileId: profileId, objId: objId, profileActive: profileActive)
|
||||
.ThenAsync(
|
||||
Success: pctf => pctf.Any() ? Ok(pctf) : NotFound(),
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
logger.LogNotice(ntc);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public override async Task<IActionResult> Create([FromBody] ProfileControlsTFCreateDto createDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if (id is null)
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
|
||||
if (createDto.UserId != id)
|
||||
return Unauthorized();
|
||||
|
||||
return await base.Create(createDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public override async Task<IActionResult> Delete([FromRoute] int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? userId))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if (userId is null)
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
|
||||
return await _service.ReadByIdAsync(id).ThenAsync(
|
||||
SuccessAsync: async pctf => pctf.UserId == userId ? await base.Delete(id) : Unauthorized(),
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
return ntc.HasFlag(Flag.NotFound) ? NotFound() : StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileObjState;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ProfileObjStateController : CRUDControllerBaseWithErrorHandling<IProfileObjStateService, ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjStateUpdateDto, ProfileObjState, int>
|
||||
{
|
||||
private readonly ILogger<ProfileObjStateController> logger;
|
||||
|
||||
public ProfileObjStateController(ILogger<ProfileObjStateController> logger, IProfileObjStateService service) : base(logger, service)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Update(ProfileObjStateUpdateDto updateDto) => base.Update(updateDto);
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAsync(
|
||||
bool withProfile = true, bool withUser = true, bool withState = true,
|
||||
int? profileId = null, int? objId = null, bool? profileActive = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if (id is null)
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
|
||||
return await _service.ReadAsync(
|
||||
withProfile: withProfile, withUser: withUser, withState,
|
||||
userId: id,
|
||||
profileId: profileId, objId: objId, profileActive: profileActive)
|
||||
.ThenAsync(
|
||||
Success: pctf => pctf.Any() ? Ok(pctf) : NotFound(),
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
logger.LogNotice(ntc);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public override async Task<IActionResult> Create([FromBody] ProfileObjStateCreateDto createDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if (id is null)
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
|
||||
if (createDto.UserId != id)
|
||||
return Unauthorized();
|
||||
|
||||
return await base.Create(createDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public override async Task<IActionResult> Delete([FromRoute] int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? userId))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if (userId is null)
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
|
||||
return await _service.ReadByIdAsync(id).ThenAsync(
|
||||
SuccessAsync: async pctf => pctf.UserId == userId ? await base.Delete(id) : Unauthorized(),
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
return ntc.HasFlag(Flag.NotFound) ? NotFound() : StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using DigitalData.Core.API;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class StateController : CRUDControllerBaseWithErrorHandling<IStateService, StateCreateDto, StateDto, StateUpdateDto, State, int>
|
||||
{
|
||||
public StateController(ILogger<StateController> logger, IStateService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -10,6 +10,7 @@ namespace WorkFlow.API.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Obsolete("Use MediatR")]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<UserController> logger;
|
||||
@@ -24,31 +25,18 @@ public class UserController : ControllerBase
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAsync()
|
||||
{
|
||||
try
|
||||
if (!User.TryGetUserId(out var id))
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
{
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to retrieve user identity.");
|
||||
}
|
||||
else if(id is int id_int)
|
||||
return await userService.ReadByIdAsync(id_int).ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
logger.LogNotice(ntc);
|
||||
return NotFound();
|
||||
});
|
||||
else
|
||||
{
|
||||
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
||||
logger.LogError("Authorization failed: User ID claim not found.");
|
||||
return Unauthorized("Failed to retrieve user identity.");
|
||||
}
|
||||
|
||||
return await userService.ReadByIdAsync(id).ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
logger.LogNotice(ntc);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
}
|
||||
84
src/WorkFlow.API/Middleware/ExceptionHandlingMiddleware.cs
Normal file
84
src/WorkFlow.API/Middleware/ExceptionHandlingMiddleware.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using DigitalData.Core.Exceptions;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace WorkFlow.API.Middleware;
|
||||
|
||||
//TODO: Fix and use DigitalData.Core.Exceptions.Middleware
|
||||
/// <summary>
|
||||
/// Middleware for handling exceptions globally in the application.
|
||||
/// Captures exceptions thrown during the request pipeline execution,
|
||||
/// logs them, and returns an appropriate HTTP response with a JSON error message.
|
||||
/// </summary>
|
||||
[Obsolete("Use DigitalData.Core.Exceptions.Middleware")]
|
||||
public class ExceptionHandlingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<ExceptionHandlingMiddleware> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExceptionHandlingMiddleware"/> class.
|
||||
/// </summary>
|
||||
/// <param name="next">The next middleware in the request pipeline.</param>
|
||||
/// <param name="logger">The logger instance for logging exceptions.</param>
|
||||
public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the middleware to handle the HTTP request.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP context of the current request.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _next(context); // Continue down the pipeline
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await HandleExceptionAsync(context, ex, _logger);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles exceptions by logging them and writing an appropriate JSON response.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP context of the current request.</param>
|
||||
/// <param name="exception">The exception that occurred.</param>
|
||||
/// <param name="logger">The logger instance for logging the exception.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
private static async Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger logger)
|
||||
{
|
||||
context.Response.ContentType = "application/json";
|
||||
|
||||
string message;
|
||||
|
||||
switch (exception)
|
||||
{
|
||||
case BadRequestException badRequestEx:
|
||||
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
message = badRequestEx.Message;
|
||||
break;
|
||||
|
||||
case NotFoundException notFoundEx:
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
message = notFoundEx.Message;
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.LogError(exception, "Unhandled exception occurred.");
|
||||
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
message = "An unexpected error occurred.";
|
||||
break;
|
||||
}
|
||||
|
||||
await context.Response.WriteAsync(JsonSerializer.Serialize(new
|
||||
{
|
||||
message
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
using WorkFlow.Application;
|
||||
using DigitalData.UserManager.Application;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Infrastructure;
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Auth.Client;
|
||||
using DigitalData.Core.Abstractions.Security.Extensions;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using DigitalData.UserManager.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using WorkFlow.API.Models;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using NLog;
|
||||
using NLog.Web;
|
||||
using WorkFlow.API;
|
||||
using WorkFlow.API.Extensions;
|
||||
using WorkFlow.API.Filters;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using DigitalData.Auth.Client;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using WorkFlow.API;
|
||||
using Microsoft.Extensions.Options;
|
||||
using DigitalData.Core.Abstractions.Security;
|
||||
using WorkFlow.API.Middleware;
|
||||
using WorkFlow.API.Models;
|
||||
using WorkFlow.Application;
|
||||
using WorkFlow.Infrastructure;
|
||||
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
logger.Info("Logging initialized.");
|
||||
@@ -26,22 +26,42 @@ try
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var config = builder.Configuration;
|
||||
|
||||
Directory
|
||||
.GetFiles(builder.Environment.ContentRootPath, "appsettings.*.json", SearchOption.TopDirectoryOnly)
|
||||
.Where(file => Path.GetFileName(file) != $"appsettings.Development.json")
|
||||
.ToList()
|
||||
.ForEach(file => config.AddJsonFile(file, true, true));
|
||||
|
||||
// Add NLogger
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Host.UseNLog();
|
||||
builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
|
||||
if (!builder.Environment.IsDevelopment())
|
||||
{
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Host.UseNLog();
|
||||
}
|
||||
|
||||
// Add services to the container
|
||||
var cnn_str = config.GetConnectionString("Default") ?? throw new("Default connection string not found.");
|
||||
builder.Services.AddDbContext<WFDBContext>(options => options.UseSqlServer(cnn_str).EnableDetailedErrors());
|
||||
builder.Services.AddWorkFlow().AddUserManager<WFDBContext>();
|
||||
builder.Services.AddCookieBasedLocalizer();
|
||||
var mediatRLicense = config["MediatRLicense"]
|
||||
?? throw new InvalidOperationException(
|
||||
"The 'MediatRLicense' configuration value is missing or empty." +
|
||||
"Please ensure it is properly set in the configuration source.");
|
||||
builder.Services.AddWorkFlowServices(opt =>
|
||||
{
|
||||
opt.MediatRLicense = mediatRLicense;
|
||||
opt.ConfigMapping(config.GetSection("MappingOptions"));
|
||||
}).AddWorkFlowRepositories();
|
||||
|
||||
builder.Services.AddUserManager<WFDBContext>();
|
||||
|
||||
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
|
||||
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
||||
{
|
||||
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
|
||||
});
|
||||
|
||||
bool disableAPIKeyAuth = config.GetValue<bool>("DisableAPIKeyAuth") && builder.IsDevOrDiP();
|
||||
bool disableAPIKeyAuth = config.GetValue<bool>("DisableAPIKeyAuth");
|
||||
if (disableAPIKeyAuth)
|
||||
builder.Services.AddAPIKeyAuth(new APIKeyAuthOptions());
|
||||
else
|
||||
@@ -135,8 +155,10 @@ try
|
||||
|
||||
lazyProvider.Factory = () => app.Services;
|
||||
|
||||
app.UseMiddleware<ExceptionHandlingMiddleware>();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.IsDevOrDiP() && app.Configuration.GetValue<bool>("EnableSwagger"))
|
||||
if (app.Configuration.GetValue<bool>("EnableSwagger"))
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
@@ -148,8 +170,6 @@ try
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseCookieBasedLocalizer("de-DE");
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7120;http://localhost:5130",
|
||||
"environmentVariables": {
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PackageId>WorkFlow.API</PackageId>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>1.2.1</Version>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>WorkFlow.API</Product>
|
||||
<Title>WorkFlow.API</Title>
|
||||
<AssemblyVersion>1.1.0</AssemblyVersion>
|
||||
<FileVersion>1.1.0</FileVersion>
|
||||
<AssemblyVersion>1.2.1</AssemblyVersion>
|
||||
<FileVersion>1.2.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -20,16 +20,19 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.3" />
|
||||
<PackageReference Include="DigitalData.Core.API" Version="2.1.1" />
|
||||
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.7" />
|
||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.0.0" />
|
||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.20" />
|
||||
<PackageReference Include="NLog" Version="5.3.4" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.14" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="UserManager" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WorkFlow.Application\WorkFlow.Application.csproj" />
|
||||
<ProjectReference Include="..\WorkFlow.Infrastructure\WorkFlow.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
18
src/WorkFlow.API/appsettings.Auth.json
Normal file
18
src/WorkFlow.API/appsettings.Auth.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"DisableAPIKeyAuth": true,
|
||||
"APIKeyAuth": {
|
||||
"Key": "ULbcOUiAXAoCXPviyCGtObZUGnrCHNgDmtNbQNpq5MOhB0EFQn18dObdQ93INNy8xIcnOPMJfEHqOotllELVrJ2R5AjqOfQszT2j00w215GanD3UiJGwFhwmdoNFsmNj",
|
||||
"HeaderName": "X-API-Key",
|
||||
"SwaggerDescription": "Required header for API key authentication. Enter a valid API key."
|
||||
},
|
||||
"AuthClientParams": {
|
||||
"Url": "http://172.24.12.39:9090/auth-hub",
|
||||
"RetryDelay": "00:00:05",
|
||||
"PublicKeys": [
|
||||
{
|
||||
"Issuer": "auth.digitaldata.works",
|
||||
"Audience": "work-flow.digitaldata.works"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
11
src/WorkFlow.API/appsettings.LDAP.json
Normal file
11
src/WorkFlow.API/appsettings.LDAP.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"DirectorySearchOptions": {
|
||||
"ServerName": "DD-VMP01-DC01",
|
||||
"Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works",
|
||||
"UserCacheExpirationDays": 1,
|
||||
"CustomSearchFilters": {
|
||||
"User": "(&(objectClass=user)(sAMAccountName=*))",
|
||||
"Group": "(&(objectClass=group) (samAccountName=*))"
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/WorkFlow.API/appsettings.Logging.json
Normal file
51
src/WorkFlow.API/appsettings.Logging.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"NLog": {
|
||||
"throwConfigExceptions": true,
|
||||
"variables": {
|
||||
"logDirectory": "E:\\LogFiles\\Digital Data\\workFlow.API",
|
||||
"logFileNamePrefix": "${shortdate}-workFlow.API"
|
||||
},
|
||||
"targets": {
|
||||
"infoLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Info.log",
|
||||
"maxArchiveDays": 30
|
||||
},
|
||||
"errorLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Error.log",
|
||||
"maxArchiveDays": 30
|
||||
},
|
||||
"criticalLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Critical.log",
|
||||
"maxArchiveDays": 30
|
||||
}
|
||||
},
|
||||
// Trace, Debug, Info, Warn, Error and *Fatal*
|
||||
"rules": [
|
||||
{
|
||||
"logger": "*",
|
||||
"minLevel": "Info",
|
||||
"maxLevel": "Warn",
|
||||
"writeTo": "infoLogs"
|
||||
},
|
||||
{
|
||||
"logger": "*",
|
||||
"level": "Error",
|
||||
"writeTo": "errorLogs"
|
||||
},
|
||||
{
|
||||
"logger": "*",
|
||||
"level": "Fatal",
|
||||
"writeTo": "criticalLogs"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
17
src/WorkFlow.API/appsettings.Mapping.json
Normal file
17
src/WorkFlow.API/appsettings.Mapping.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"MappingOptions": {
|
||||
"TfFileUri": {
|
||||
"Scheme": "https",
|
||||
"Host": "dd-gan.digitaldata.works",
|
||||
"Port": 8443,
|
||||
"Path": "api/file"
|
||||
},
|
||||
"TfFileIconUri": {
|
||||
"Scheme": "https",
|
||||
"Host": "dd-gan.digitaldata.works",
|
||||
"Port": 8443,
|
||||
"Path": "api/file",
|
||||
"Query": "icon=true"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +1,10 @@
|
||||
{
|
||||
"DiPMode": true,
|
||||
"EnableSwagger": true,
|
||||
"DisableAPIKeyAuth": false,
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"NLog": {
|
||||
"throwConfigExceptions": true,
|
||||
"variables": {
|
||||
"logDirectory": "E:\\LogFiles\\Digital Data\\workFlow.API",
|
||||
"logFileNamePrefix": "${shortdate}-workFlow.API"
|
||||
},
|
||||
"targets": {
|
||||
"infoLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Info.log",
|
||||
"maxArchiveDays": 30
|
||||
},
|
||||
"errorLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Error.log",
|
||||
"maxArchiveDays": 30
|
||||
},
|
||||
"criticalLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Critical.log",
|
||||
"maxArchiveDays": 30
|
||||
}
|
||||
},
|
||||
// Trace, Debug, Info, Warn, Error and *Fatal*
|
||||
"rules": [
|
||||
{
|
||||
"logger": "*",
|
||||
"minLevel": "Info",
|
||||
"maxLevel": "Warn",
|
||||
"writeTo": "infoLogs"
|
||||
},
|
||||
{
|
||||
"logger": "*",
|
||||
"level": "Error",
|
||||
"writeTo": "errorLogs"
|
||||
},
|
||||
{
|
||||
"logger": "*",
|
||||
"level": "Fatal",
|
||||
"writeTo": "criticalLogs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||
},
|
||||
"DirectorySearchOptions": {
|
||||
"ServerName": "DD-VMP01-DC01",
|
||||
"Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works",
|
||||
"UserCacheExpirationDays": 1,
|
||||
"CustomSearchFilters": {
|
||||
"User": "(&(objectClass=user)(sAMAccountName=*))",
|
||||
"Group": "(&(objectClass=group) (samAccountName=*))"
|
||||
}
|
||||
},
|
||||
"APIKeyAuth": {
|
||||
"Key": "ULbcOUiAXAoCXPviyCGtObZUGnrCHNgDmtNbQNpq5MOhB0EFQn18dObdQ93INNy8xIcnOPMJfEHqOotllELVrJ2R5AjqOfQszT2j00w215GanD3UiJGwFhwmdoNFsmNj",
|
||||
"HeaderName": "X-API-Key",
|
||||
"SwaggerDescription": "Required header for API key authentication. Enter a valid API key."
|
||||
},
|
||||
"OpenApiInfo": {
|
||||
"Title": "WorkFlow API",
|
||||
"Contact": {
|
||||
@@ -77,15 +13,5 @@
|
||||
"Url": "https://digitaldata.works/"
|
||||
}
|
||||
},
|
||||
"AuthClientParams": {
|
||||
"Url": "https://localhost:7192/auth-hub",
|
||||
"PublicKeys": [
|
||||
{
|
||||
"Issuer": "auth.digitaldata.works",
|
||||
"Audience": "work-flow.digitaldata.works",
|
||||
"Content": "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3QCd7dH/xOUITFZbitMa/xnh8a0LyL6ZBvSRAwkI9ceplTRSHJXoM1oB+xtjWE1kOuHVLe941Tm03szS4+/rHIm0Ejva/KKlv7sPFAHE/pWuoPS303vOHgI4HAFcuwywA8CghUWzaaK5LU/Hl8srWwxBHv5hKIUjJFJygeAIENvFOZ1gFbB3MPEC99PiPOwAmfl4tMQUmSsFyspl/RWVi7bTv26ZE+m3KPcWppmvmYjXlSitxRaySxnfFvpca/qWfd/uUUg2KWKtpAwWVkqr0qD9v3TyKSgHoGDsrFpwSx8qufUJSinmZ1u/0iKl6TXeHubYS4C4SUSVjOWXymI2ZQIDAQAB-----END PUBLIC KEY-----"
|
||||
}
|
||||
],
|
||||
"RetryDelay": "00:00:05"
|
||||
}
|
||||
"MediatRLicense": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg"
|
||||
}
|
||||
20
src/WorkFlow.Application/Buttons/ReadButton.cs
Normal file
20
src/WorkFlow.Application/Buttons/ReadButton.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace WorkFlow.Application.Buttons;
|
||||
|
||||
public record ButtonDto
|
||||
{
|
||||
public byte? DialogNo { get; init; }
|
||||
|
||||
public string? BtnType { get; init; }
|
||||
|
||||
public string? Icon { get; init; }
|
||||
|
||||
public string? ForeColor { get; init; }
|
||||
|
||||
public string? BackColor { get; init; }
|
||||
|
||||
public string? Command { get; init; }
|
||||
|
||||
public string? DialogCommand { get; init; }
|
||||
|
||||
public string? ConfirmationText { get; init; }
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using WorkFlow.Application.DTO.Config;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts
|
||||
{
|
||||
public interface IConfigService : ICRUDService<ConfigCreateDto, ConfigDto, Config, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts
|
||||
{
|
||||
public interface IProfileControlsTFService : ICRUDService<ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTF, int>
|
||||
{
|
||||
Task<DataResult<IEnumerable<ProfileControlsTFDto>>> ReadAsync(
|
||||
bool withProfile = true, bool withUser = false,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null, bool? profileActive = null);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using WorkFlow.Application.DTO.ProfileObjState;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts;
|
||||
|
||||
public interface IProfileObjStateService : ICRUDService<ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjState, int>
|
||||
{
|
||||
Task<DataResult<IEnumerable<ProfileObjStateDto>>> ReadAsync(
|
||||
bool withProfile = true, bool withUser = true, bool withState = true,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace WorkFlow.Application.Contracts;
|
||||
|
||||
public interface IProfileService
|
||||
{
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts
|
||||
{
|
||||
public interface IStateService : ICRUDService<StateCreateDto, StateDto, State, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Repository for retrieving <see cref="PObject"/> entities from the database.
|
||||
/// </summary>
|
||||
public interface IProfileObjRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the list of <see cref="PObject"/> associated with a given user ID and profile ID by calling a database function.
|
||||
/// </summary>
|
||||
/// <param name="userId">The unique identifier of the user whose profile is to be retrieved.</param>
|
||||
/// <param name="profileId">The unique identifier of the profile whose object is to be retrieved.</param>
|
||||
/// <param name="cancel">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous operation. The task result contains the <see cref="PObject"/> object if found; otherwise, <c>null</c>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Logs an error if no profile is found, or if multiple profiles are returned, indicating potential data issues.
|
||||
/// </remarks>
|
||||
public Task<IEnumerable<PObject>> ReadAsync(int userId, int profileId, CancellationToken cancel = default);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Repository implementation for retrieving <see cref="Profile"/> entities from the database.
|
||||
/// </summary>
|
||||
public interface IProfileRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="Profile"/> associated with a given user ID by calling a database function.
|
||||
/// </summary>
|
||||
/// <param name="userId">The unique identifier of the user whose profile is to be retrieved.</param>
|
||||
/// <param name="cancel">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous operation. The task result contains the <see cref="Profile"/> object if found; otherwise, <c>null</c>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Logs an error if no profile is found, or if multiple profiles are returned, indicating potential data issues.
|
||||
/// </remarks>
|
||||
Task<Profile?> ReadAsync(int userId, CancellationToken cancel = default);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.Services;
|
||||
using WorkFlow.Infrastructure;
|
||||
|
||||
namespace WorkFlow.Application
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddWorkFlowServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddAutoMapper(typeof(MappingProfile).Assembly);
|
||||
services.TryAddScoped<IConfigService, ConfigService>();
|
||||
services.TryAddScoped<IProfileControlsTFService, ProfileControlsTFService>();
|
||||
services.TryAddScoped<IProfileObjStateService, ProfileObjStateService>();
|
||||
services.TryAddScoped<IProfileService, ProfileService>();
|
||||
services.TryAddScoped<IStateService, StateService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddWorkFlow(this IServiceCollection services) => services.AddWorkFlowRepositories().AddWorkFlowServices();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WorkFlow.Application.DTO
|
||||
namespace WorkFlow.Application.Dto
|
||||
{
|
||||
public record BaseCreateDto
|
||||
{
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WorkFlow.Application.DTO
|
||||
namespace WorkFlow.Application.Dto
|
||||
{
|
||||
public record BaseUpdateDto : IUnique<int>
|
||||
public record BaseUpdateDto
|
||||
{
|
||||
public required int Id { get; init; }
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.Config
|
||||
{
|
||||
public record ConfigCreateDto(string Title, string String);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.Config
|
||||
{
|
||||
public record ConfigUpdateDto(string Title, string String) : BaseUpdateDto;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.Profile
|
||||
{
|
||||
public record ProfileCreateDto(string IntlName, int ExtId1, bool Active, byte TypeId) : BaseCreateDto;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.Profile
|
||||
{
|
||||
public record ProfileDto(int Id,
|
||||
string IntlName,
|
||||
int ExtId1,
|
||||
bool Active,
|
||||
byte TypeId,
|
||||
string AddedWho,
|
||||
DateTime AddedWhen,
|
||||
string? ChangedWho = null,
|
||||
DateTime? ChangedWhen = null);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.Profile
|
||||
{
|
||||
public record ProfileUpdateDto(string IntlName, int ExtId1, bool Active, byte TypeId) : BaseUpdateDto;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.ProfileControlsTF
|
||||
{
|
||||
public record ProfileControlsTFCreateDto(
|
||||
int ProfileId,
|
||||
int UserId,
|
||||
long ObjId,
|
||||
string ObjType,
|
||||
string AttrName,
|
||||
string CtrlType,
|
||||
string CtrlCaption,
|
||||
bool Mandatory,
|
||||
bool ReadOnly,
|
||||
string? ChoiceList = null) : BaseCreateDto;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
|
||||
namespace WorkFlow.Application.DTO.ProfileControlsTF
|
||||
{
|
||||
public record ProfileControlsTFDto(int Id,
|
||||
int ProfileId,
|
||||
int UserId,
|
||||
long ObjId,
|
||||
string ObjType,
|
||||
string AttrName,
|
||||
string CtrlType,
|
||||
string CtrlCaption,
|
||||
bool Mandatory,
|
||||
bool ReadOnly,
|
||||
string AddedWho,
|
||||
DateTime AddedWhen,
|
||||
string? ChoiceList = null,
|
||||
ProfileDto? Profile = null,
|
||||
UserReadDto? User = null);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace WorkFlow.Application.DTO.ProfileControlsTF
|
||||
{
|
||||
/// <summary>
|
||||
/// This Data Transfer Object (DTO) serves as a placeholder and does not support updates.
|
||||
/// </summary>
|
||||
public record ProfileControlsTFUpdateDto(int Id) : IUnique<int>;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.ProfileObjState
|
||||
{
|
||||
public record ProfileObjStateCreateDto(
|
||||
int ProfileId,
|
||||
int UserId,
|
||||
long ObjId,
|
||||
int StateId,
|
||||
string? State2 = null,
|
||||
string? State3 = null,
|
||||
string? State4 = null) : BaseCreateDto;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
|
||||
namespace WorkFlow.Application.DTO.ProfileObjState
|
||||
{
|
||||
public record ProfileObjStateDto(int Id,
|
||||
int ProfileId,
|
||||
int UserId,
|
||||
long ObjId,
|
||||
int StateId,
|
||||
string AddedWho,
|
||||
DateTime AddedWhen,
|
||||
string? State2 = null,
|
||||
string? State3 = null,
|
||||
string? State4 = null,
|
||||
ProfileDto? Profile = null,
|
||||
UserReadDto? User = null,
|
||||
StateDto? State = null);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace WorkFlow.Application.DTO.ProfileObjState
|
||||
{
|
||||
/// <summary>
|
||||
/// This Data Transfer Object (DTO) serves as a placeholder and does not support updates.
|
||||
/// </summary>
|
||||
public record ProfileObjStateUpdateDto(int Id) : IUnique<int>;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.State
|
||||
{
|
||||
public record StateCreateDto(string IntlState) : BaseCreateDto;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace WorkFlow.Application.DTO.State
|
||||
{
|
||||
public record StateDto(int Id, string IntlState, string AddedWho, DateTime AddedWhen);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace WorkFlow.Application.DTO.State
|
||||
{
|
||||
/// <summary>
|
||||
/// This Data Transfer Object (DTO) serves as a placeholder and does not support updates.
|
||||
/// </summary>
|
||||
public record StateUpdateDto(int Id) : IUnique<int>;
|
||||
}
|
||||
52
src/WorkFlow.Application/DependencyInjection.cs
Normal file
52
src/WorkFlow.Application/DependencyInjection.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WorkFlow.Application.Mapping;
|
||||
|
||||
namespace WorkFlow.Application;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceCollection AddWorkFlowServices(this IServiceCollection services, Action<WorkFlowServiceOptions>? options = null)
|
||||
{
|
||||
WorkFlowServiceOptions sOptions = new(services);
|
||||
options?.Invoke(sOptions);
|
||||
|
||||
services.AddAutoMapper(typeof(MappingProfile).Assembly);
|
||||
services.AddMediatR(cfg =>
|
||||
{
|
||||
cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly);
|
||||
cfg.LicenseKey = sOptions.MediatRLicense;
|
||||
});
|
||||
|
||||
if(!sOptions.IsMappingConfigured)
|
||||
services.Configure<MappingOptions>(_ => { });
|
||||
|
||||
services.AddTransient<TfFileUriResolver>();
|
||||
services.AddTransient<TfFileIconUriResolver>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public class WorkFlowServiceOptions
|
||||
{
|
||||
private readonly IServiceCollection _services;
|
||||
|
||||
internal bool IsMappingConfigured { get; private set; } = false;
|
||||
|
||||
public WorkFlowServiceOptions(IServiceCollection services) => _services = services;
|
||||
|
||||
private void EnsureSingleMappingConfiguration(Action action)
|
||||
{
|
||||
if (IsMappingConfigured)
|
||||
throw new InvalidOperationException("Mapping configuration has already been set.");
|
||||
action();
|
||||
IsMappingConfigured = true;
|
||||
}
|
||||
|
||||
public void ConfigMapping(IConfiguration config) => EnsureSingleMappingConfiguration(() => _services.Configure<MappingOptions>(config));
|
||||
|
||||
public void ConfigMapping(Action<MappingOptions> options) => EnsureSingleMappingConfiguration(() => _services.Configure(options));
|
||||
|
||||
public string? MediatRLicense { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace WorkFlow.Application.DTO.Config
|
||||
namespace WorkFlow.Application.Dto
|
||||
{
|
||||
public record ConfigDto(int Id,
|
||||
string Title,
|
||||
16
src/WorkFlow.Application/Dto/ObjectDto.cs
Normal file
16
src/WorkFlow.Application/Dto/ObjectDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public class ObjectDto
|
||||
{
|
||||
public IEnumerable<string> Headlines { get; set; } = Array.Empty<string>();
|
||||
|
||||
public IEnumerable<string> Sublines { get; set; } = Array.Empty<string>();
|
||||
|
||||
public string? CmdCheckIn { get; set; }
|
||||
|
||||
public ObjectStateDto? State { get; set; }
|
||||
|
||||
public IEnumerable<ObjectStateHistDto> StateHistories { get; set; } = Array.Empty<ObjectStateHistDto>();
|
||||
|
||||
public IEnumerable<PControlsUpdateDto>? ControlsUpdates { get; set; } = Array.Empty<PControlsUpdateDto>();
|
||||
}
|
||||
15
src/WorkFlow.Application/Dto/ObjectStateDto.cs
Normal file
15
src/WorkFlow.Application/Dto/ObjectStateDto.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public record ObjectStateDto
|
||||
{
|
||||
public virtual string? Intl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds state 2, 3 and 4 as a list of strings.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Others { get; set; } = Array.Empty<string>();
|
||||
|
||||
public virtual IEnumerable<PControlsTFDto>? TFControls { get; set; }
|
||||
|
||||
public virtual IEnumerable<TfFileDto>? TfFiles { get; set; }
|
||||
}
|
||||
15
src/WorkFlow.Application/Dto/ObjectStateHistDto.cs
Normal file
15
src/WorkFlow.Application/Dto/ObjectStateHistDto.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public record ObjectStateHistDto
|
||||
{
|
||||
public virtual string? Intl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds state 2, 3 and 4 as a list of strings.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Others { get; set; } = Array.Empty<string>();
|
||||
|
||||
public string? ChangedWho { get; set; }
|
||||
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
}
|
||||
24
src/WorkFlow.Application/Dto/PControlsTFDto.cs
Normal file
24
src/WorkFlow.Application/Dto/PControlsTFDto.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public record PControlsTFDto
|
||||
{
|
||||
public byte? DialogNo { get; set; }
|
||||
|
||||
public string? AttrName { get; set; }
|
||||
|
||||
public string? CtrlType { get; set; }
|
||||
|
||||
public string? Caption { get; set; }
|
||||
|
||||
public string? Text { get; set; }
|
||||
|
||||
public string? Icon { get; set; }
|
||||
|
||||
public bool? Mandatory { get; set; }
|
||||
|
||||
public string? ChoiceList { get; set; }
|
||||
|
||||
public bool? ReadOnly { get; set; }
|
||||
|
||||
public byte? Sequ { get; set; }
|
||||
}
|
||||
12
src/WorkFlow.Application/Dto/PControlsUpdateDto.cs
Normal file
12
src/WorkFlow.Application/Dto/PControlsUpdateDto.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public record PControlsUpdateDto
|
||||
{
|
||||
public string? AttrName { get; set; }
|
||||
|
||||
public string? AttrValue { get; set; }
|
||||
|
||||
public string? AddedWho { get; set; }
|
||||
|
||||
public DateTime? AddedWhen { get; set; }
|
||||
}
|
||||
22
src/WorkFlow.Application/Dto/ProfileDto.cs
Normal file
22
src/WorkFlow.Application/Dto/ProfileDto.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using WorkFlow.Application.Buttons;
|
||||
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public class ProfileDto
|
||||
{
|
||||
public byte? TypeId { get; init; }
|
||||
|
||||
public string? Caption { get; init; }
|
||||
|
||||
public string? Subtitle { get; init; }
|
||||
|
||||
public int? CountObj { get; init; }
|
||||
|
||||
public string? ForeColor { get; init; }
|
||||
|
||||
public string? BackColor { get; init; }
|
||||
|
||||
public IEnumerable<ObjectDto> Objects { get; init; } = Array.Empty<ObjectDto>();
|
||||
|
||||
public IEnumerable<ButtonDto>? Buttons { get; set; } = Array.Empty<ButtonDto>();
|
||||
}
|
||||
14
src/WorkFlow.Application/Dto/TfFileDto.cs
Normal file
14
src/WorkFlow.Application/Dto/TfFileDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace WorkFlow.Application.Dto;
|
||||
|
||||
public class TfFileDto
|
||||
{
|
||||
public string? Url { get; set; }
|
||||
|
||||
public string? Headline { get; set; }
|
||||
|
||||
public string? Subline { get; set; }
|
||||
|
||||
public string? Comment { get; set; }
|
||||
|
||||
public string? IconUrl { get; set; }
|
||||
}
|
||||
52
src/WorkFlow.Application/Mapping/MappingOptions.cs
Normal file
52
src/WorkFlow.Application/Mapping/MappingOptions.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
namespace WorkFlow.Application.Mapping;
|
||||
|
||||
public class MappingOptions
|
||||
{
|
||||
public UriBuilderOptions TfFileUri { get; set; } = new();
|
||||
|
||||
public UriBuilderOptions TfFileIconUri { get; set; } = new();
|
||||
|
||||
public class UriBuilderOptions
|
||||
{
|
||||
public string? Scheme { get; set; }
|
||||
|
||||
public string? Host { get; set; }
|
||||
|
||||
public int? Port { get; set; }
|
||||
|
||||
private string _path = "/";
|
||||
|
||||
public string Path
|
||||
{
|
||||
get => _path;
|
||||
set => _path = value.Trim('/');
|
||||
}
|
||||
|
||||
private string _query = string.Empty;
|
||||
|
||||
public string Query
|
||||
{
|
||||
get => _query;
|
||||
set => _query = value.TrimStart('?');
|
||||
}
|
||||
|
||||
public UriBuilder ToBuilder
|
||||
{
|
||||
get
|
||||
{
|
||||
var uriBuilder = new UriBuilder()
|
||||
{
|
||||
Scheme = Scheme ?? "http",
|
||||
Host = Host ?? "localhost",
|
||||
Path = Path,
|
||||
Query = Query,
|
||||
};
|
||||
|
||||
if (Port is int port)
|
||||
uriBuilder.Port = port;
|
||||
|
||||
return uriBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/WorkFlow.Application/Mapping/MappingProfile.cs
Normal file
37
src/WorkFlow.Application/Mapping/MappingProfile.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using WorkFlow.Application.Buttons;
|
||||
using WorkFlow.Application.Dto;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Mapping;
|
||||
|
||||
public class MappingProfile : AutoMapper.Profile
|
||||
{
|
||||
public MappingProfile()
|
||||
{
|
||||
CreateMap<Config, ConfigDto>();
|
||||
|
||||
CreateMap<Profile, ProfileDto>();
|
||||
|
||||
CreateMap<PControlsTF, PControlsTFDto>();
|
||||
|
||||
CreateMap<Button, ButtonDto>();
|
||||
|
||||
CreateMap<PObject, ObjectDto>()
|
||||
.ForMember(dest => dest.Headlines, opt => opt.MapFrom(src => new[] { src.Headline1, src.Headline2 }))
|
||||
.ForMember(dest => dest.Sublines, opt => opt.MapFrom(src => new[] { src.Subline1, src.Subline2 }));
|
||||
|
||||
CreateMap<PObjectState, ObjectStateDto>()
|
||||
.ForMember(dest => dest.Intl, opt => opt.MapFrom(src => src.State1 != null ? src.State1.IntlState : null))
|
||||
.ForMember(dest => dest.Others, opt => opt.MapFrom(src => new string?[] { src.State2, src.State3, src.State4 }));
|
||||
|
||||
CreateMap<PObjectStateHist, ObjectStateHistDto>()
|
||||
.ForMember(dest => dest.Intl, opt => opt.MapFrom(src => src.State1 != null ? src.State1.IntlState : null))
|
||||
.ForMember(dest => dest.Others, opt => opt.MapFrom(src => new string?[] { src.State2, src.State3, src.State4 }));
|
||||
|
||||
CreateMap<TfFile, TfFileDto>()
|
||||
.ForMember(dest => dest.Url, opt => opt.MapFrom<TfFileUriResolver>())
|
||||
.ForMember(dest => dest.IconUrl, opt => opt.MapFrom<TfFileIconUriResolver>());
|
||||
|
||||
CreateMap<PControlsUpdate, PControlsUpdateDto>();
|
||||
}
|
||||
}
|
||||
24
src/WorkFlow.Application/Mapping/TfFileIconUriResolver.cs
Normal file
24
src/WorkFlow.Application/Mapping/TfFileIconUriResolver.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Web;
|
||||
using WorkFlow.Application.Dto;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Mapping;
|
||||
|
||||
public class TfFileIconUriResolver : IValueResolver<TfFile, TfFileDto, string?>
|
||||
{
|
||||
private readonly Func<UriBuilder> _uriBuilderFactory;
|
||||
|
||||
public TfFileIconUriResolver(IOptions<MappingOptions> options) => _uriBuilderFactory = () => options.Value.TfFileIconUri.ToBuilder;
|
||||
|
||||
public string? Resolve(TfFile source, TfFileDto destination, string? destMember, ResolutionContext context)
|
||||
{
|
||||
if(string.IsNullOrEmpty(source.Icon))
|
||||
return null;
|
||||
|
||||
var builder = _uriBuilderFactory();
|
||||
builder.AppendPath(source.Icon);
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
23
src/WorkFlow.Application/Mapping/TfFileUriResolver.cs
Normal file
23
src/WorkFlow.Application/Mapping/TfFileUriResolver.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Options;
|
||||
using WorkFlow.Application.Dto;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Mapping;
|
||||
|
||||
public class TfFileUriResolver : IValueResolver<TfFile, TfFileDto, string?>
|
||||
{
|
||||
private readonly Func<UriBuilder> _uriBuilderFactory;
|
||||
|
||||
public TfFileUriResolver(IOptions<MappingOptions> options) => _uriBuilderFactory = () => options.Value.TfFileUri.ToBuilder;
|
||||
|
||||
public string? Resolve(TfFile source, TfFileDto destination, string? destMember, ResolutionContext context)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source.Path))
|
||||
return null;
|
||||
|
||||
var builder = _uriBuilderFactory();
|
||||
builder.AppendPath(source.Path);
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
14
src/WorkFlow.Application/Mapping/UriBuilderExtensions.cs
Normal file
14
src/WorkFlow.Application/Mapping/UriBuilderExtensions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Web;
|
||||
|
||||
namespace WorkFlow.Application.Mapping;
|
||||
|
||||
internal static class UriBuilderExtensions
|
||||
{
|
||||
public static void AppendPath(this UriBuilder uriBuilder, string path, bool encode = true)
|
||||
{
|
||||
if(encode)
|
||||
path = HttpUtility.UrlEncode(path);
|
||||
|
||||
uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/', '\\')}/{path.Trim('/', '\\')}";
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using AutoMapper;
|
||||
using WorkFlow.Application.DTO.Config;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||
using WorkFlow.Application.DTO.ProfileObjState;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application
|
||||
{
|
||||
public class MappingProfile : AutoMapper.Profile
|
||||
{
|
||||
public MappingProfile()
|
||||
{
|
||||
// Mapping entity to DTO
|
||||
CreateMap<Config, ConfigDto>();
|
||||
CreateMap<Domain.Entities.Profile, ProfileDto>();
|
||||
CreateMap<ProfileControlsTF, ProfileControlsTFDto>();
|
||||
CreateMap<ProfileObjState, ProfileObjStateDto>();
|
||||
CreateMap<State, StateDto>();
|
||||
|
||||
// Mapping create-DTO to entity
|
||||
CreateMap<ConfigCreateDto, Config>();
|
||||
CreateMap<ProfileCreateDto, Domain.Entities.Profile>();
|
||||
CreateMap<ProfileControlsTFCreateDto, ProfileControlsTF>();
|
||||
CreateMap<ProfileObjStateCreateDto, ProfileObjState>();
|
||||
CreateMap<StateCreateDto, State>();
|
||||
|
||||
// Mapping update-DTO to entity
|
||||
CreateMap<ConfigUpdateDto, Config>();
|
||||
CreateMap<ProfileUpdateDto, Domain.Entities.Profile>();
|
||||
CreateMap<ProfileControlsTFUpdateDto, ProfileControlsTF>();
|
||||
CreateMap<ProfileObjStateUpdateDto, ProfileObjState>();
|
||||
CreateMap<StateUpdateDto, State>();
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/WorkFlow.Application/Profiles/ReadProfileQuery.cs
Normal file
71
src/WorkFlow.Application/Profiles/ReadProfileQuery.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using MediatR;
|
||||
using WorkFlow.Application.Buttons;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Application.Dto;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Profiles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to read a user profile by their user ID.
|
||||
/// </summary>
|
||||
/// <param name="UserId">The ID of the user whose profile is being requested.</param>
|
||||
public record ReadProfileQuery(int UserId, bool IncludeObject = true) : IRequest<ProfileDto>;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="ReadProfileQuery"/> request by retrieving the user profile
|
||||
/// from the data store using the <see cref="IProfileRepository"/>.
|
||||
/// </summary>
|
||||
public class ReadProfileHandler : IRequestHandler<ReadProfileQuery, ProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
|
||||
private readonly IProfileObjRepository _objRepository;
|
||||
|
||||
private readonly IRepository<Button> _bttnRepository;
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReadProfileHandler"/> class.
|
||||
/// </summary>
|
||||
/// <param name="profileRepository">The profile repository used to access profile data.</param>
|
||||
/// <param name="objRepository">The profile object repository used to access object data.</param>
|
||||
public ReadProfileHandler(IProfileRepository profileRepository, IProfileObjRepository objRepository, IRepository<Button> buttonRepository, IMapper mapper)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_objRepository = objRepository;
|
||||
_bttnRepository = buttonRepository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="ReadProfileQuery"/> request by retrieving the profile
|
||||
/// corresponding to the specified user ID.
|
||||
/// </summary>
|
||||
/// <param name="request">The request containing the user ID.</param>
|
||||
/// <param name="cancel">A cancellation token for the operation.</param>
|
||||
/// <returns>The user profile if found; otherwise, <c>null</c>.</returns>
|
||||
public async Task<ProfileDto> Handle(ReadProfileQuery request, CancellationToken cancel = default)
|
||||
{
|
||||
var profile = await _profileRepository.ReadAsync(request.UserId, cancel)
|
||||
?? throw new NotFoundException();
|
||||
|
||||
if (request.IncludeObject && profile.Id is int profileId)
|
||||
profile.Objects = await _objRepository.ReadAsync(request.UserId, profileId, cancel);
|
||||
|
||||
if (profile.Id is int pId)
|
||||
profile.Buttons = await _bttnRepository.Read(b => b.ProfileId == pId).ToListAsync(cancel);
|
||||
|
||||
return _mapper.Map<ProfileDto>(profile);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReadProfileQueryExtensions
|
||||
{
|
||||
public static Task<ProfileDto> ReadProfileAsync(this IMediator mediator, int userId, bool includeObject = true)
|
||||
=> mediator.Send(new ReadProfileQuery(UserId: userId, IncludeObject: includeObject));
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.Application;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Config;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
public class ConfigService : CRUDService<IConfigRepository, ConfigCreateDto, ConfigDto, Config, int>,
|
||||
IConfigService, ICRUDService<ConfigCreateDto, ConfigDto, Config, int>
|
||||
{
|
||||
public ConfigService(IConfigRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services
|
||||
{
|
||||
public class ProfileControlsTFService : CRUDService<IProfileControlsTFRepository, ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTF, int>,
|
||||
IProfileControlsTFService, ICRUDService<ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTF, int>
|
||||
{
|
||||
public ProfileControlsTFService(IProfileControlsTFRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<ProfileControlsTFDto>>> ReadAsync(
|
||||
bool withProfile = true, bool withUser = false,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null, bool? profileActive = null)
|
||||
{
|
||||
var pctf_list = await _repository.ReadAsync(
|
||||
isReadonly: true,
|
||||
withProfile: withProfile, withUser: withUser,
|
||||
userId: userId, username: username,
|
||||
profileId: profileId, objId: objId, profileActive: profileActive);
|
||||
|
||||
var pctf_dto_list = _mapper.Map<IEnumerable<ProfileControlsTFDto>>(pctf_list);
|
||||
|
||||
return Result.Success(pctf_dto_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileObjState;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
public class ProfileObjStateService : CRUDService<IProfileObjStateRepository, ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjState, int>,
|
||||
IProfileObjStateService, ICRUDService<ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjState, int>
|
||||
{
|
||||
public ProfileObjStateService(IProfileObjStateRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<ProfileObjStateDto>>> ReadAsync(
|
||||
bool withProfile = true, bool withUser = true, bool withState = true,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null)
|
||||
{
|
||||
var pos_list = await _repository.ReadAsync(
|
||||
isReadonly: true,
|
||||
withProfile: withProfile, withUser: withUser, withState: withState,
|
||||
userId: userId, username: username,
|
||||
profileId: profileId, objId: objId);
|
||||
|
||||
var post_dto_list = _mapper.Map<IEnumerable<ProfileObjStateDto>>(pos_list);
|
||||
|
||||
return Result.Success(post_dto_list);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using WorkFlow.Application.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
public class ProfileService : IProfileService
|
||||
{
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.Application;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
public class StateService : CRUDService<IStateRepository, StateCreateDto, StateDto, State, int>,
|
||||
IStateService, ICRUDService<StateCreateDto, StateDto, State, int>
|
||||
{
|
||||
public StateService(IStateRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,16 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="3.2.0" />
|
||||
<PackageReference Include="UserManager.Application" Version="3.1.2" />
|
||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.0.0" />
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="3.3.4" />
|
||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.0.1" />
|
||||
<PackageReference Include="MediatR" Version="13.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.20" />
|
||||
<PackageReference Include="UserManager" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WorkFlow.Domain\WorkFlow.Domain.csproj" />
|
||||
<ProjectReference Include="..\WorkFlow.Infrastructure\WorkFlow.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
115
src/WorkFlow.Domain/Entities/Button.cs
Normal file
115
src/WorkFlow.Domain/Entities/Button.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_PROF_BUTTONS")]
|
||||
public class Button
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID", TypeName = "int")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("MWF_PROFILE_ID", TypeName = "int")]
|
||||
public required int ProfileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("DIALOG_NO", TypeName = "tinyint")]
|
||||
public byte? DialogNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("BTN_TYPE", TypeName = "nvarchar(20)")]
|
||||
public string? BtnType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("TEXT", TypeName = "nvarchar(500)")]
|
||||
public string? Text { get; set; }
|
||||
|
||||
[Column("ICON", TypeName = "nvarchar(100)")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("FORE_COLOR", TypeName = "nvarchar(100)")]
|
||||
public string? ForeColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("BACK_COLOR", TypeName = "nvarchar(100)")]
|
||||
public string? BackColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("COMMAND", TypeName = "nvarchar(max)")]
|
||||
public string? Command { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("DIALOG_COMMAND", TypeName = "nvarchar(max)")]
|
||||
public string? DialogCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("CONFIRMATION_TEXT", TypeName = "nvarchar(250)")]
|
||||
public string? ConfirmationText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHO", TypeName = "nvarchar(100)")]
|
||||
public string? AddedWho { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? AddedWhen { get; set; }
|
||||
|
||||
[Column("CHANGED_WHO", TypeName = "nvarchar(100)")]
|
||||
public string? ChangedWho { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities
|
||||
{
|
||||
[Table("TBMWF_CONFIG", Schema = "dbo")]
|
||||
public class Config : IUnique<int>
|
||||
public class Config
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID")]
|
||||
|
||||
94
src/WorkFlow.Domain/Entities/PControlsTF.cs
Normal file
94
src/WorkFlow.Domain/Entities/PControlsTF.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_PROF_CONTROLS_TF", Schema = "dbo")]
|
||||
public class PControlsTF
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("OBJ_STATE_ID", TypeName = "bigint")]
|
||||
public long ObjStateId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("DIALOG_NO", TypeName = "tinyint")]
|
||||
public byte? DialogNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ATTR_NAME", TypeName = "nvarchar(100)")]
|
||||
public string? AttrName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("CTRL_TYPE", TypeName = "nvarchar(10)")]
|
||||
public string? CtrlType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("CAPTION", TypeName = "nvarchar(100)")]
|
||||
public string? Caption { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("TEXT", TypeName = "nvarchar(500)")]
|
||||
public string? Text { get; set; }
|
||||
|
||||
[Column("ICON", TypeName = "nvarchar(100)")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("MANDATORY", TypeName = "bit")]
|
||||
public bool? Mandatory { get; set; }
|
||||
|
||||
[Column("CHOICE_LIST", TypeName = "nvarchar(max)")]
|
||||
public string? ChoiceList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("READ_ONLY", TypeName = "bit")]
|
||||
public bool? ReadOnly { get; set; }
|
||||
|
||||
[Column("SEQU", TypeName = "tinyint")]
|
||||
public byte? Sequ { get; set; }
|
||||
|
||||
[Column("ADDED_WHO", TypeName = "nvarchar(100)")]
|
||||
public required string AddedWho { get; set; }
|
||||
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
}
|
||||
69
src/WorkFlow.Domain/Entities/PControlsUpdate.cs
Normal file
69
src/WorkFlow.Domain/Entities/PControlsUpdate.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_PROFILE_CONTROLS_UPDATE")]
|
||||
public class PControlsUpdate
|
||||
{
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("MWF_PROFILE_ID", TypeName = "int")]
|
||||
public int ProfileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("USR_ID", TypeName = "int")]
|
||||
public int? UsrId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("OBJ_ID", TypeName = "bigint")]
|
||||
public long ObjId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ATTR_NAME", TypeName = "nvarchar(100)")]
|
||||
public string? AttrName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ATTR_VALUE", TypeName = "nvarchar(3000)")]
|
||||
public string? AttrValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHO", TypeName = "nvarchar(30)")]
|
||||
public string? AddedWho { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? AddedWhen { get; set; }
|
||||
}
|
||||
34
src/WorkFlow.Domain/Entities/PObject.cs
Normal file
34
src/WorkFlow.Domain/Entities/PObject.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
public class PObject
|
||||
{
|
||||
[Column("ObjStateID")]
|
||||
public long? ObjStateId { get; set; }
|
||||
|
||||
[Column("ObjectID")]
|
||||
public long? Id { get; set; }
|
||||
|
||||
[Column("Headline1")]
|
||||
public string? Headline1 { get; set; }
|
||||
|
||||
[Column("Headline2")]
|
||||
public string? Headline2 { get; set; }
|
||||
|
||||
[Column("Subline1")]
|
||||
public string? Subline1 { get; set; }
|
||||
|
||||
[Column("Subline2")]
|
||||
public string? Subline2 { get; set; }
|
||||
|
||||
[Column("CMD_CheckIn")]
|
||||
public string? CmdCheckIn { get; set; }
|
||||
|
||||
[ForeignKey("ObjStateId")]
|
||||
public virtual PObjectState? State { get; set; }
|
||||
|
||||
public virtual IEnumerable<PObjectStateHist>? StateHistories { get; set; }
|
||||
|
||||
public virtual IEnumerable<PControlsUpdate>? ControlsUpdates { get; set; }
|
||||
}
|
||||
88
src/WorkFlow.Domain/Entities/PObjectState.cs
Normal file
88
src/WorkFlow.Domain/Entities/PObjectState.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_PROFILE_OBJ_STATE", Schema = "dbo")]
|
||||
public class PObjectState
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("MWF_PROFILE_ID", TypeName = "int")]
|
||||
public int? ProfileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("USR_ID", TypeName = "int")]
|
||||
public int? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("OBJ_ID", TypeName = "bigint")]
|
||||
public long? ObjectId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("STATE_ID", TypeName = "int")]
|
||||
public int StateId { get; set; }
|
||||
|
||||
[Column("STATE2", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? State2 { get; set; }
|
||||
|
||||
[Column("STATE3", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? State3 { get; set; }
|
||||
|
||||
[Column("STATE4", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? State4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHO", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? AddedWho { get; set; } = "SYS";
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? AddedWhen { get; set; } = DateTime.Now;
|
||||
|
||||
[Column("CHANGED_WHO", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? ChangedWho { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[ForeignKey("StateId")]
|
||||
public virtual State? State1 { get; set; }
|
||||
|
||||
public virtual IEnumerable<PControlsTF>? TFControls { get; set; }
|
||||
|
||||
public virtual IEnumerable<TfFile>? TfFiles { get; set; }
|
||||
}
|
||||
65
src/WorkFlow.Domain/Entities/PObjectStateHist.cs
Normal file
65
src/WorkFlow.Domain/Entities/PObjectStateHist.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_PROFILE_OBJ_STATE_HISTORY", Schema = "dbo")]
|
||||
public class PObjectStateHist
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("MWF_PROFILE_ID", TypeName = "int")]
|
||||
public int? ProfileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("USR_ID", TypeName = "int")]
|
||||
public int? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("OBJ_ID", TypeName = "bigint")]
|
||||
public long? ObjectId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("STATE_ID", TypeName = "int")]
|
||||
public int StateId { get; set; }
|
||||
|
||||
[Column("STATE2", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? State2 { get; set; }
|
||||
|
||||
[Column("STATE3", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? State3 { get; set; }
|
||||
|
||||
[Column("STATE4", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? State4 { get; set; }
|
||||
|
||||
[Column("CHANGED_WHO", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string? ChangedWho { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[ForeignKey("StateId")]
|
||||
public virtual State? State1 { get; set; }
|
||||
}
|
||||
@@ -8,7 +8,7 @@ public class Profile
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Column("TYPE_ID")]
|
||||
public int? TypeId { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
|
||||
[Column("CAPTION")]
|
||||
public string? Caption { get; set; }
|
||||
@@ -24,4 +24,10 @@ public class Profile
|
||||
|
||||
[Column("BACK_COLOR")]
|
||||
public string? BackColor { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public IEnumerable<PObject>? Objects { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public IEnumerable<Button>? Buttons { get; set; }
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities
|
||||
{
|
||||
[Table("TBMWF_PROF_CONTROLS_TF", Schema = "dbo")]
|
||||
public class ProfileControlsTF : IUnique<int>
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID")]
|
||||
public int Id { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("MWF_PROFILE_ID")]
|
||||
public required int ProfileId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("USR_ID")]
|
||||
public required int UserId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("OBJ_ID")]
|
||||
public required long ObjId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("OBJ_TYPE", TypeName = "varchar(10)")]
|
||||
public required string ObjType { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ATTR_NAME", TypeName = "varchar(100)")]
|
||||
public required string AttrName { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("CTRL_TYPE", TypeName = "varchar(10)")]
|
||||
public required string CtrlType { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("CTRL_CAPTION", TypeName = "varchar(100)")]
|
||||
public required string CtrlCaption { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("MANDATORY")]
|
||||
public required bool Mandatory { get; init; }
|
||||
|
||||
[Column("CHOICE_LIST", TypeName = "nvarchar(max)")]
|
||||
public string? ChoiceList { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("READ_ONLY")]
|
||||
public required bool ReadOnly { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHO", TypeName = "varchar(100)")]
|
||||
public required string AddedWho { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public required DateTime AddedWhen { get; init; }
|
||||
|
||||
[ForeignKey("ProfileId")]
|
||||
public Profile? Profile { get; init; } = default;
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public User? User { get; set; } = default;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities
|
||||
{
|
||||
[Table("TBMWF_PROFILE_OBJ_STATE", Schema = "dbo")]
|
||||
public class ProfileObjState : IUnique<int>
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID")]
|
||||
public int Id { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("MWF_PROFILE_ID")]
|
||||
public required int ProfileId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("USR_ID")]
|
||||
public required int UserId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("OBJ_ID")]
|
||||
public required long ObjId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("STATE_ID")]
|
||||
public required int StateId { get; init; }
|
||||
|
||||
[Column("STATE2", TypeName = "nvarchar(3000)")]
|
||||
public string? State2 { get; init; }
|
||||
|
||||
[Column("STATE3", TypeName = "nvarchar(3000)")]
|
||||
public string? State3 { get; init; }
|
||||
|
||||
[Column("STATE4", TypeName = "nvarchar(3000)")]
|
||||
public string? State4 { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHO", TypeName = "varchar(30)")]
|
||||
public required string AddedWho { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public required DateTime AddedWhen { get; init; }
|
||||
|
||||
[ForeignKey("ProfileId")]
|
||||
public Profile? Profile { get; init; } = null;
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public User? User { get; init; } = null;
|
||||
|
||||
[ForeignKey("StateId")]
|
||||
public State? State { get; init; } = null;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,24 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_WF_STATE", Schema = "dbo")]
|
||||
public class State
|
||||
{
|
||||
[Table("TBMWF_WF_STATE", Schema = "dbo")]
|
||||
public class State : IUnique<int>
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID")]
|
||||
public int Id { get; init; }
|
||||
[Key]
|
||||
[Column("GUID")]
|
||||
public int Id { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("INTL_STATE", TypeName = "varchar(100)")]
|
||||
public required string IntlState { get; init; }
|
||||
[Required]
|
||||
[Column("INTL_STATE", TypeName = "varchar(100)")]
|
||||
public required string IntlState { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHO", TypeName = "varchar(30)")]
|
||||
public required string AddedWho { get; init; }
|
||||
[Required]
|
||||
[Column("ADDED_WHO", TypeName = "varchar(30)")]
|
||||
public required string AddedWho { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public required DateTime AddedWhen { get; init; }
|
||||
}
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public required DateTime AddedWhen { get; init; }
|
||||
}
|
||||
60
src/WorkFlow.Domain/Entities/TfFile.cs
Normal file
60
src/WorkFlow.Domain/Entities/TfFile.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
[Table("TBMWF_TF_FILES")]
|
||||
public class TfFile
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("OBJ_STATE_ID", TypeName = "bigint")]
|
||||
public long ObjStateId { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(512)]
|
||||
[Column("F_FAPTH", TypeName = "nvarchar(512)")]
|
||||
public string Path { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("HEADLINE", TypeName = "nvarchar(100)")]
|
||||
public string? Headline { get; set; }
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("SUBLINE", TypeName = "nvarchar(100)")]
|
||||
public string? Subline { get; set; }
|
||||
|
||||
[StringLength(250)]
|
||||
[Column("COMMENT", TypeName = "nvarchar(250)")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("ICON", TypeName = "nvarchar(100)")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHO", TypeName = "nvarchar(100)")]
|
||||
public string? AddedWho { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Although this field is marked as <c>nullable</c> in the database schema to allow
|
||||
/// for greater flexibility during database-level operations or migrations, it is
|
||||
/// treated as <c>required</c> and <c>not null</c> within the application logic.
|
||||
/// Validation should be enforced at the application level to ensure a value is provided.
|
||||
/// </summary>
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? AddedWhen { get; set; }
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="UserManager.Domain" Version="3.0.1" />
|
||||
<PackageReference Include="UserManager" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Contracts
|
||||
{
|
||||
public interface IConfigRepository : ICRUDRepository<Config, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Contracts
|
||||
{
|
||||
public interface IProfileControlsTFRepository : ICRUDRepository<ProfileControlsTF, int>
|
||||
{
|
||||
Task<IEnumerable<ProfileControlsTF>> ReadAsync(
|
||||
bool isReadonly = true,
|
||||
bool withProfile = true, bool withUser = false,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null, bool? profileActive = null);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Contracts
|
||||
{
|
||||
public interface IProfileObjStateRepository : ICRUDRepository<ProfileObjState, int>
|
||||
{
|
||||
Task<IEnumerable<ProfileObjState>> ReadAsync(
|
||||
bool isReadonly = true,
|
||||
bool withProfile = true, bool withUser = true, bool withState = true,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
public interface IProfileRepository
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Contracts
|
||||
{
|
||||
public interface IStateRepository : ICRUDRepository<State, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
using WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
namespace WorkFlow.Infrastructure
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddWorkFlowRepositories(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddScoped<IConfigRepository, ConfigRepository>();
|
||||
services.TryAddScoped<IProfileControlsTFRepository, ProfileControlsTFRepository>();
|
||||
services.TryAddScoped<IProfileObjStateRepository, ProfileObjStateRepository>();
|
||||
services.TryAddScoped<IProfileRepository, ProfileRepository>();
|
||||
services.TryAddScoped<IStateRepository, StateRepository>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/WorkFlow.Infrastructure/DependencyInjection.cs
Normal file
27
src/WorkFlow.Infrastructure/DependencyInjection.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure.AutoMapper;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
namespace WorkFlow.Infrastructure;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceCollection AddWorkFlowRepositories(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddScoped<IProfileRepository, ProfileRepository>();
|
||||
services.TryAddScoped<IProfileObjRepository, PObjectRepository>();
|
||||
|
||||
services.AddDbRepository<WFDBContext, Config>(c => c.Configs).UseAutoMapper();
|
||||
services.AddDbRepository<WFDBContext, PControlsTF>(c => c.ProfileControlsTFs).UseAutoMapper();
|
||||
services.AddDbRepository<WFDBContext, State>(c => c.States).UseAutoMapper();
|
||||
services.AddDbRepository<WFDBContext, Button>(c => c.Buttons).UseAutoMapper();
|
||||
services.AddDbRepository<WFDBContext, State>(c => c.States).UseAutoMapper();
|
||||
services.AddDbRepository<WFDBContext, PObjectState>(c => c.ProfileObjStates).UseAutoMapper();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories
|
||||
{
|
||||
//TODO: Make the db context type generic so that it can be used by other projects with different db contexts.
|
||||
public class ConfigRepository : CRUDRepository<Config, int, WFDBContext>, IConfigRepository, ICRUDRepository<Config, int>
|
||||
{
|
||||
public ConfigRepository(WFDBContext dbContext) : base(dbContext, dbContext.Configs)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Repository implementation for retrieving <see cref="PObject"/> entities from the database.
|
||||
/// </summary>
|
||||
public class PObjectRepository : IProfileObjRepository
|
||||
{
|
||||
private readonly WFDBContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PObjectRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">The database context used for accessing profile data.</param>
|
||||
public PObjectRepository(WFDBContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the list of <see cref="PObject"/> associated with a given user ID and profile ID by calling a database function.
|
||||
/// </summary>
|
||||
/// <param name="userId">The unique identifier of the user whose profile is to be retrieved.</param>
|
||||
/// <param name="profileId">The unique identifier of the profile whose object is to be retrieved.</param>
|
||||
/// <param name="cancel">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous operation. The task result contains the <see cref="PObject"/> object if found; otherwise, <c>null</c>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Logs an error if no profile is found, or if multiple profiles are returned, indicating potential data issues.
|
||||
/// </remarks>
|
||||
public async Task<IEnumerable<PObject>> ReadAsync(int userId, int profileId, CancellationToken cancel = default)
|
||||
=> await _context.Objects
|
||||
.FromSqlRaw("SELECT * FROM [FNMWF_GET_PROFILE_OBJECTS] ({0}, {1})", userId, profileId)
|
||||
.Include(obj => obj.State).ThenInclude(objState => objState != null ? objState.State1 : null)
|
||||
.Include(obj => obj.State).ThenInclude(objState => objState != null ? objState.TFControls : null)
|
||||
.Include(obj => obj.State).ThenInclude(objState => objState != null ? objState.TfFiles : null)
|
||||
.Include(obj => obj.StateHistories!).ThenInclude(hist => hist != null ? hist.State1 : null)
|
||||
.Include(obj => obj.ControlsUpdates)
|
||||
.ToListAsync(cancel);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories
|
||||
{
|
||||
public class ProfileControlsTFRepository : CRUDRepository<ProfileControlsTF, int, WFDBContext>, IProfileControlsTFRepository, ICRUDRepository<ProfileControlsTF, int>
|
||||
{
|
||||
public ProfileControlsTFRepository(WFDBContext dbContext) : base(dbContext, dbContext.ProfileControlsTFs)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IQueryable<ProfileControlsTF> ReadOnly() => base.ReadOnly().Include(pctf => pctf.Profile).Include(pctf => pctf.User);
|
||||
|
||||
protected IQueryable<ProfileControlsTF> Read(bool isReadonly = false, bool withProfile = true, bool withUser = true, int? profileId = null, int? userId = null, string? username = null, int? objId = null)
|
||||
{
|
||||
var query = isReadonly ? _dbSet.AsNoTracking() : _dbSet.AsQueryable();
|
||||
|
||||
if (withProfile)
|
||||
query = query.Include(pctf => pctf.Profile);
|
||||
|
||||
if (withUser)
|
||||
query = query.Include(pctf => pctf.User);
|
||||
|
||||
if (profileId is not null)
|
||||
query = query.Where(pctf => pctf.ProfileId == profileId);
|
||||
|
||||
if (userId is not null)
|
||||
query = query.Where(pctf => pctf.UserId == userId);
|
||||
|
||||
if (username is null)
|
||||
query = query.Where(pctf => pctf.User!.Username == username);
|
||||
|
||||
if (objId is not null)
|
||||
query = query.Where(pctf => pctf.ObjId == objId);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProfileControlsTF>> ReadAsync(
|
||||
bool isReadonly = true,
|
||||
bool withProfile = true, bool withUser = true,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null, bool? profileActive = null)
|
||||
=> await Read(
|
||||
isReadonly: isReadonly,
|
||||
withProfile: withProfile, withUser: withUser,
|
||||
userId: userId, username: username,
|
||||
profileId: profileId, objId: objId)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
public class ProfileObjStateRepository : CRUDRepository<ProfileObjState, int, WFDBContext>, IProfileObjStateRepository, ICRUDRepository<ProfileObjState, int>
|
||||
{
|
||||
public ProfileObjStateRepository(WFDBContext dbContext) : base(dbContext, dbContext.ProfileObjStates)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IQueryable<ProfileObjState> ReadOnly() => base.ReadOnly().Include(pos => pos.Profile).Include(pos => pos.State);
|
||||
|
||||
protected IQueryable<ProfileObjState> Read(bool isReadonly = false, bool withProfile = true, bool withUser = true, bool withState = true, int? profileId = null, int? userId = null, string? username = null, int? stateId = null, int? objId = null)
|
||||
{
|
||||
var query = isReadonly ? _dbSet.AsNoTracking() : _dbSet.AsQueryable();
|
||||
|
||||
if (withProfile)
|
||||
query = query.Include(pctf => pctf.Profile);
|
||||
|
||||
if (withUser)
|
||||
query = query.Include(pctf => pctf.User);
|
||||
|
||||
if (withState)
|
||||
query = query.Include(pctf => pctf.State);
|
||||
|
||||
if (profileId is not null)
|
||||
query = query.Where(pctf => pctf.ProfileId == profileId);
|
||||
|
||||
if (userId is not null)
|
||||
query = query.Where(pctf => pctf.UserId == userId);
|
||||
|
||||
if (username is null)
|
||||
query = query.Where(pctf => pctf.User!.Username == username);
|
||||
|
||||
if (stateId is null)
|
||||
query = query.Where(pctf => pctf.State!.Id == stateId);
|
||||
|
||||
if (objId is not null)
|
||||
query = query.Where(pctf => pctf.ObjId == objId);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProfileObjState>> ReadAsync(
|
||||
bool isReadonly = true,
|
||||
bool withProfile = true, bool withUser = true, bool withState = true,
|
||||
int? userId = null, string? username = null,
|
||||
int? profileId = null, int? objId = null)
|
||||
=> await Read(
|
||||
isReadonly: isReadonly,
|
||||
withProfile: withProfile, withUser: withUser, withState: withState,
|
||||
userId: userId, username: username,
|
||||
profileId: profileId, objId: objId)
|
||||
.ToListAsync();
|
||||
}
|
||||
@@ -1,7 +1,55 @@
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Repository implementation for retrieving <see cref="Profile"/> entities from the database.
|
||||
/// </summary>
|
||||
public class ProfileRepository : IProfileRepository
|
||||
{
|
||||
private readonly ILogger<ProfileRepository> _logger;
|
||||
private readonly WFDBContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">The database context used for accessing profile data.</param>
|
||||
/// <param name="logger">The logger instance used for logging repository operations.</param>
|
||||
public ProfileRepository(WFDBContext context, ILogger<ProfileRepository> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="Profile"/> associated with a given user ID by calling a database function.
|
||||
/// </summary>
|
||||
/// <param name="userId">The unique identifier of the user whose profile is to be retrieved.</param>
|
||||
/// <param name="cancel">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous operation. The task result contains the <see cref="Profile"/> object if found; otherwise, <c>null</c>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Logs an error if no profile is found, or if multiple profiles are returned, indicating potential data issues.
|
||||
/// </remarks>
|
||||
public async Task<Profile?> ReadAsync(int userId, CancellationToken cancel = default)
|
||||
{
|
||||
var profiles = await _context.Profiles
|
||||
.FromSqlRaw("SELECT * FROM FNMWF_GET_PROFILES ({0})", userId)
|
||||
.ToListAsync(cancel);
|
||||
|
||||
if (profiles == null || profiles.Count == 0)
|
||||
{
|
||||
_logger.LogError("No profile record was found associated with user ID {userId}.", userId);
|
||||
}
|
||||
else if (profiles.Count > 1)
|
||||
{
|
||||
_logger.LogError("Multiple profile records were found for user ID {userId}, which may indicate a data integrity issue.", userId);
|
||||
}
|
||||
|
||||
return profiles?.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
public class StateRepository : CRUDRepository<State, int, WFDBContext>, IStateRepository, ICRUDRepository<State, int>
|
||||
{
|
||||
public StateRepository(WFDBContext dbContext) : base(dbContext, dbContext.States)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using DigitalData.UserManager.Infrastructure;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure;
|
||||
@@ -10,11 +11,13 @@ public class WFDBContext : DbContext, IUserManagerDbContext
|
||||
{
|
||||
public DbSet<Config> Configs { get; set; }
|
||||
|
||||
public DbSet<ProfileControlsTF> ProfileControlsTFs { get; set; }
|
||||
public DbSet<PControlsTF> ProfileControlsTFs { get; set; }
|
||||
|
||||
public DbSet<Profile> Profiles { get; set; }
|
||||
|
||||
public DbSet<PObject> Objects { get; set; }
|
||||
|
||||
public DbSet<ProfileObjState> ProfileObjStates { get; set; }
|
||||
public DbSet<PObjectState> ProfileObjStates { get; set; }
|
||||
|
||||
public DbSet<State> States { get; set; }
|
||||
|
||||
@@ -32,15 +35,38 @@ public class WFDBContext : DbContext, IUserManagerDbContext
|
||||
|
||||
public DbSet<ClientUser> ClientUsers { get; set; }
|
||||
|
||||
public DbSet<Button> Buttons { get; set; }
|
||||
|
||||
public WFDBContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
//configure model builder for user manager tables
|
||||
modelBuilder.ConfigureUserManager();
|
||||
|
||||
modelBuilder.Entity<PObjectState>()
|
||||
.HasMany(objState => objState.TFControls)
|
||||
.WithOne()
|
||||
.HasForeignKey(control => control.ObjStateId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<PObjectState>()
|
||||
.HasMany(objState => objState.TfFiles)
|
||||
.WithOne()
|
||||
.HasForeignKey(file => file.ObjStateId);
|
||||
|
||||
modelBuilder.Entity<PObject>()
|
||||
.HasMany(p => p.StateHistories)
|
||||
.WithOne()
|
||||
.HasForeignKey(hist => hist.ObjectId);
|
||||
|
||||
modelBuilder.Entity<PObject>()
|
||||
.HasMany(obj => obj.ControlsUpdates)
|
||||
.WithOne()
|
||||
.HasForeignKey(cu => cu.ObjId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,15 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.0.0" />
|
||||
<PackageReference Include="UserManager.Infrastructure" Version="3.0.1" />
|
||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.0.0" />
|
||||
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.1.1" />
|
||||
<PackageReference Include="DigitalData.Core.Infrastructure.AutoMapper" Version="1.0.3" />
|
||||
<PackageReference Include="UserManager" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WorkFlow.Domain\WorkFlow.Domain.csproj" />
|
||||
<ProjectReference Include="..\WorkFlow.Application\WorkFlow.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user