Compare commits
32 Commits
master
...
168a4b0791
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 537891b8c5 | |||
| f8be2d9f26 | |||
| 547d723f47 | |||
| 1fcdcf6c0a | |||
| a5bffdf1ce |
@@ -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.Profile;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ProfileController : CRUDControllerBaseWithErrorHandling<IProfileService, ProfileCreateDto, ProfileDto, ProfileUpdateDto, Profile, int>
|
||||
{
|
||||
public ProfileController(ILogger<ProfileController> logger, IProfileService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,91 +0,0 @@
|
||||
{
|
||||
"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": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,15 +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, bool? profileActive = null);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts
|
||||
{
|
||||
public interface IProfileService : ICRUDService<ProfileCreateDto, ProfileDto, Profile, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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,16 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.Application;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
public class ProfileService : CRUDService<IProfileRepository, ProfileCreateDto, ProfileDto, Profile, int>,
|
||||
IProfileService, ICRUDService<ProfileCreateDto, ProfileDto, Profile, int>
|
||||
{
|
||||
public ProfileService(IProfileRepository repository, AutoMapper.IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities
|
||||
{
|
||||
[Table("TBMWF_PROFILE", Schema = "dbo")]
|
||||
public class Profile : IUnique<int>
|
||||
{
|
||||
[Key]
|
||||
[Column("GUID")]
|
||||
public int Id { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("INTL_NAME", TypeName = "varchar(200)")]
|
||||
public required string IntlName { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("EXT_ID1")]
|
||||
public required int ExtId1 { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("ACTIVE")]
|
||||
public required bool Active { 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; }
|
||||
|
||||
[Column("CHANGED_WHO", TypeName = "varchar(30)")]
|
||||
public string? ChangedWho { get; init; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("TYPE_ID")]
|
||||
public required byte TypeId { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -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, bool? profileActive = null);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Contracts
|
||||
{
|
||||
public interface IProfileRepository : ICRUDRepository<Profile, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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, 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 (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);
|
||||
|
||||
if (profileActive is not null)
|
||||
query = query.Where(pctf => pctf.Profile!.Active == profileActive);
|
||||
|
||||
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, profileActive: profileActive)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
@@ -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 ProfileRepository : CRUDRepository<Profile, int, WFDBContext>, IProfileRepository, ICRUDRepository<Profile, int>
|
||||
{
|
||||
public ProfileRepository(WFDBContext dbContext) : base(dbContext, dbContext.Profiles)
|
||||
{
|
||||
}
|
||||
}
|
||||
54
WorkFlow.sln
54
WorkFlow.sln
@@ -3,13 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34622.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkFlow.Domain", "WorkFlow.Domain\WorkFlow.Domain.csproj", "{71E9264E-A2F0-4E5A-B010-8E4618C0C6AC}"
|
||||
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
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkFlow.Infrastructure", "WorkFlow.Infrastructure\WorkFlow.Infrastructure.csproj", "{62526D0D-3365-4113-854A-3656191D7C63}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlow.Application", "WorkFlow.Application\WorkFlow.Application.csproj", "{5700B5DD-D17E-4E17-ADE5-48C95A0CC364}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlow.API", "src\WorkFlow.API\WorkFlow.API.csproj", "{2B724243-4C79-F3A4-EE25-B9A53C81464C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlow.API", "WorkFlow.API\WorkFlow.API.csproj", "{4FB33592-EF0D-47C3-9CDE-03B2EF12BE00}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlow.Application", "src\WorkFlow.Application\WorkFlow.Application.csproj", "{F1B4AC83-5137-C20B-641C-1699B46007A0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlow.Domain", "src\WorkFlow.Domain\WorkFlow.Domain.csproj", "{92A11048-6B9C-374E-87A0-BD6D8F864B77}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlow.Infrastructure", "src\WorkFlow.Infrastructure\WorkFlow.Infrastructure.csproj", "{94F2D67D-649E-63D2-A3BF-0BEC98C2D7E6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -17,26 +25,32 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{71E9264E-A2F0-4E5A-B010-8E4618C0C6AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{71E9264E-A2F0-4E5A-B010-8E4618C0C6AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{71E9264E-A2F0-4E5A-B010-8E4618C0C6AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{71E9264E-A2F0-4E5A-B010-8E4618C0C6AC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{62526D0D-3365-4113-854A-3656191D7C63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{62526D0D-3365-4113-854A-3656191D7C63}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{62526D0D-3365-4113-854A-3656191D7C63}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{62526D0D-3365-4113-854A-3656191D7C63}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5700B5DD-D17E-4E17-ADE5-48C95A0CC364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5700B5DD-D17E-4E17-ADE5-48C95A0CC364}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5700B5DD-D17E-4E17-ADE5-48C95A0CC364}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5700B5DD-D17E-4E17-ADE5-48C95A0CC364}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4FB33592-EF0D-47C3-9CDE-03B2EF12BE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4FB33592-EF0D-47C3-9CDE-03B2EF12BE00}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FB33592-EF0D-47C3-9CDE-03B2EF12BE00}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FB33592-EF0D-47C3-9CDE-03B2EF12BE00}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2B724243-4C79-F3A4-EE25-B9A53C81464C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2B724243-4C79-F3A4-EE25-B9A53C81464C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2B724243-4C79-F3A4-EE25-B9A53C81464C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2B724243-4C79-F3A4-EE25-B9A53C81464C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F1B4AC83-5137-C20B-641C-1699B46007A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F1B4AC83-5137-C20B-641C-1699B46007A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F1B4AC83-5137-C20B-641C-1699B46007A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F1B4AC83-5137-C20B-641C-1699B46007A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{92A11048-6B9C-374E-87A0-BD6D8F864B77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{92A11048-6B9C-374E-87A0-BD6D8F864B77}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{92A11048-6B9C-374E-87A0-BD6D8F864B77}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{92A11048-6B9C-374E-87A0-BD6D8F864B77}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94F2D67D-649E-63D2-A3BF-0BEC98C2D7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94F2D67D-649E-63D2-A3BF-0BEC98C2D7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94F2D67D-649E-63D2-A3BF-0BEC98C2D7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94F2D67D-649E-63D2-A3BF-0BEC98C2D7E6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{2B724243-4C79-F3A4-EE25-B9A53C81464C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{F1B4AC83-5137-C20B-641C-1699B46007A0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{92A11048-6B9C-374E-87A0-BD6D8F864B77} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{94F2D67D-649E-63D2-A3BF-0BEC98C2D7E6} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1ECB3995-5040-40BC-BC70-906E64BB4E01}
|
||||
EndGlobalSection
|
||||
|
||||
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
|
||||
@@ -17,4 +17,22 @@ public class ConfigController : CRUDControllerBaseWithErrorHandling<IConfigServi
|
||||
public ConfigController(ILogger<ConfigController> logger, IConfigService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Create(ConfigCreateDto createDto)
|
||||
{
|
||||
return base.Create(createDto);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Update(ConfigUpdateDto updateDto)
|
||||
{
|
||||
return base.Update(updateDto);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Delete([FromRoute] int id)
|
||||
{
|
||||
return base.Delete(id);
|
||||
}
|
||||
}
|
||||
@@ -7,31 +7,11 @@ namespace WorkFlow.API.Controllers
|
||||
[APIKeyAuth]
|
||||
public static class ControllerExtensions
|
||||
{
|
||||
public static bool TryGetUserId(this ControllerBase controller, out int? id)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetUsername(this ControllerBase controller, out string username)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.Name);
|
||||
var value = user.FindFirstValue(ClaimTypes.Name);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
@@ -45,9 +25,9 @@ namespace WorkFlow.API.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetName(this ControllerBase controller, out string name)
|
||||
public static bool TryGetName(this ClaimsPrincipal user, out string name)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.Surname);
|
||||
var value = user.FindFirstValue(ClaimTypes.Surname);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
@@ -61,9 +41,9 @@ namespace WorkFlow.API.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetPrename(this ControllerBase controller, out string prename)
|
||||
public static bool TryGetPrename(this ClaimsPrincipal user, out string prename)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.GivenName);
|
||||
var value = user.FindFirstValue(ClaimTypes.GivenName);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
@@ -77,9 +57,9 @@ namespace WorkFlow.API.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetEmail(this ControllerBase controller, out string email)
|
||||
public static bool TryGetEmail(this ClaimsPrincipal user, out string email)
|
||||
{
|
||||
var value = controller.User.FindFirstValue(ClaimTypes.Email);
|
||||
var value = user.FindFirstValue(ClaimTypes.Email);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
45
src/WorkFlow.API/Controllers/ProfileController.cs
Normal file
45
src/WorkFlow.API/Controllers/ProfileController.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Profiles;
|
||||
|
||||
namespace WorkFlow.API.Controllers;
|
||||
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ProfileController : ControllerBase
|
||||
{
|
||||
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()
|
||||
{
|
||||
try
|
||||
{
|
||||
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 profile is null ? NotFound() : Ok(profile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,15 +35,10 @@ public class ProfileControlsTFController : CRUDControllerBase<IProfileControlsTF
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
if (!User.TryGetUserId(out var 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 Unauthorized("Failed to retrieve user identity.");
|
||||
}
|
||||
|
||||
return await _service.ReadAsync(
|
||||
@@ -65,21 +60,17 @@ public class ProfileControlsTFController : CRUDControllerBase<IProfileControlsTF
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
[HttpPost]
|
||||
public override async Task<IActionResult> Create([FromBody] ProfileControlsTFCreateDto createDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
if (!User.TryGetUserId(out var 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();
|
||||
@@ -93,21 +84,17 @@ public class ProfileControlsTFController : CRUDControllerBase<IProfileControlsTF
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
[HttpDelete]
|
||||
public override async Task<IActionResult> Delete([FromRoute] int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? userId))
|
||||
if (!User.TryGetUserId(out var 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(),
|
||||
@@ -35,21 +35,16 @@ namespace WorkFlow.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
if (!User.TryGetUserId(out var 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 Unauthorized("Failed to retrieve user identity.");
|
||||
}
|
||||
|
||||
return await _service.ReadAsync(
|
||||
withProfile: withProfile, withUser: withUser, withState,
|
||||
userId: id,
|
||||
profileId: profileId, objId: objId, profileActive: profileActive)
|
||||
profileId: profileId, objId: objId)
|
||||
.ThenAsync(
|
||||
Success: pctf => pctf.Any() ? Ok(pctf) : NotFound(),
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
@@ -70,16 +65,11 @@ namespace WorkFlow.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
if (!User.TryGetUserId(out var 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();
|
||||
@@ -98,16 +88,11 @@ namespace WorkFlow.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? userId))
|
||||
if (!User.TryGetUserId(out var 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(),
|
||||
@@ -17,4 +17,22 @@ public class StateController : CRUDControllerBaseWithErrorHandling<IStateService
|
||||
public StateController(ILogger<StateController> logger, IStateService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Create(StateCreateDto createDto)
|
||||
{
|
||||
return base.Create(createDto);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Update(StateUpdateDto updateDto)
|
||||
{
|
||||
return base.Update(updateDto);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> Delete([FromRoute] int id)
|
||||
{
|
||||
return base.Delete(id);
|
||||
}
|
||||
}
|
||||
@@ -26,24 +26,19 @@ public class UserController : ControllerBase
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.TryGetUserId(out int? id))
|
||||
if (!User.TryGetUserId(out var 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.");
|
||||
return Unauthorized("Failed to retrieve user identity.");
|
||||
}
|
||||
|
||||
return await userService.ReadByIdAsync(id).ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
logger.LogNotice(ntc);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using WorkFlow.API;
|
||||
using Microsoft.Extensions.Options;
|
||||
using DigitalData.Core.Abstractions.Security;
|
||||
using DigitalData.Core.Abstractions.Security.Extensions;
|
||||
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
logger.Info("Logging initialized.");
|
||||
@@ -26,14 +27,28 @@ 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>();
|
||||
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).AddWorkFlowRepositories().AddUserManager<WFDBContext>();
|
||||
builder.Services.AddCookieBasedLocalizer();
|
||||
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
|
||||
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
||||
@@ -20,7 +20,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.3" />
|
||||
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.7" />
|
||||
<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" />
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
<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.json
Normal file
17
src/WorkFlow.API/appsettings.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"DiPMode": true,
|
||||
"EnableSwagger": true,
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||
},
|
||||
"OpenApiInfo": {
|
||||
"Title": "WorkFlow API",
|
||||
"Contact": {
|
||||
"Email": "info-flow@digitaldata.works",
|
||||
"Name": "Digital Data GmbH",
|
||||
"Url": "https://digitaldata.works/"
|
||||
}
|
||||
},
|
||||
"MediatRLicense": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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);
|
||||
}
|
||||
5
src/WorkFlow.Application/Contracts/IProfileService.cs
Normal file
5
src/WorkFlow.Application/Contracts/IProfileService.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace WorkFlow.Application.Contracts;
|
||||
|
||||
public interface IProfileService
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
public interface IConfigRepository : ICRUDRepository<Config, int>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Repository for retrieving <see cref="ProfileObject"/> entities from the database.
|
||||
/// </summary>
|
||||
public interface IProfileObjRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the list of <see cref="ProfileObject"/> 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="ProfileObject"/> 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<ProfileObject>> ReadAsync(int userId, int profileId, CancellationToken cancel = default);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
public interface IStateRepository : ICRUDRepository<State, int>
|
||||
{
|
||||
}
|
||||
34
src/WorkFlow.Application/DependencyInjection.cs
Normal file
34
src/WorkFlow.Application/DependencyInjection.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.Services;
|
||||
|
||||
namespace WorkFlow.Application;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceCollection AddWorkFlowServices(this IServiceCollection services, Action<DIOptions>? options = null)
|
||||
{
|
||||
DIOptions diOptions = new();
|
||||
options?.Invoke(diOptions);
|
||||
|
||||
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>();
|
||||
services.AddMediatR(cfg =>
|
||||
{
|
||||
cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly);
|
||||
cfg.LicenseKey = diOptions.MediatRLicense;
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public class DIOptions
|
||||
{
|
||||
public string MediatRLicense { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
54
src/WorkFlow.Application/Profiles/ReadProfile.cs
Normal file
54
src/WorkFlow.Application/Profiles/ReadProfile.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using MediatR;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
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 ReadProfile(int UserId, bool IncludeObject = true) : IRequest<Domain.Entities.Profile?>;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="ReadProfile"/> request by retrieving the user profile
|
||||
/// from the data store using the <see cref="IProfileRepository"/>.
|
||||
/// </summary>
|
||||
public class ReadProfileHandler : IRequestHandler<ReadProfile, Domain.Entities.Profile?>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
|
||||
private readonly IProfileObjRepository _objRepository;
|
||||
|
||||
/// <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)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_objRepository = objRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="ReadProfile"/> 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<Domain.Entities.Profile?> Handle(ReadProfile request, CancellationToken cancel = default)
|
||||
{
|
||||
var profile = await _profileRepository.ReadAsync(request.UserId, cancel);
|
||||
if (request.IncludeObject && profile?.Id is int profileId)
|
||||
profile.Objects = await _objRepository.ReadAsync(request.UserId, profileId, cancel);
|
||||
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReadProfileExtensions
|
||||
{
|
||||
public static Task<Domain.Entities.Profile?> ReadProfileAsync(this IMediator mediator, int userId, bool includeObject = true)
|
||||
=> mediator.Send(new ReadProfile(UserId: userId, IncludeObject: includeObject));
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using DigitalData.Core.Application;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Config;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
@@ -5,7 +5,7 @@ using DigitalData.Core.DTO;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
namespace WorkFlow.Application.Services
|
||||
{
|
||||
@@ -5,7 +5,7 @@ using DigitalData.Core.DTO;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileObjState;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
@@ -19,13 +19,13 @@ public class ProfileObjStateService : CRUDService<IProfileObjStateRepository, Pr
|
||||
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)
|
||||
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, profileActive: profileActive);
|
||||
profileId: profileId, objId: objId);
|
||||
|
||||
var post_dto_list = _mapper.Map<IEnumerable<ProfileObjStateDto>>(pos_list);
|
||||
|
||||
7
src/WorkFlow.Application/Services/ProfileService.cs
Normal file
7
src/WorkFlow.Application/Services/ProfileService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using WorkFlow.Application.Contracts;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
public class ProfileService : IProfileService
|
||||
{
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using DigitalData.Core.Application;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
|
||||
namespace WorkFlow.Application.Services;
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="3.2.0" />
|
||||
<PackageReference Include="MediatR" Version="13.0.0" />
|
||||
<PackageReference Include="UserManager.Application" Version="3.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WorkFlow.Domain\WorkFlow.Domain.csproj" />
|
||||
<ProjectReference Include="..\WorkFlow.Infrastructure\WorkFlow.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
30
src/WorkFlow.Domain/Entities/Profile.cs
Normal file
30
src/WorkFlow.Domain/Entities/Profile.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
public class Profile
|
||||
{
|
||||
[Column("PROFILE_ID")]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Column("TYPE_ID")]
|
||||
public byte? TypeId { get; set; }
|
||||
|
||||
[Column("CAPTION")]
|
||||
public string? Caption { get; set; }
|
||||
|
||||
[Column("SUBTITLE")]
|
||||
public string? Subtitle { get; set; }
|
||||
|
||||
[Column("COUNTOBJ")]
|
||||
public int? CountObj { get; set; }
|
||||
|
||||
[Column("FORE_COLOR")]
|
||||
public string? ForeColor { get; set; }
|
||||
|
||||
[Column("BACK_COLOR")]
|
||||
public string? BackColor { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public IEnumerable<ProfileObject>? Objects { get; set; }
|
||||
}
|
||||
27
src/WorkFlow.Domain/Entities/ProfileObjects.cs
Normal file
27
src/WorkFlow.Domain/Entities/ProfileObjects.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WorkFlow.Domain.Entities;
|
||||
|
||||
public class ProfileObject
|
||||
{
|
||||
[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; }
|
||||
}
|
||||
21
src/WorkFlow.Infrastructure/DependencyInjection.cs
Normal file
21
src/WorkFlow.Infrastructure/DependencyInjection.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
namespace WorkFlow.Infrastructure;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
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<IProfileObjRepository, ProfileObjRepository>();
|
||||
services.TryAddScoped<IStateRepository, StateRepository>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
14
src/WorkFlow.Infrastructure/Repositories/ConfigRepository.cs
Normal file
14
src/WorkFlow.Infrastructure/Repositories/ConfigRepository.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
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,53 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Repository implementation for retrieving <see cref="ProfileObject"/> entities from the database.
|
||||
/// </summary>
|
||||
public class ProfileObjRepository : IProfileObjRepository
|
||||
{
|
||||
private readonly WFDBContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileObjRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">The database context used for accessing profile data.</param>
|
||||
public ProfileObjRepository(WFDBContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the list of <see cref="ProfileObject"/> 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="ProfileObject"/> 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<ProfileObject>> ReadAsync(int userId, int profileId, CancellationToken cancel = default)
|
||||
=> await _context.Objects
|
||||
.FromSqlRaw("SELECT * FROM [FNMWF_GET_PROFILE_OBJECTS] ({0}, {1})", userId, profileId)
|
||||
.ToListAsync(cancel);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
@@ -14,7 +14,7 @@ public class ProfileObjStateRepository : CRUDRepository<ProfileObjState, int, WF
|
||||
|
||||
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)
|
||||
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();
|
||||
|
||||
@@ -42,9 +42,6 @@ public class ProfileObjStateRepository : CRUDRepository<ProfileObjState, int, WF
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -52,11 +49,11 @@ public class ProfileObjStateRepository : CRUDRepository<ProfileObjState, int, WF
|
||||
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)
|
||||
int? profileId = null, int? objId = null)
|
||||
=> await Read(
|
||||
isReadonly: isReadonly,
|
||||
withProfile: withProfile, withUser: withUser, withState: withState,
|
||||
userId: userId, username: username,
|
||||
profileId: profileId, objId: objId, profileActive: profileActive)
|
||||
profileId: profileId, objId: objId)
|
||||
.ToListAsync();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
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,7 +1,7 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using WorkFlow.Application.Contracts.Repositories;
|
||||
using WorkFlow.Domain.Entities;
|
||||
using WorkFlow.Infrastructure.Contracts;
|
||||
|
||||
namespace WorkFlow.Infrastructure.Repositories;
|
||||
|
||||
@@ -14,6 +14,8 @@ public class WFDBContext : DbContext, IUserManagerDbContext
|
||||
|
||||
public DbSet<Profile> Profiles { get; set; }
|
||||
|
||||
public DbSet<ProfileObject> Objects { get; set; }
|
||||
|
||||
public DbSet<ProfileObjState> ProfileObjStates { get; set; }
|
||||
|
||||
public DbSet<State> States { get; set; }
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WorkFlow.Domain\WorkFlow.Domain.csproj" />
|
||||
<ProjectReference Include="..\WorkFlow.Application\WorkFlow.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user