Compare commits
33 Commits
41151593fd
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3832351dd1 | ||
|
|
99237cbecc | ||
|
|
cb2edffe91 | ||
|
|
4d3768248e | ||
|
|
fb38bc1fd4 | ||
|
|
10b557374d | ||
|
|
f266e6728f | ||
|
|
3373fceef3 | ||
|
|
f7eaa0f7de | ||
|
|
d5b1ee41a0 | ||
|
|
c3f5d90b6a | ||
|
|
753eb18b71 | ||
|
|
17d8373739 | ||
|
|
d6ccc10244 | ||
|
|
3dccf82710 | ||
|
|
c7d8b67ccb | ||
|
|
b76043fa24 | ||
|
|
e28f4560d6 | ||
|
|
97d5156bbb | ||
|
|
40cf8f3f10 | ||
|
|
a325d07c6b | ||
|
|
69abd3afa2 | ||
|
|
cbdd6ee295 | ||
|
|
2c1abaaf32 | ||
|
|
8038ff74dd | ||
|
|
edcf3781b7 | ||
|
|
6ea053be36 | ||
|
|
67a62d7311 | ||
|
|
e17875dad7 | ||
|
|
b460de4e37 | ||
|
|
1ca336abe0 | ||
|
|
6e4a575864 | ||
|
|
d664adf000 |
14
WorkFlow.API/Attributes/ApiKeyAuthAttribute.cs
Normal file
14
WorkFlow.API/Attributes/ApiKeyAuthAttribute.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Filters;
|
||||||
|
|
||||||
|
namespace WorkFlow.API.Attributes
|
||||||
|
{
|
||||||
|
//TODO: move APIKeyAuthAttribute to Core.API
|
||||||
|
public class APIKeyAuthAttribute : ServiceFilterAttribute
|
||||||
|
{
|
||||||
|
public APIKeyAuthAttribute()
|
||||||
|
: base(typeof(APIKeyAuthFilter))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using DigitalData.UserManager.Application.Contracts;
|
|
||||||
using DigitalData.UserManager.Application.DTOs.User;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using DigitalData.UserManager.Application;
|
|
||||||
using DigitalData.Core.Abstractions.Application;
|
|
||||||
using Microsoft.Extensions.Localization;
|
|
||||||
using DigitalData.Core.DTO;
|
|
||||||
using WorkFlow.API.Models;
|
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class AuthController(IUserService userService, IGroupOfUserService gouService, IDirectorySearchService directorySearchService, IStringLocalizer<Resource> localizer, ILogger<AuthController> logger) : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly IUserService _userService = userService;
|
|
||||||
private readonly IGroupOfUserService _gouService = gouService;
|
|
||||||
private readonly IDirectorySearchService _dirSearchService = directorySearchService;
|
|
||||||
private readonly IStringLocalizer<Resource> _localizer = localizer;
|
|
||||||
private readonly ILogger<AuthController> _logger = logger;
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpGet("check")]
|
|
||||||
public IActionResult CheckAuthentication()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Ok(User.Identity?.IsAuthenticated ?? false);
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "{Message}", ex.Message);
|
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost("login")]
|
|
||||||
public async Task<IActionResult> Login([FromBody] Login login)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var username = string.Empty;
|
|
||||||
DataResult<UserReadDto>? uRes = null;
|
|
||||||
|
|
||||||
if(login.Username is not null && login.UserId is not null)
|
|
||||||
return BadRequest("Invalid request: either 'UserId' or 'Username' must be provided, but not both.");
|
|
||||||
else if(login.Username is not null)
|
|
||||||
username = login.Username;
|
|
||||||
else if(login.UserId is int userId)
|
|
||||||
{
|
|
||||||
uRes = await _userService.ReadByIdAsync(userId);
|
|
||||||
if (!uRes.IsSuccess || uRes.Data is null)
|
|
||||||
{
|
|
||||||
return Unauthorized(uRes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return BadRequest("Invalid request: either 'UserId' or 'Username' must be provided, but not both.");
|
|
||||||
|
|
||||||
bool isValid = _dirSearchService.ValidateCredentials(username, login.Password);
|
|
||||||
|
|
||||||
if (!isValid)
|
|
||||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
|
||||||
|
|
||||||
var gouMsg = await _gouService.HasGroup(username, "PM_USER", caseSensitive: false);
|
|
||||||
if (!gouMsg.IsSuccess)
|
|
||||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UnauthorizedUser]));
|
|
||||||
|
|
||||||
//find the user
|
|
||||||
uRes ??= await _userService.ReadByUsernameAsync(username);
|
|
||||||
if (!uRes.IsSuccess || uRes.Data is null)
|
|
||||||
{
|
|
||||||
_logger.LogNotice(uRes.Notices);
|
|
||||||
return Unauthorized();
|
|
||||||
}
|
|
||||||
|
|
||||||
UserReadDto user = uRes.Data;
|
|
||||||
|
|
||||||
// Create claimsIdentity
|
|
||||||
var claimsIdentity = new ClaimsIdentity(user.ToClaimList(), CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
|
|
||||||
// Create authProperties
|
|
||||||
var authProperties = new AuthenticationProperties
|
|
||||||
{
|
|
||||||
IsPersistent = true,
|
|
||||||
AllowRefresh = true,
|
|
||||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(60)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sign in
|
|
||||||
await HttpContext.SignInAsync(
|
|
||||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
|
||||||
new ClaimsPrincipal(claimsIdentity),
|
|
||||||
authProperties);
|
|
||||||
|
|
||||||
_dirSearchService.SetSearchRootCache(user.Username, login.Password);
|
|
||||||
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "{Message}", ex.Message);
|
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize]
|
|
||||||
[HttpGet("user")]
|
|
||||||
public async Task<IActionResult> GetUserWithClaims()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Extract the username from the Name claim.
|
|
||||||
string? username = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(username))
|
|
||||||
return Unauthorized();
|
|
||||||
|
|
||||||
return await _userService.ReadByUsernameAsync(username)
|
|
||||||
.ThenAsync(Ok, IActionResult (m, n) =>
|
|
||||||
{
|
|
||||||
_logger.LogNotice(n);
|
|
||||||
return NotFound(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "{Message}", ex.Message);
|
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize]
|
|
||||||
[HttpPost("logout")]
|
|
||||||
public async Task<IActionResult> Logout()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "{Message}", ex.Message);
|
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,20 @@
|
|||||||
using DigitalData.Core.API;
|
using DigitalData.Core.API;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
using WorkFlow.Application.Contracts;
|
using WorkFlow.Application.Contracts;
|
||||||
using WorkFlow.Application.DTO.Config;
|
using WorkFlow.Application.DTO.Config;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
namespace WorkFlow.API.Controllers;
|
||||||
|
|
||||||
|
[APIKeyAuth]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class ConfigController : CRUDControllerBaseWithErrorHandling<IConfigService, ConfigCreateDto, ConfigDto, ConfigUpdateDto, Config, int>
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
public ConfigController(ILogger<ConfigController> logger, IConfigService service) : base(logger, service)
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
public class ConfigController(ILogger<ConfigController> logger, IConfigService service) : CRUDControllerBaseWithErrorHandling<IConfigService, ConfigCreateDto, ConfigDto, ConfigUpdateDto, Config, int>(logger, service)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
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
|
public static class ControllerExtensions
|
||||||
{
|
{
|
||||||
public static bool TryGetUserId(this ControllerBase controller, out int? id)
|
public static bool TryGetUserId(this ControllerBase controller, out int? id)
|
||||||
|
|||||||
24
WorkFlow.API/Controllers/PlaceHolderAuthController.cs
Normal file
24
WorkFlow.API/Controllers/PlaceHolderAuthController.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using WorkFlow.API.Models;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
|
|
||||||
|
namespace WorkFlow.API.Controllers;
|
||||||
|
|
||||||
|
//TODO: implement up-to-date AuthController in UserManager
|
||||||
|
[APIKeyAuth]
|
||||||
|
[Route("api/Auth")]
|
||||||
|
[ApiController]
|
||||||
|
[Tags("Auth")]
|
||||||
|
public class PlaceholderAuthController : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult CreateTokenViaBody([FromBody] Login login)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("check")]
|
||||||
|
[Authorize]
|
||||||
|
public IActionResult Check() => Ok();
|
||||||
|
}
|
||||||
@@ -1,16 +1,20 @@
|
|||||||
using DigitalData.Core.API;
|
using DigitalData.Core.API;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
using WorkFlow.Application.Contracts;
|
using WorkFlow.Application.Contracts;
|
||||||
using WorkFlow.Application.DTO.Profile;
|
using WorkFlow.Application.DTO.Profile;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
namespace WorkFlow.API.Controllers;
|
||||||
|
|
||||||
|
[APIKeyAuth]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class ProfileController : CRUDControllerBaseWithErrorHandling<IProfileService, ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
public ProfileController(ILogger<ProfileController> logger, IProfileService service) : base(logger, service)
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
public class ProfileController(ILogger<ProfileController> logger, IProfileService service) : CRUDControllerBaseWithErrorHandling<IProfileService, ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>(logger, service)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,117 +2,125 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
using WorkFlow.Application.Contracts;
|
using WorkFlow.Application.Contracts;
|
||||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
namespace WorkFlow.API.Controllers;
|
||||||
|
|
||||||
|
[APIKeyAuth]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class ProfileControlsTFController : CRUDControllerBase<IProfileControlsTFService, ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTFUpdateDto, ProfileControlsTF, int>
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
private readonly ILogger<ProfileControlsTFController> logger;
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
public ProfileControlsTFController(ILogger<ProfileControlsTFController> logger, IProfileControlsTFService service) : base(logger, service)
|
||||||
public class ProfileControlsTFController(ILogger<ProfileControlsTFController> logger, IProfileControlsTFService service) : CRUDControllerBase<IProfileControlsTFService, ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTFUpdateDto, ProfileControlsTF, int>(logger, service)
|
|
||||||
{
|
{
|
||||||
[NonAction]
|
this.logger = logger;
|
||||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
}
|
||||||
|
|
||||||
[NonAction]
|
[NonAction]
|
||||||
public override Task<IActionResult> Update(ProfileControlsTFUpdateDto updateDto) => base.Update(updateDto);
|
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||||
|
|
||||||
[HttpGet]
|
[NonAction]
|
||||||
public async Task<IActionResult> GetAsync(
|
public override Task<IActionResult> Update(ProfileControlsTFUpdateDto updateDto) => base.Update(updateDto);
|
||||||
bool withProfile = true, bool withUser = false,
|
|
||||||
int? profileId = null, int? objId = null, bool? profileActive = null)
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAsync(
|
||||||
|
bool withProfile = true, bool withUser = false,
|
||||||
|
int? profileId = null, int? objId = null, bool? profileActive = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
if (!this.TryGetUserId(out int? 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.");
|
||||||
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)
|
else if (id is null)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
return StatusCode(StatusCodes.Status500InternalServerError, "Invalid user ID.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
return await _service.ReadAsync(
|
||||||
public override async Task<IActionResult> Create([FromBody] ProfileControlsTFCreateDto createDto)
|
withProfile: withProfile, withUser: withUser,
|
||||||
{
|
userId: id,
|
||||||
try
|
profileId: profileId, objId: objId, profileActive: profileActive)
|
||||||
{
|
.ThenAsync(
|
||||||
if (!this.TryGetUserId(out int? id))
|
Success: pctf => pctf.Any() ? Ok(pctf) : NotFound(),
|
||||||
{
|
|
||||||
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) =>
|
Fail: IActionResult (msg, ntc) =>
|
||||||
{
|
{
|
||||||
_logger.LogNotice(ntc);
|
logger.LogNotice(ntc);
|
||||||
return ntc.HasFlag(Flag.NotFound) ? NotFound() : StatusCode(StatusCodes.Status500InternalServerError);
|
return NotFound();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
logger.LogError("Authorization failed: User ID claim not found.");
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,17 +2,26 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
using WorkFlow.Application.Contracts;
|
using WorkFlow.Application.Contracts;
|
||||||
using WorkFlow.Application.DTO.ProfileObjState;
|
using WorkFlow.Application.DTO.ProfileObjState;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
namespace WorkFlow.API.Controllers
|
||||||
{
|
{
|
||||||
|
[APIKeyAuth]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class ProfileObjStateController(ILogger<ProfileObjStateController> logger, IProfileObjStateService service) : CRUDControllerBaseWithErrorHandling<IProfileObjStateService, ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjStateUpdateDto, ProfileObjState, int>(logger, service)
|
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]
|
[NonAction]
|
||||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
using DigitalData.Core.API;
|
using DigitalData.Core.API;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
using WorkFlow.Application.Contracts;
|
using WorkFlow.Application.Contracts;
|
||||||
using WorkFlow.Application.DTO.State;
|
using WorkFlow.Application.DTO.State;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
namespace WorkFlow.API.Controllers;
|
||||||
|
|
||||||
|
[APIKeyAuth]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class StateController : CRUDControllerBaseWithErrorHandling<IStateService, StateCreateDto, StateDto, StateUpdateDto, State, int>
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
public StateController(ILogger<StateController> logger, IStateService service) : base(logger, service)
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
public class StateController(ILogger<StateController> logger, IStateService service) : CRUDControllerBaseWithErrorHandling<IStateService, StateCreateDto, StateDto, StateUpdateDto, State, int>(logger, service)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,43 +2,53 @@
|
|||||||
using DigitalData.UserManager.Application.Contracts;
|
using DigitalData.UserManager.Application.Contracts;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorkFlow.API.Attributes;
|
||||||
|
|
||||||
namespace WorkFlow.API.Controllers
|
namespace WorkFlow.API.Controllers;
|
||||||
|
|
||||||
|
[APIKeyAuth]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class UserController : ControllerBase
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
private readonly ILogger<UserController> logger;
|
||||||
[ApiController]
|
private readonly IUserService userService;
|
||||||
[Authorize]
|
|
||||||
public class UserController(ILogger<UserController> logger, IUserService userService) : ControllerBase
|
public UserController(ILogger<UserController> logger, IUserService userService)
|
||||||
{
|
{
|
||||||
[HttpGet]
|
this.logger = logger;
|
||||||
public async Task<IActionResult> GetAsync()
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
if (!this.TryGetUserId(out int? 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.");
|
||||||
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)
|
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(ex, "An unexpected error occurred while processing the request: {Message}", ex.Message);
|
logger.LogError("Invalid user ID: Retrieved ID is null or not an integer.");
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError, "An internal server error occurred.");
|
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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
22
WorkFlow.API/Extensions/DIExtensions.cs
Normal file
22
WorkFlow.API/Extensions/DIExtensions.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using WorkFlow.API.Filters;
|
||||||
|
using WorkFlow.API.Models;
|
||||||
|
|
||||||
|
namespace WorkFlow.API.Extensions
|
||||||
|
{
|
||||||
|
public static class DIExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddAPIKeyAuth(this IServiceCollection services, Func<string?, bool> isValidKey, string headerName = "X-API-Key")
|
||||||
|
=> services.AddSingleton<APIKeyAuthFilter>(provider => new(isValidKey: isValidKey, headerName: headerName));
|
||||||
|
|
||||||
|
public static IServiceCollection AddAPIKeyAuth(this IServiceCollection services, APIKeyAuthOptions options, bool configureOptions = true)
|
||||||
|
{
|
||||||
|
if(configureOptions)
|
||||||
|
services.TryAddSingleton(Options.Create(options));
|
||||||
|
|
||||||
|
return services.AddAPIKeyAuth(isValidKey: key => options.Key is null || options.Key == key, headerName: options.HeaderName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
WorkFlow.API/Filters/APIKeyAuthHeaderOpFilter.cs
Normal file
42
WorkFlow.API/Filters/APIKeyAuthHeaderOpFilter.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.OpenApi.Any;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using WorkFlow.API.Models;
|
||||||
|
|
||||||
|
namespace WorkFlow.API.Filters;
|
||||||
|
|
||||||
|
public class APIKeyAuthHeaderOpFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
private readonly APIKeyAuthOptions apiKeyAuthOptions;
|
||||||
|
private readonly IWebHostEnvironment environment;
|
||||||
|
|
||||||
|
public APIKeyAuthHeaderOpFilter(IOptions<APIKeyAuthOptions> options, IWebHostEnvironment environment)
|
||||||
|
{
|
||||||
|
this.environment = environment;
|
||||||
|
apiKeyAuthOptions = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
var param = new OpenApiParameter
|
||||||
|
{
|
||||||
|
Name = apiKeyAuthOptions.HeaderName,
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Required = true,
|
||||||
|
AllowEmptyValue = false,
|
||||||
|
Schema = new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = "string"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(environment.IsDevelopment())
|
||||||
|
param.Schema.Default = new OpenApiString(apiKeyAuthOptions.Key);
|
||||||
|
|
||||||
|
if (apiKeyAuthOptions.SwaggerDescription is not null)
|
||||||
|
param.Description = apiKeyAuthOptions.SwaggerDescription;
|
||||||
|
|
||||||
|
operation.Parameters.Add(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
WorkFlow.API/Filters/ApiKeyAuthFilter.cs
Normal file
22
WorkFlow.API/Filters/ApiKeyAuthFilter.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace WorkFlow.API.Filters;
|
||||||
|
|
||||||
|
public class APIKeyAuthFilter : IAuthorizationFilter
|
||||||
|
{
|
||||||
|
private readonly Func<string?, bool> isValidKey;
|
||||||
|
private readonly string headerName;
|
||||||
|
|
||||||
|
public APIKeyAuthFilter(Func<string?, bool> isValidKey, string headerName = "X-API-Key")
|
||||||
|
{
|
||||||
|
this.isValidKey = isValidKey;
|
||||||
|
this.headerName = headerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAuthorization(AuthorizationFilterContext context)
|
||||||
|
{
|
||||||
|
if (!isValidKey(context.HttpContext.Request.Headers[headerName]))
|
||||||
|
context.Result = new UnauthorizedResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
10
WorkFlow.API/Jenkinsfile
vendored
Normal file
10
WorkFlow.API/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
stages {
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
sh 'dotnet build'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
WorkFlow.API/LazyServiceProvider.cs
Normal file
18
WorkFlow.API/LazyServiceProvider.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace WorkFlow.API;
|
||||||
|
|
||||||
|
public class LazyServiceProvider : IServiceProvider
|
||||||
|
{
|
||||||
|
private Lazy<IServiceProvider>? _serviceProvider;
|
||||||
|
|
||||||
|
public Func<IServiceProvider> Factory
|
||||||
|
{
|
||||||
|
set => _serviceProvider = new(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? GetService(Type serviceType)
|
||||||
|
{
|
||||||
|
if (_serviceProvider is null)
|
||||||
|
throw new InvalidOperationException("GetService cannot be called before _serviceProvider is set.");
|
||||||
|
return _serviceProvider.Value.GetService(serviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
WorkFlow.API/Models/APIKeyAuthOptions.cs
Normal file
11
WorkFlow.API/Models/APIKeyAuthOptions.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace WorkFlow.API.Models
|
||||||
|
{
|
||||||
|
public class APIKeyAuthOptions
|
||||||
|
{
|
||||||
|
public string? Key { get; init; } = null;
|
||||||
|
|
||||||
|
public string HeaderName { get; init; } = "X-API-Key";
|
||||||
|
|
||||||
|
public string? SwaggerDescription { get; init; } = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
WorkFlow.API/Models/AuthTokenKeys.cs
Normal file
12
WorkFlow.API/Models/AuthTokenKeys.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace WorkFlow.API.Models;
|
||||||
|
|
||||||
|
public class AuthTokenKeys
|
||||||
|
{
|
||||||
|
public string Cookie { get; init; } = "AuthToken";
|
||||||
|
|
||||||
|
public string QueryString { get; init; } = "AuthToken";
|
||||||
|
|
||||||
|
public string Issuer { get; init; } = "auth.digitaldata.works";
|
||||||
|
|
||||||
|
public string Audience { get; init; } = "work-flow.digitaldata.works";
|
||||||
|
}
|
||||||
@@ -5,13 +5,14 @@ namespace WorkFlow.API.Models
|
|||||||
{
|
{
|
||||||
public static class ModelExtensions
|
public static class ModelExtensions
|
||||||
{
|
{
|
||||||
public static List<Claim> ToClaimList(this UserReadDto user) => [
|
public static List<Claim> ToClaimList(this UserReadDto user) => new()
|
||||||
|
{
|
||||||
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
|
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||||
new (ClaimTypes.Name, user.Username),
|
new (ClaimTypes.Name, user.Username),
|
||||||
new (ClaimTypes.Surname, user.Name ?? ""),
|
new (ClaimTypes.Surname, user.Name ?? ""),
|
||||||
new (ClaimTypes.GivenName, user.Prename ?? ""),
|
new (ClaimTypes.GivenName, user.Prename ?? ""),
|
||||||
new (ClaimTypes.Email, user.Email ?? "")
|
new (ClaimTypes.Email, user.Email ?? "")
|
||||||
];
|
};
|
||||||
|
|
||||||
public static Dictionary<string, object> ToClaimDictionary(this UserReadDto user) => user.ToClaimList().ToDictionary(claim => claim.Type, claim => (object) claim.Value);
|
public static Dictionary<string, object> ToClaimDictionary(this UserReadDto user) => user.ToClaimList().ToDictionary(claim => claim.Type, claim => (object) claim.Value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,64 +2,160 @@ using WorkFlow.Application;
|
|||||||
using DigitalData.UserManager.Application;
|
using DigitalData.UserManager.Application;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using WorkFlow.Infrastructure;
|
using WorkFlow.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
||||||
using DigitalData.Core.API;
|
using DigitalData.Core.API;
|
||||||
using DigitalData.Core.Application;
|
using DigitalData.Core.Application;
|
||||||
using DigitalData.UserManager.Application.DTOs.User;
|
using DigitalData.UserManager.Application.DTOs.User;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using WorkFlow.API.Models;
|
using WorkFlow.API.Models;
|
||||||
using System.Security.Claims;
|
using NLog;
|
||||||
|
using NLog.Web;
|
||||||
|
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;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||||
var config = builder.Configuration;
|
logger.Info("Logging initialized.");
|
||||||
|
|
||||||
// Add services to the container.
|
try
|
||||||
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();
|
|
||||||
builder.ConfigureBySection<DirectorySearchOptions>();
|
|
||||||
builder.Services.AddDirectorySearchService();
|
|
||||||
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
|
||||||
{
|
{
|
||||||
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
});
|
var config = builder.Configuration;
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
// Add NLogger
|
||||||
|
builder.Logging.ClearProviders();
|
||||||
|
builder.Host.UseNLog();
|
||||||
|
|
||||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
// Add services to the container
|
||||||
.AddCookie(options =>
|
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();
|
||||||
|
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
|
||||||
|
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
||||||
{
|
{
|
||||||
options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security
|
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
|
||||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only
|
|
||||||
options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites
|
|
||||||
options.LoginPath = "/api/auth/login";
|
|
||||||
options.LogoutPath = "/api/auth/logout";
|
|
||||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(60); // timeout.
|
|
||||||
options.SlidingExpiration = true; //refreshes the expiration time on each request.
|
|
||||||
options.Cookie.Name = "AuthSession";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
bool disableAPIKeyAuth = config.GetValue<bool>("DisableAPIKeyAuth") && builder.IsDevOrDiP();
|
||||||
builder.Services.AddSwaggerGen();
|
if (disableAPIKeyAuth)
|
||||||
|
builder.Services.AddAPIKeyAuth(new APIKeyAuthOptions());
|
||||||
|
else
|
||||||
|
if (config.GetSection("APIKeyAuth").Get<APIKeyAuthOptions>() is APIKeyAuthOptions options)
|
||||||
|
builder.Services.AddAPIKeyAuth(options);
|
||||||
|
else
|
||||||
|
throw new("The API Key Authorization configuration is not available in the app settings, even though the app is not in development or DiP mode and API Key Authorization is not disabled.");
|
||||||
|
|
||||||
var app = builder.Build();
|
var lazyProvider = new LazyServiceProvider();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams"));
|
||||||
if (app.IsDevOrDiP() && app.Configuration.GetValue<bool>("EnableSwagger"))
|
|
||||||
{
|
builder.Services.AddControllers();
|
||||||
app.UseSwagger();
|
|
||||||
app.UseSwaggerUI();
|
var authTokenKeys = config.GetSection(nameof(AuthTokenKeys)).Get<AuthTokenKeys>() ?? new();
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddJwtBearer(opt =>
|
||||||
|
{
|
||||||
|
opt.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
|
||||||
|
{
|
||||||
|
var clientParams = lazyProvider.GetRequiredService<IOptions<ClientParams>>()?.Value;
|
||||||
|
var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience);
|
||||||
|
return new List<SecurityKey>() { publicKey.SecurityKey };
|
||||||
|
},
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidIssuer = authTokenKeys.Issuer,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidAudience = authTokenKeys.Audience,
|
||||||
|
};
|
||||||
|
|
||||||
|
opt.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnMessageReceived = context =>
|
||||||
|
{
|
||||||
|
// if there is no token read related cookie or query string
|
||||||
|
if (context.Token is null) // if there is no token
|
||||||
|
{
|
||||||
|
if (context.Request.Cookies.TryGetValue(authTokenKeys.Cookie, out var cookieToken) && cookieToken is not null)
|
||||||
|
context.Token = cookieToken;
|
||||||
|
else if (context.Request.Query.TryGetValue(authTokenKeys.QueryString, out var queryStrToken))
|
||||||
|
context.Token = queryStrToken;
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(setupAct =>
|
||||||
|
{
|
||||||
|
setupAct.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Scheme = "Bearer"
|
||||||
|
});
|
||||||
|
|
||||||
|
setupAct.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Bearer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Array.Empty<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!disableAPIKeyAuth)
|
||||||
|
setupAct.OperationFilter<APIKeyAuthHeaderOpFilter>();
|
||||||
|
|
||||||
|
if (config.GetSection("OpenApiInfo").Get<OpenApiInfo>() is OpenApiInfo openApiInfo)
|
||||||
|
setupAct.SwaggerDoc(openApiInfo?.Version ?? "v1", openApiInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
lazyProvider.Factory = () => app.Services;
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.IsDevOrDiP() && app.Configuration.GetValue<bool>("EnableSwagger"))
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseCookieBasedLocalizer("de-DE");
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "Stopped program because of exception.");
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
app.UseCookieBasedLocalizer("de-DE");
|
|
||||||
|
|
||||||
app.MapControllers();
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
|
-->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<WebPublishMethod>Package</WebPublishMethod>
|
||||||
|
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||||
|
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||||
|
<SiteUrlToLaunchAfterPublish />
|
||||||
|
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||||
|
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||||
|
<ProjectGuid>4fb33592-ef0d-47c3-9cde-03b2ef12be00</ProjectGuid>
|
||||||
|
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\workFLOW\API\net7\$(Version)\workFLOW.API.zip</DesktopBuildPackageLocation>
|
||||||
|
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||||
|
<DeployIisAppPath>WorkFlow.API</DeployIisAppPath>
|
||||||
|
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
|
-->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<WebPublishMethod>Package</WebPublishMethod>
|
||||||
|
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||||
|
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||||
|
<SiteUrlToLaunchAfterPublish />
|
||||||
|
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||||
|
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||||
|
<ProjectGuid>4fb33592-ef0d-47c3-9cde-03b2ef12be00</ProjectGuid>
|
||||||
|
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\workFLOW\API\net8\$(Version)\workFLOW.API.zip</DesktopBuildPackageLocation>
|
||||||
|
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||||
|
<DeployIisAppPath>WorkFlow.API</DeployIisAppPath>
|
||||||
|
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"http": {
|
"http": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": false,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "http://localhost:5130",
|
"applicationUrl": "http://localhost:5130",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"https": {
|
"https": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": false,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "https://localhost:7120;http://localhost:5130",
|
"applicationUrl": "https://localhost:7120;http://localhost:5130",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
"launchBrowser": true,
|
"launchBrowser": false,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
|||||||
8
WorkFlow.API/WFKey.cs
Normal file
8
WorkFlow.API/WFKey.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace WorkFlow.API
|
||||||
|
{
|
||||||
|
public static class WFKey
|
||||||
|
{
|
||||||
|
public static readonly string WrongPassword = nameof(WrongPassword);
|
||||||
|
public static readonly string UserNotFoundOrWrongPassword = nameof(UserNotFoundOrWrongPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,30 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<PackageId>WorkFlow.API</PackageId>
|
||||||
|
<Version>1.1.0</Version>
|
||||||
|
<Company>Digital Data GmbH</Company>
|
||||||
|
<Product>WorkFlow.API</Product>
|
||||||
|
<Title>WorkFlow.API</Title>
|
||||||
|
<AssemblyVersion>1.1.0</AssemblyVersion>
|
||||||
|
<FileVersion>1.1.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DigitalData.Core.API" Version="2.0.0" />
|
<_WebToolingArtifacts Remove="Properties\PublishProfiles\IISProfile - Copy.pubxml" />
|
||||||
|
<_WebToolingArtifacts Remove="Properties\PublishProfiles\IISProfileNet7.pubxml" />
|
||||||
|
<_WebToolingArtifacts Remove="Properties\PublishProfiles\IISProfileNet8.pubxml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.3" />
|
||||||
|
<PackageReference Include="DigitalData.Core.API" Version="2.1.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="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,56 @@
|
|||||||
{
|
{
|
||||||
"DiPMode": true,
|
"DiPMode": true,
|
||||||
"EnableSwagger": true,
|
"EnableSwagger": true,
|
||||||
|
"DisableAPIKeyAuth": false,
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"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": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||||
@@ -19,5 +63,29 @@
|
|||||||
"User": "(&(objectClass=user)(sAMAccountName=*))",
|
"User": "(&(objectClass=user)(sAMAccountName=*))",
|
||||||
"Group": "(&(objectClass=group) (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": {
|
||||||
|
"Email": "info-flow@digitaldata.works",
|
||||||
|
"Name": "Digital Data GmbH",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using WorkFlow.Domain.Entities;
|
|||||||
|
|
||||||
namespace WorkFlow.Application.Contracts
|
namespace WorkFlow.Application.Contracts
|
||||||
{
|
{
|
||||||
public interface IConfigService : ICRUDService<ConfigCreateDto, ConfigDto, ConfigUpdateDto, Config, int>
|
public interface IConfigService : ICRUDService<ConfigCreateDto, ConfigDto, Config, int>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ using WorkFlow.Domain.Entities;
|
|||||||
|
|
||||||
namespace WorkFlow.Application.Contracts
|
namespace WorkFlow.Application.Contracts
|
||||||
{
|
{
|
||||||
public interface IProfileControlsTFService : ICRUDService<ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTFUpdateDto, ProfileControlsTF, int>
|
public interface IProfileControlsTFService : ICRUDService<ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTF, int>
|
||||||
{
|
{
|
||||||
Task<DataResult<IEnumerable<ProfileControlsTFDto>>> ReadAsync(
|
Task<DataResult<IEnumerable<ProfileControlsTFDto>>> ReadAsync(
|
||||||
bool withProfile = true, bool withUser = false,
|
bool withProfile = true, bool withUser = false,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using WorkFlow.Domain.Entities;
|
|||||||
|
|
||||||
namespace WorkFlow.Application.Contracts
|
namespace WorkFlow.Application.Contracts
|
||||||
{
|
{
|
||||||
public interface IProfileObjStateService : ICRUDService<ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjStateUpdateDto, ProfileObjState, int>
|
public interface IProfileObjStateService : ICRUDService<ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjState, int>
|
||||||
{
|
{
|
||||||
Task<DataResult<IEnumerable<ProfileObjStateDto>>> ReadAsync(
|
Task<DataResult<IEnumerable<ProfileObjStateDto>>> ReadAsync(
|
||||||
bool withProfile = true, bool withUser = true, bool withState = true,
|
bool withProfile = true, bool withUser = true, bool withState = true,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using WorkFlow.Domain.Entities;
|
|||||||
|
|
||||||
namespace WorkFlow.Application.Contracts
|
namespace WorkFlow.Application.Contracts
|
||||||
{
|
{
|
||||||
public interface IProfileService : ICRUDService<ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>
|
public interface IProfileService : ICRUDService<ProfileCreateDto, ProfileDto, Profile, int>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using WorkFlow.Domain.Entities;
|
|||||||
|
|
||||||
namespace WorkFlow.Application.Contracts
|
namespace WorkFlow.Application.Contracts
|
||||||
{
|
{
|
||||||
public interface IStateService : ICRUDService<StateCreateDto, StateDto, StateUpdateDto, State, int>
|
public interface IStateService : ICRUDService<StateCreateDto, StateDto, State, int>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,12 @@ using WorkFlow.Application.DTO.Config;
|
|||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
|
|
||||||
namespace WorkFlow.Application.Services
|
namespace WorkFlow.Application.Services;
|
||||||
|
|
||||||
|
public class ConfigService : CRUDService<IConfigRepository, ConfigCreateDto, ConfigDto, Config, int>,
|
||||||
|
IConfigService, ICRUDService<ConfigCreateDto, ConfigDto, Config, int>
|
||||||
{
|
{
|
||||||
public class ConfigService(IConfigRepository repository, IMapper mapper)
|
public ConfigService(IConfigRepository repository, IMapper mapper) : base(repository, mapper)
|
||||||
: CRUDService<IConfigRepository, ConfigCreateDto, ConfigDto, ConfigUpdateDto, Config, int>(repository, mapper),
|
|
||||||
IConfigService, ICRUDService<ConfigCreateDto, ConfigDto, ConfigUpdateDto, Config, int>
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,10 +9,13 @@ using WorkFlow.Infrastructure.Contracts;
|
|||||||
|
|
||||||
namespace WorkFlow.Application.Services
|
namespace WorkFlow.Application.Services
|
||||||
{
|
{
|
||||||
public class ProfileControlsTFService(IProfileControlsTFRepository repository, IMapper mapper)
|
public class ProfileControlsTFService : CRUDService<IProfileControlsTFRepository, ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTF, int>,
|
||||||
: CRUDService<IProfileControlsTFRepository, ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTFUpdateDto, ProfileControlsTF, int>(repository, mapper),
|
IProfileControlsTFService, ICRUDService<ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTF, int>
|
||||||
IProfileControlsTFService, ICRUDService<ProfileControlsTFCreateDto, ProfileControlsTFDto, ProfileControlsTFUpdateDto, ProfileControlsTF, int>
|
|
||||||
{
|
{
|
||||||
|
public ProfileControlsTFService(IProfileControlsTFRepository repository, IMapper mapper) : base(repository, mapper)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<DataResult<IEnumerable<ProfileControlsTFDto>>> ReadAsync(
|
public async Task<DataResult<IEnumerable<ProfileControlsTFDto>>> ReadAsync(
|
||||||
bool withProfile = true, bool withUser = false,
|
bool withProfile = true, bool withUser = false,
|
||||||
int? userId = null, string? username = null,
|
int? userId = null, string? username = null,
|
||||||
|
|||||||
@@ -7,26 +7,28 @@ using WorkFlow.Application.DTO.ProfileObjState;
|
|||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
|
|
||||||
namespace WorkFlow.Application.Services
|
namespace WorkFlow.Application.Services;
|
||||||
|
|
||||||
|
public class ProfileObjStateService : CRUDService<IProfileObjStateRepository, ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjState, int>,
|
||||||
|
IProfileObjStateService, ICRUDService<ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjState, int>
|
||||||
{
|
{
|
||||||
public class ProfileObjStateService(IProfileObjStateRepository repository, IMapper mapper)
|
public ProfileObjStateService(IProfileObjStateRepository repository, IMapper mapper) : base(repository, mapper)
|
||||||
: CRUDService<IProfileObjStateRepository, ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjStateUpdateDto, ProfileObjState, int>(repository, mapper),
|
|
||||||
IProfileObjStateService, ICRUDService<ProfileObjStateCreateDto, ProfileObjStateDto, ProfileObjStateUpdateDto, ProfileObjState, int>
|
|
||||||
{
|
{
|
||||||
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, bool? profileActive = null)
|
|
||||||
{
|
|
||||||
var pos_list = await _repository.ReadAsync(
|
|
||||||
isReadonly: true,
|
|
||||||
withProfile: withProfile, withUser: withUser, withState: withState,
|
|
||||||
userId: userId, username: username,
|
|
||||||
profileId: profileId, objId: objId, profileActive: profileActive);
|
|
||||||
|
|
||||||
var post_dto_list = _mapper.Map<IEnumerable<ProfileObjStateDto>>(pos_list);
|
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, bool? profileActive = null)
|
||||||
|
{
|
||||||
|
var pos_list = await _repository.ReadAsync(
|
||||||
|
isReadonly: true,
|
||||||
|
withProfile: withProfile, withUser: withUser, withState: withState,
|
||||||
|
userId: userId, username: username,
|
||||||
|
profileId: profileId, objId: objId, profileActive: profileActive);
|
||||||
|
|
||||||
return Result.Success(post_dto_list);
|
var post_dto_list = _mapper.Map<IEnumerable<ProfileObjStateDto>>(pos_list);
|
||||||
}
|
|
||||||
|
return Result.Success(post_dto_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,12 @@ using WorkFlow.Application.DTO.Profile;
|
|||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
|
|
||||||
namespace WorkFlow.Application.Services
|
namespace WorkFlow.Application.Services;
|
||||||
|
|
||||||
|
public class ProfileService : CRUDService<IProfileRepository, ProfileCreateDto, ProfileDto, Profile, int>,
|
||||||
|
IProfileService, ICRUDService<ProfileCreateDto, ProfileDto, Profile, int>
|
||||||
{
|
{
|
||||||
public class ProfileService(IProfileRepository repository, AutoMapper.IMapper mapper)
|
public ProfileService(IProfileRepository repository, AutoMapper.IMapper mapper) : base(repository, mapper)
|
||||||
: CRUDService<IProfileRepository, ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>(repository, mapper),
|
|
||||||
IProfileService, ICRUDService<ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,12 @@ using WorkFlow.Application.DTO.State;
|
|||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
|
|
||||||
namespace WorkFlow.Application.Services
|
namespace WorkFlow.Application.Services;
|
||||||
|
|
||||||
|
public class StateService : CRUDService<IStateRepository, StateCreateDto, StateDto, State, int>,
|
||||||
|
IStateService, ICRUDService<StateCreateDto, StateDto, State, int>
|
||||||
{
|
{
|
||||||
public class StateService(IStateRepository repository, IMapper mapper)
|
public StateService(IStateRepository repository, IMapper mapper) : base(repository, mapper)
|
||||||
: CRUDService<IStateRepository, StateCreateDto, StateDto, StateUpdateDto, State, int>(repository, mapper),
|
|
||||||
IStateService, ICRUDService<StateCreateDto, StateDto, StateUpdateDto, State, int>
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="2.0.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="3.2.0" />
|
||||||
<PackageReference Include="UserManager.Application" Version="2.0.0" />
|
<PackageReference Include="UserManager.Application" Version="3.1.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="UserManager.Domain" Version="2.0.0" />
|
<PackageReference Include="UserManager.Domain" Version="3.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ using WorkFlow.Infrastructure.Contracts;
|
|||||||
namespace WorkFlow.Infrastructure.Repositories
|
namespace WorkFlow.Infrastructure.Repositories
|
||||||
{
|
{
|
||||||
//TODO: Make the db context type generic so that it can be used by other projects with different db contexts.
|
//TODO: Make the db context type generic so that it can be used by other projects with different db contexts.
|
||||||
public class ConfigRepository(WFDBContext dbContext) : CRUDRepository<Config, int, WFDBContext>(dbContext, dbContext.Configs), IConfigRepository, ICRUDRepository<Config, int>
|
public class ConfigRepository : CRUDRepository<Config, int, WFDBContext>, IConfigRepository, ICRUDRepository<Config, int>
|
||||||
{
|
{
|
||||||
|
public ConfigRepository(WFDBContext dbContext) : base(dbContext, dbContext.Configs)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,12 @@ using WorkFlow.Infrastructure.Contracts;
|
|||||||
|
|
||||||
namespace WorkFlow.Infrastructure.Repositories
|
namespace WorkFlow.Infrastructure.Repositories
|
||||||
{
|
{
|
||||||
public class ProfileControlsTFRepository(WFDBContext dbContext) : CRUDRepository<ProfileControlsTF, int, WFDBContext>(dbContext, dbContext.ProfileControlsTFs), IProfileControlsTFRepository, ICRUDRepository<ProfileControlsTF, int>
|
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 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, bool? profileActive = null)
|
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, bool? profileActive = null)
|
||||||
|
|||||||
@@ -4,56 +4,59 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
|
|
||||||
namespace WorkFlow.Infrastructure.Repositories
|
namespace WorkFlow.Infrastructure.Repositories;
|
||||||
|
|
||||||
|
public class ProfileObjStateRepository : CRUDRepository<ProfileObjState, int, WFDBContext>, IProfileObjStateRepository, ICRUDRepository<ProfileObjState, int>
|
||||||
{
|
{
|
||||||
public class ProfileObjStateRepository(WFDBContext dbContext) : CRUDRepository<ProfileObjState, int, WFDBContext>(dbContext, dbContext.ProfileObjStates), 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, bool? profileActive = 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);
|
|
||||||
|
|
||||||
if (profileActive is not null)
|
|
||||||
query = query.Where(pctf => pctf.Profile!.Active == profileActive);
|
|
||||||
|
|
||||||
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, bool? profileActive = null)
|
|
||||||
=> await Read(
|
|
||||||
isReadonly: isReadonly,
|
|
||||||
withProfile: withProfile, withUser: withUser, withState: withState,
|
|
||||||
userId: userId, username: username,
|
|
||||||
profileId: profileId, objId: objId, profileActive: profileActive)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, bool? profileActive = 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);
|
||||||
|
|
||||||
|
if (profileActive is not null)
|
||||||
|
query = query.Where(pctf => pctf.Profile!.Active == profileActive);
|
||||||
|
|
||||||
|
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, bool? profileActive = null)
|
||||||
|
=> await Read(
|
||||||
|
isReadonly: isReadonly,
|
||||||
|
withProfile: withProfile, withUser: withUser, withState: withState,
|
||||||
|
userId: userId, username: username,
|
||||||
|
profileId: profileId, objId: objId, profileActive: profileActive)
|
||||||
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,11 @@ using DigitalData.Core.Infrastructure;
|
|||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
|
|
||||||
namespace WorkFlow.Infrastructure.Repositories
|
namespace WorkFlow.Infrastructure.Repositories;
|
||||||
|
|
||||||
|
public class ProfileRepository : CRUDRepository<Profile, int, WFDBContext>, IProfileRepository, ICRUDRepository<Profile, int>
|
||||||
{
|
{
|
||||||
public class ProfileRepository(WFDBContext dbContext) : CRUDRepository<Profile, int, WFDBContext>(dbContext, dbContext.Profiles), IProfileRepository, ICRUDRepository<Profile, int>
|
public ProfileRepository(WFDBContext dbContext) : base(dbContext, dbContext.Profiles)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,12 @@
|
|||||||
using DigitalData.Core.Infrastructure;
|
using DigitalData.Core.Infrastructure;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
using WorkFlow.Infrastructure.Contracts;
|
using WorkFlow.Infrastructure.Contracts;
|
||||||
namespace WorkFlow.Infrastructure.Repositories
|
|
||||||
|
namespace WorkFlow.Infrastructure.Repositories;
|
||||||
|
|
||||||
|
public class StateRepository : CRUDRepository<State, int, WFDBContext>, IStateRepository, ICRUDRepository<State, int>
|
||||||
{
|
{
|
||||||
public class StateRepository(WFDBContext dbContext) : CRUDRepository<State, int, WFDBContext>(dbContext, dbContext.States), IStateRepository, ICRUDRepository<State, int>
|
public StateRepository(WFDBContext dbContext) : base(dbContext, dbContext.States)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,38 +4,43 @@ using DigitalData.UserManager.Infrastructure.Contracts;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using WorkFlow.Domain.Entities;
|
using WorkFlow.Domain.Entities;
|
||||||
|
|
||||||
namespace WorkFlow.Infrastructure
|
namespace WorkFlow.Infrastructure;
|
||||||
|
|
||||||
|
public class WFDBContext : DbContext, IUserManagerDbContext
|
||||||
{
|
{
|
||||||
public class WFDBContext(DbContextOptions options) : DbContext(options), IUserManagerDbContext
|
public DbSet<Config> Configs { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ProfileControlsTF> ProfileControlsTFs { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Profile> Profiles { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ProfileObjState> ProfileObjStates { get; set; }
|
||||||
|
|
||||||
|
public DbSet<State> States { get; set; }
|
||||||
|
|
||||||
|
public DbSet<GroupOfUser> GroupOfUsers { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Group> Groups { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ModuleOfUser> ModuleOfUsers { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Module> Modules { get; set; }
|
||||||
|
|
||||||
|
public DbSet<User> Users { get; set; }
|
||||||
|
|
||||||
|
public DbSet<UserRep> UserReps { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ClientUser> ClientUsers { get; set; }
|
||||||
|
|
||||||
|
public WFDBContext(DbContextOptions options) : base(options)
|
||||||
{
|
{
|
||||||
public DbSet<Config> Configs { get; set; }
|
}
|
||||||
|
|
||||||
public DbSet<ProfileControlsTF> ProfileControlsTFs { get; set; }
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
//configure model builder for user manager tables
|
||||||
|
modelBuilder.ConfigureUserManager();
|
||||||
|
|
||||||
public DbSet<Profile> Profiles { get; set; }
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
public DbSet<ProfileObjState> ProfileObjStates { get; set; }
|
|
||||||
|
|
||||||
public DbSet<State> States { get; set; }
|
|
||||||
|
|
||||||
public DbSet<GroupOfUser> GroupOfUsers { get; set; }
|
|
||||||
|
|
||||||
public DbSet<Group> Groups { get; set; }
|
|
||||||
|
|
||||||
public DbSet<ModuleOfUser> ModuleOfUsers { get; set; }
|
|
||||||
|
|
||||||
public DbSet<Module> Modules { get; set; }
|
|
||||||
|
|
||||||
public DbSet<User> Users { get; set; }
|
|
||||||
|
|
||||||
public DbSet<UserRep> UserReps { get; set; }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
//configure model builder for user manager tables
|
|
||||||
modelBuilder.ConfigureUserManager();
|
|
||||||
|
|
||||||
base.OnModelCreating(modelBuilder);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.0.0" />
|
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.0.0" />
|
||||||
<PackageReference Include="UserManager.Infrastructure" Version="2.0.0" />
|
<PackageReference Include="UserManager.Infrastructure" Version="3.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user