feat: initial commit

This commit is contained in:
Thom Lamb
2026-06-23 11:26:55 -05:00
parent d472a6cff8
commit 1e042cc5e8
722 changed files with 278037 additions and 1 deletions
+10
View File
@@ -0,0 +1,10 @@
.dockerignore
.gitignore
**/Dockerfile
**/.env
**/.vs
**/.vscode
**/bin
**/obj
**/.toolstarget
**/node_modules
+273
View File
@@ -0,0 +1,273 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
###################
# compiled source #
###################
*.com
*.class
*.dll
*.exe
*.pdb
*.dll.config
*.cache
*.suo
# Include dlls if theyre in the NuGet packages directory
!/packages/*/lib/*.dll
# Include dlls if they're in the CommonReferences directory
!*CommonReferences/*.dll
####################
# VS Upgrade stuff #
####################
_UpgradeReport_Files/
###############
# Directories #
###############
bin/
obj/
TestResults/
###################
# Web publish log #
###################
*.Publish.xml
#############
# Resharper #
#############
/_ReSharper.*
*.ReSharper.*
############
# Packages #
############
# its better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
######################
# Logs and databases #
######################
*.log
*.sqlite
# OS generated files #
######################
.DS_Store?
ehthumbs.db
Icon?
Thumbs.db
# User-specific files
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studo 2015 cache/options directory
.vs/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
ClickOnce/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
bower_components/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
**/node_modules/*
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# SonarQube files
sonarqube/
.vs/
*.orig
buildlogs/
# Jetbrains Rider IDE
.idea/
+156
View File
@@ -0,0 +1,156 @@
ARG PROJECT=Strata.Stratasphere
ARG VERSION=0.0.0
ARG SONARURL=''
ARG SONARLOGIN=''
ARG SONARBRANCH=''
ARG STRATASPHERE_TESTS_AWS_ACCESS_KEY_ID=''
ARG STRATASPHERE_TESTS_AWS_SECRET_ACCESS_KEY=''
##############
# Base image #
##############
FROM ecr.ops.stratanetwork.net/strata.microsoft.dotnet.aspnet:6.0 AS base
# Add TMZ files for CST
RUN cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"
RUN cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
RUN sed -i'.bak' 's/$/ contrib/' /etc/apt/sources.list
RUN apt-get update --allow-releaseinfo-change \
&& apt-get install -y \
libc6-dev \
libgdiplus \
libx11-dev \
ttf-mscorefonts-installer \
fontconfig \
&& rm -rf /var/lib/apt/lists/*
###############
# Build image #
###############
FROM ecr.ops.stratanetwork.net/strata.microsoft.dotnet.sdk:6.0 as build
ARG PROJECT
ARG VERSION
ARG SONARURL
ARG SONARLOGIN
ARG SONARBRANCH
ARG STRATASPHERE_TESTS_AWS_ACCESS_KEY_ID
ARG STRATASPHERE_TESTS_AWS_SECRET_ACCESS_KEY
ENV AWS_ACCESS_KEY_ID=${STRATASPHERE_TESTS_AWS_ACCESS_KEY_ID}
ENV AWS_SECRET_ACCESS_KEY=${STRATASPHERE_TESTS_AWS_SECRET_ACCESS_KEY}
ENV AWS_DEFAULT_REGION=us-east-1
COPY ["awsconfig", "/root/.aws/config"]
# Add TMZ files for CST
RUN cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"
RUN cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
RUN apt-get update --allow-releaseinfo-change \
&& apt-get install -y \
libc6-dev \
libgdiplus \
libx11-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
# Copy project files and restore
COPY ["${PROJECT}.sln", "${PROJECT}.sln"]
COPY src/**/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p src/${file%.*}/ && mv $file src/${file%.*}/; done
COPY tests/**/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p tests/${file%.*}/ && mv $file tests/${file%.*}/; done
RUN dotnet restore "${PROJECT}.sln" \
--source https://api.nuget.org/v3/index.json \
--source https://proget.sdt.local/nuget/nuget/v3/index.json
# Copy files and build
COPY . .
RUN if [ "${SONARLOGIN}" != "" ] ; then dotnet sonarscanner begin \
/k:"${PROJECT}" \
/d:sonar.scm.provider=git \
/d:sonar.host.url="${SONARURL}" \
${SONARBRANCH} \
/d:sonar.login="${SONARLOGIN}" \
/d:sonar.cs.opencover.reportsPaths="/src/cover.xml" \
/d:sonar.dependencyCheck.jsonReportPath=/src/buildlogs/dependency-check-report.json \
/d:sonar.dependencyCheck.htmlReportPath=/src/buildlogs/dependency-check-report.html \
/v:sonar.projectVersion="${VERSION}"; fi
RUN dotnet build "${PROJECT}.sln" \
--configuration Release \
--no-restore
# Run tests
RUN dotnet test "tests/${PROJECT}.Api.APITests/${PROJECT}.Api.APITests.csproj" \
--configuration Release \
--no-restore \
--no-build \
--verbosity=normal \
--logger "trx;LogFileName=/test-results/api-api-tests.trx" \
-p:CollectCoverage=true \
-p:CoverletOutputFormat="json" \
-p:CoverletOutput=/test-results/cover.json \
|| true
RUN dotnet test "tests/${PROJECT}.Api.UnitTests/${PROJECT}.Api.UnitTests.csproj" \
--configuration Release \
--no-restore \
--no-build \
--verbosity=normal \
--logger "trx;LogFileName=/test-results/api-unit-tests.trx" \
-p:CollectCoverage=true \
-p:CoverletOutputFormat="json" \
-p:CoverletOutput=/test-results/cover-apiUnit.json \
-p:MergeWith=/test-results/cover.json \
|| true
RUN dotnet test "tests/${PROJECT}.Biz.UnitTests/${PROJECT}.Biz.UnitTests.csproj" \
--configuration Release \
--no-restore \
--no-build \
--verbosity=normal \
--logger "trx;LogFileName=/test-results/unit-tests.trx" \
-p:CollectCoverage=true \
-p:CoverletOutputFormat="opencover" \
-p:CoverletOutput=/test-results/cover.xml \
-p:MergeWith=/test-results/cover-apiUnit.json \
|| true
# Publish project
RUN dotnet publish "src/${PROJECT}.Api/${PROJECT}.Api.csproj" \
--configuration Release \
--no-restore \
--no-build \
--output /app
RUN if [ "${SONARLOGIN}" != "" ] ; then \
(/dc/dependency-check/bin/dependency-check.sh -f JSON -f HTML -s . -o ./buildlogs \
--suppression ./sonarsuppressions.xml \
--noupdate --nodeAuditSkipDevDependencies --disableNodeJS \
--dbDriverName "com.microsoft.sqlserver.jdbc.SQLServerDriver" \
--connectionString "jdbc:sqlserver://ddensqldevops01.sdt.local;Database=DependencyCheck;encrypt=true;trustServerCertificate=true;" \
--dbUser "dcuser" --dbPassword "${SONARLOGIN}" || true) && \
dotnet sonarscanner end /d:sonar.login="${SONARLOGIN}"; \
fi
###############
# Final image #
###############
FROM base AS final
ARG PROJECT
WORKDIR /app
ARG PROJECT
ENV PROJECTDLL=${PROJECT}.Api.dll
ENV DOTNET_ENVIRONMENT=Development
ENV ASPNETCORE_ENVIRONMENT=Development
COPY --from=build /app /app
COPY --from=build /test-results /test-results
ENTRYPOINT dotnet ${PROJECTDLL}
+72
View File
@@ -0,0 +1,72 @@
ARG PROJECT=Strata.Stratasphere
ARG VERSION=0.0.0
##############
# Base image #
##############
FROM ecr.ops.stratanetwork.net/strata.microsoft.dotnet.aspnet:6.0 AS base
# Add TMZ files for CST
RUN cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
RUN sed -i'.bak' 's/$/ contrib/' /etc/apt/sources.list
RUN apt-get update --allow-releaseinfo-change \
&& apt-get install -y \
libc6-dev \
libgdiplus \
libx11-dev \
ttf-mscorefonts-installer \
fontconfig \
&& rm -rf /var/lib/apt/lists/*
###############
# Build image #
###############
FROM ecr.ops.stratanetwork.net/strata.microsoft.dotnet.sdk:6.0 as build
ARG PROJECT
ARG VERSION
# Add TMZ files for CST
RUN cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
WORKDIR /src
# Copy project files and restore
COPY ["${PROJECT}.sln", "${PROJECT}.sln"]
COPY src/**/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p src/${file%.*}/ && mv $file src/${file%.*}/; done
COPY tests/**/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p tests/${file%.*}/ && mv $file tests/${file%.*}/; done
RUN dotnet restore "${PROJECT}.sln" \
--source https://api.nuget.org/v3/index.json \
--source https://proget.sdt.local/nuget/nuget/v3/index.json
# Copy files and build
COPY . .
RUN dotnet build "${PROJECT}.sln" \
--configuration Release \
--no-restore
# Publish project
RUN dotnet publish "src/${PROJECT}.Dashboard/${PROJECT}.Dashboard.csproj" \
--configuration Release \
--no-restore \
--no-build \
--output /app
###############
# Final image #
###############
FROM base AS final
ARG PROJECT
WORKDIR /app
ARG PROJECT
ENV PROJECTDLL=${PROJECT}.Dashboard.dll
ENV DOTNET_ENVIRONMENT=Development
ENV ASPNETCORE_ENVIRONMENT=Development
COPY --from=build /app /app
ENTRYPOINT dotnet ${PROJECTDLL}
+72
View File
@@ -0,0 +1,72 @@
ARG PROJECT=Strata.Stratasphere
ARG VERSION=0.0.0
##############
# Base image #
##############
FROM ecr.ops.stratanetwork.net/strata.microsoft.dotnet.aspnet:6.0 AS base
# Add TMZ files for CST
RUN cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
RUN sed -i'.bak' 's/$/ contrib/' /etc/apt/sources.list
RUN apt-get update --allow-releaseinfo-change \
&& apt-get install -y \
libc6-dev \
libgdiplus \
libx11-dev \
ttf-mscorefonts-installer \
fontconfig \
&& rm -rf /var/lib/apt/lists/*
###############
# Build image #
###############
FROM ecr.ops.stratanetwork.net/strata.microsoft.dotnet.sdk:6.0 as build
ARG PROJECT
ARG VERSION
# Add TMZ files for CST
RUN cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
WORKDIR /src
# Copy project files and restore
COPY ["${PROJECT}.sln", "${PROJECT}.sln"]
COPY src/**/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p src/${file%.*}/ && mv $file src/${file%.*}/; done
COPY tests/**/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p tests/${file%.*}/ && mv $file tests/${file%.*}/; done
RUN dotnet restore "${PROJECT}.sln" \
--source https://api.nuget.org/v3/index.json \
--source https://proget.sdt.local/nuget/nuget/v3/index.json
# Copy files and build
COPY . .
RUN dotnet build "${PROJECT}.sln" \
--configuration Release \
--no-restore
# Publish project
RUN dotnet publish "src/${PROJECT}.Service/${PROJECT}.Service.csproj" \
--configuration Release \
--no-restore \
--no-build \
--output /app
###############
# Final image #
###############
FROM base AS final
ARG PROJECT
WORKDIR /app
ARG PROJECT
ENV PROJECTDLL=${PROJECT}.Service.dll
ENV DOTNET_ENVIRONMENT=Development
ENV ASPNETCORE_ENVIRONMENT=Development
COPY --from=build /app /app
ENTRYPOINT dotnet ${PROJECTDLL}
+28
View File
@@ -0,0 +1,28 @@
FROM node:18.17.0 as build
# ENV CI=true
# Set working directory
WORKDIR /app
# Install dependencies
RUN npm config set @strata:registry http://proget.sdt.local/npm/npm
RUN npm config set strict-ssl false
COPY src/Strata.Stratasphere.Web/template/package*.json ./
RUN npm cache verify
RUN npm install --legacy-peer-deps
RUN npm ci --legacy-peer-deps
RUN npx browserslist@latest --update-db
# Copy in rest of app and build
COPY src/Strata.Stratasphere.Web/template/ .
RUN npm run build
# Run tests
#RUN npm run test
# Build release container
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY src/Strata.Stratasphere.Web/nginx.conf /etc/nginx/conf.d/default.conf
+47 -1
View File
@@ -1 +1,47 @@
# strataspheredatamanagement # Strataspheredatamanagement
## First Time Setup Notes
For first time setting up AWS authentication you'll need to follow the steps here https://confluence.sdt.local/display/SWPRJ/IAM+Application+Role+Setup+for+AWS+applications#IAMApplicationRoleSetupforAWSapplications-AWSCredentialsSetup
You will need the contents below in your AWS config file located here: %UserProfile%/.aws/config
```
[profile stratasphere-datawrangling]
source_profile = 809820578507_SDT-Dev-Developers
role_arn = arn:aws:iam::809820578507:role/SDT-data-wrangler-Service-Role
region=us-east-1
```
### SonarQube Metrics
[SonarQube](https://sonarqube.ops.stratanetwork.net/dashboard?id=Strata.StratasphereDataManagement)
### Build Status
[![build](https://github.com/stratadecision/strataspheredatamanagement/actions/workflows/build.yaml/badge.svg)](https://github.com/stratadecision/strataspheredatamanagement/actions/workflows/build.yaml)
## Branching and Versioning
| branch | version format | example |
| ---------- | --------------------- | --------------- |
| master | #.#.# | 1.2.3 |
| feature/\* | #.#+1.0-featureName.# | 1.3.0-newfeat.1 |
| fix/\* | #.#.#+1-fixName.# | 1.2.4-bug.1 |
See our [confluence page](https://confluence.sdt.local/display/DOP/Branching+and+Versioning) for more information
## Usage
### Build and Run
```
docker-compose up --build
```
API - https://localhost:8443
Web - http://localhost:3000
### Extracting nuget package
```
docker create --name throwaway stratatemplate_template-api
docker cp throwaway:/pack .
docker rm throwaway
```
@@ -0,0 +1,48 @@
--Sandbox Database
USE ROLE DATAADMIN;
CREATE DATABASE IF NOT EXISTS DATALAKE_SANDBOX COMMENT = 'Sandbox environment for datalake';
GRANT USAGE ON DATABASE DATALAKE_SANDBOX TO ROLE DATAANALYST;
GRANT CREATE SCHEMA ON DATABASE DATALAKE_SANDBOX TO ROLE DATAANALYST;
USE ROLE DATAADMIN;
USE DATABASE DATALAKE_SANDBOX;
CREATE SCHEMA IF NOT EXISTS DATA WITH MANAGED ACCESS;
ALTER SCHEMA IF EXISTS DATA ENABLE MANAGED ACCESS;
GRANT USAGE ON SCHEMA DATA TO ROLE DATAANALYST;
GRANT SELECT ON ALL TABLES IN SCHEMA DATA TO ROLE DATAANALYST;
GRANT SELECT ON FUTURE TABLES IN SCHEMA DATA TO ROLE DATAANALYST;
--Staging Database
USE ROLE DATAADMIN;
CREATE DATABASE IF NOT EXISTS DATALAKE_STAGING COMMENT = 'Staging environment for datalake';
GRANT USAGE ON DATABASE DATALAKE_STAGING TO ROLE DATAANALYST;
GRANT CREATE SCHEMA ON DATABASE DATALAKE_STAGING TO ROLE DATAANALYST;
USE ROLE DATAADMIN;
USE DATABASE DATALAKE_STAGING;
CREATE SCHEMA IF NOT EXISTS DATA WITH MANAGED ACCESS;
ALTER SCHEMA IF EXISTS DATA ENABLE MANAGED ACCESS;
GRANT USAGE ON SCHEMA DATA TO ROLE DATAANALYST;
GRANT SELECT ON ALL TABLES IN SCHEMA DATA TO ROLE DATAANALYST;
GRANT SELECT ON FUTURE TABLES IN SCHEMA DATA TO ROLE DATAANALYST;
--Production Database
USE ROLE DATAADMIN;
CREATE DATABASE IF NOT EXISTS DATALAKE_PROD COMMENT = 'Production environment for datalake';
GRANT USAGE ON DATABASE DATALAKE_PROD TO ROLE DATAANALYST;
GRANT CREATE SCHEMA ON DATABASE DATALAKE_PROD TO ROLE DATAANALYST;
USE ROLE DATAADMIN;
USE DATABASE DATALAKE_PROD;
CREATE SCHEMA IF NOT EXISTS DATA WITH MANAGED ACCESS;
ALTER SCHEMA IF EXISTS DATA ENABLE MANAGED ACCESS;
GRANT USAGE ON SCHEMA DATA TO ROLE DATAANALYST;
GRANT SELECT ON ALL TABLES IN SCHEMA DATA TO ROLE DATAANALYST;
GRANT SELECT ON FUTURE TABLES IN SCHEMA DATA TO ROLE DATAANALYST;
+60
View File
@@ -0,0 +1,60 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32922.545
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Biz", "src\Strata.Stratasphere.Biz\Strata.Stratasphere.Biz.csproj", "{55550602-86C4-44DF-B2B0-1FCE65B3A8AF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Service", "src\Strata.Stratasphere.Service\Strata.Stratasphere.Service.csproj", "{C5F500D7-F5F9-4AE8-9EA6-5589E790AC9A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Dashboard", "src\Strata.Stratasphere.Dashboard\Strata.Stratasphere.Dashboard.csproj", "{503D5A6B-4B38-42DE-9066-57605B8BFBB5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Api", "src\Strata.Stratasphere.Api\Strata.Stratasphere.Api.csproj", "{95A28653-54C1-4C70-930E-652B126AEB9C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Biz.UnitTests", "tests\Strata.Stratasphere.Biz.UnitTests\Strata.Stratasphere.Biz.UnitTests.csproj", "{4A2BD57E-BAA9-4280-B189-2ED7D5CB2F28}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Web", "src\Strata.Stratasphere.Web\Strata.Stratasphere.Web.csproj", "{2C4F6E6A-C220-49E7-99FD-B84B6AF5CBFF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strata.Stratasphere.Biz.IntegrationTests", "tests\Strata.Stratasphere.Biz.IntegrationTests\Strata.Stratasphere.Biz.IntegrationTests.csproj", "{550F3422-3FC7-45EF-A0B2-E3FCB84CAF35}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{55550602-86C4-44DF-B2B0-1FCE65B3A8AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55550602-86C4-44DF-B2B0-1FCE65B3A8AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55550602-86C4-44DF-B2B0-1FCE65B3A8AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55550602-86C4-44DF-B2B0-1FCE65B3A8AF}.Release|Any CPU.Build.0 = Release|Any CPU
{C5F500D7-F5F9-4AE8-9EA6-5589E790AC9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5F500D7-F5F9-4AE8-9EA6-5589E790AC9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5F500D7-F5F9-4AE8-9EA6-5589E790AC9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5F500D7-F5F9-4AE8-9EA6-5589E790AC9A}.Release|Any CPU.Build.0 = Release|Any CPU
{503D5A6B-4B38-42DE-9066-57605B8BFBB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{503D5A6B-4B38-42DE-9066-57605B8BFBB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{503D5A6B-4B38-42DE-9066-57605B8BFBB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{503D5A6B-4B38-42DE-9066-57605B8BFBB5}.Release|Any CPU.Build.0 = Release|Any CPU
{95A28653-54C1-4C70-930E-652B126AEB9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95A28653-54C1-4C70-930E-652B126AEB9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95A28653-54C1-4C70-930E-652B126AEB9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95A28653-54C1-4C70-930E-652B126AEB9C}.Release|Any CPU.Build.0 = Release|Any CPU
{4A2BD57E-BAA9-4280-B189-2ED7D5CB2F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A2BD57E-BAA9-4280-B189-2ED7D5CB2F28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A2BD57E-BAA9-4280-B189-2ED7D5CB2F28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A2BD57E-BAA9-4280-B189-2ED7D5CB2F28}.Release|Any CPU.Build.0 = Release|Any CPU
{2C4F6E6A-C220-49E7-99FD-B84B6AF5CBFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C4F6E6A-C220-49E7-99FD-B84B6AF5CBFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C4F6E6A-C220-49E7-99FD-B84B6AF5CBFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C4F6E6A-C220-49E7-99FD-B84B6AF5CBFF}.Release|Any CPU.Build.0 = Release|Any CPU
{550F3422-3FC7-45EF-A0B2-E3FCB84CAF35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{550F3422-3FC7-45EF-A0B2-E3FCB84CAF35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{550F3422-3FC7-45EF-A0B2-E3FCB84CAF35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{550F3422-3FC7-45EF-A0B2-E3FCB84CAF35}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BE72BC18-62A4-42A7-9B88-08A667B35A19}
EndGlobalSection
EndGlobal
+3
View File
@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dtos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stratasphere/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+4
View File
@@ -0,0 +1,4 @@
[profile default]
credential_source = Environment
role_arn = arn:aws:iam::809820578507:role/SDT-data-wrangler-Service-Role
region = us-east-1
+16
View File
@@ -0,0 +1,16 @@
version: "3"
services:
template-web:
build:
context: .
dockerfile: Web/Dockerfile
ports:
- "3000:80"
template-api:
build:
context: .
dockerfile: Api/Dockerfile
ports:
- "8080:80"
- "8443:443"
+151
View File
@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cpe>cpe:/a:jetbrains:teamcity</cpe>
<cve>CVE-2014-10002</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: Microsoft.AspNetCore.Authentication.JwtBearer.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/Microsoft\.AspNetCore\.Authentication\.JwtBearer@.*$</packageUrl>
<cve>CVE-2020-1108</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: Microsoft.VisualStudio.CodeCoverage.Shim.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/Microsoft\.VisualStudio\.CodeCoverage\.Shim@.*$</packageUrl>
<cve>CVE-2020-1171</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: Microsoft.VisualStudio.CodeCoverage.Shim.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/Microsoft\.VisualStudio\.CodeCoverage\.Shim@.*$</packageUrl>
<cve>CVE-2020-1192</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: SonarScanner.MSBuild.Tasks.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/SonarScanner\.MSBuild\.Tasks@.*$</packageUrl>
<cve>CVE-2020-22475</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: browserslist:4.14.2
]]></notes>
<packageUrl regex="true">^pkg:npm/browserslist@.*$</packageUrl>
<vulnerabilityName>1747</vulnerabilityName>
</suppress>
<suppress>
<notes><![CDATA[
file name: css-what:3.4.2
]]></notes>
<packageUrl regex="true">^pkg:npm/css\-what@.*$</packageUrl>
<vulnerabilityName>1754</vulnerabilityName>
</suppress>
<suppress>
<notes><![CDATA[
file name: dns-packet:1.3.1
]]></notes>
<packageUrl regex="true">^pkg:npm/dns\-packet@.*$</packageUrl>
<vulnerabilityName>1745</vulnerabilityName>
</suppress>
<suppress>
<notes><![CDATA[
file name: normalize-url:3.3.0
]]></notes>
<packageUrl regex="true">^pkg:npm/normalize\-url@.*$</packageUrl>
<vulnerabilityName>1755</vulnerabilityName>
</suppress>
<suppress>
<notes><![CDATA[
file name: trim-newlines:1.0.0
]]></notes>
<packageUrl regex="true">^pkg:npm/trim\-newlines@.*$</packageUrl>
<vulnerabilityName>1753</vulnerabilityName>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2014-10036</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12156</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12157</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12841</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12842</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12843</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12844</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.ServiceMessages.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.ServiceMessages@.*$</packageUrl>
<cve>CVE-2019-12845</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.VSTest.TestLogger.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.VSTest\.TestLogger@.*$</packageUrl>
<cpe>cpe:/a:jetbrains:teamcity</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: TeamCity.VSTest.TestAdapter.dll
]]></notes>
<packageUrl regex="true">^pkg:generic/TeamCity\.VSTest\.TestAdapter@.*$</packageUrl>
<cpe>cpe:/a:jetbrains:teamcity</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: dependency-check-core-5.3.2.jar: jquery-3.4.1.min.js
]]></notes>
<packageUrl regex="true">^pkg:javascript/jquery@.*$</packageUrl>
<vulnerabilityName>Regex in its jQuery.htmlPrefilter sometimes may introduce XSS</vulnerabilityName>
</suppress>
</suppressions>
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.Stratasphere.Biz.Mappings.Accounts;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class AccountMappingController : ControllerBase
{
private readonly IAccountMappingService _accountMappingService;
public AccountMappingController(IAccountMappingService accountMappingService)
{
_accountMappingService = accountMappingService;
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> SetIsSPHCostModel(AccountMappingInfo mappingInfo, CancellationToken cancellationToken)
{
var userName = User?.Identity?.Name;
await _accountMappingService.SetIsSPHCostModel(userName, mappingInfo.StrataId, mappingInfo.AccountCode, mappingInfo.IsSPHCostModel, cancellationToken);
return new AcceptedResult();
}
}
public class AccountMappingInfo
{
public int StrataId { get; set; }
public string AccountCode { get; set; }
public bool IsSPHCostModel { get; set; }
}
}
@@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.Accounts;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class AccountMappingDetailsController : ControllerBase
{
private readonly IAccountMappingDetailService _accountMappingDetailService;
public AccountMappingDetailsController(IAccountMappingDetailService accountMappingDetailService)
{
_accountMappingDetailService = accountMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<AccountMappingDetail>> GetAll(AccountMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return
await _accountMappingDetailService.GetAccountMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(AccountMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _accountMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _accountMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _accountMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
}
public class AccountMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public AccountMappingFilters FilterOptions { get; set; }
}
public class AccountMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public AccountMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.AdmitType;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class AdmitTypeMappingDetailsController : ControllerBase
{
private readonly IAdmitTypeMappingDetailService _admitTypeMappingDetailService;
public AdmitTypeMappingDetailsController(IAdmitTypeMappingDetailService admitTypeMappingDetailService)
{
_admitTypeMappingDetailService = admitTypeMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<AdmitTypeMappingDetail>> GetAll(AdmitTypeMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _admitTypeMappingDetailService.GetAdmitTypeMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(AdmitTypeMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _admitTypeMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _admitTypeMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _admitTypeMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class AdmitTypeMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public AdmitTypeMappingFilters FilterOptions { get; set; }
}
public class AdmitTypeMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public AdmitTypeMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,134 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.ClientQueries;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class ClientQueriesController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly IClientQueryService _clientQueryService;
public ClientQueriesController(DataManagementContext dataManagementContext, IClientQueryService clientQueryService)
{
_dataManagementContext = dataManagementContext;
_clientQueryService = clientQueryService;
}
private bool ClientQueryExists(int clientQueryId) => _dataManagementContext.ClientQueries.Any(e => e.ClientQueryId == clientQueryId);
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet]
public async Task<IEnumerable<ClientQuery>> GetClientQueries(CancellationToken cancellationToken)
{
var clientQueries = await _dataManagementContext.ClientQueries.ToListAsync(cancellationToken);
return clientQueries;
}
[HttpGet("{clientQueryId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<ClientQuery>> GetById(int clientQueryId, CancellationToken cancellationToken)
{
var clientQuery = await _dataManagementContext.ClientQueries.SingleOrDefaultAsync(x => x.ClientQueryId == clientQueryId, cancellationToken);
if (clientQuery == null)
{
return NotFound();
}
return clientQuery;
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesDefaultResponseType]
public async Task<ActionResult<ClientQuery>> Create([FromBody] ClientQuery clientQuery, CancellationToken cancellationToken)
{
var user = User?.Identity?.Name ?? "";
return await _clientQueryService.Create(clientQuery, user, cancellationToken);
}
[HttpPut("{clientQueryId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Update(int clientQueryId, ClientQuery clientQueryDto, CancellationToken cancellationToken)
{
if (clientQueryId != clientQueryDto.ClientQueryId) { return BadRequest(); }
var user = User?.Identity?.Name ?? "";
var updated = await _clientQueryService.Update(clientQueryDto, user, cancellationToken);
if (!updated) { return NotFound(); }
return NoContent();
}
[HttpPatch("{clientQueryId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Patch(int clientQueryId, [FromBody] JsonPatchDocument<ClientQuery> patchDoc,
CancellationToken cancellationToken)
{
if (patchDoc == null) { return BadRequest(); }
var user = User?.Identity?.Name ?? "";
var clientQuery = await _clientQueryService.Patch(clientQueryId, patchDoc, user, cancellationToken);
if (clientQuery == null) { return NotFound(); }
return new ObjectResult(clientQuery);
}
[HttpGet("{clientQueryId}/[action]")]
public async Task<bool> SaveToGithub(int clientQueryId, CancellationToken cancellationToken)
{
if (clientQueryId < 0) { return false; }
var user = User?.Identity?.Name ?? "";
return await _clientQueryService.SaveToGithub(clientQueryId, user, cancellationToken);
}
[HttpDelete("{clientQueryId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete(int clientQueryId, CancellationToken cancellationToken)
{
var clientQuery = await _dataManagementContext.ClientQueries.SingleOrDefaultAsync(p => p.ClientQueryId == clientQueryId, cancellationToken);
if (clientQuery == null)
{
return NotFound();
}
_dataManagementContext.ClientQueries.Remove(clientQuery);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return NoContent();
}
[HttpGet("{clientQueryId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> History(int clientQueryId, CancellationToken cancellationToken)
=> Ok(await _clientQueryService.History(clientQueryId, User?.Identity?.Name ?? ""));
}
}
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.Stratasphere.Biz.Database;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class DatabasesController : ControllerBase
{
private readonly IDatabaseService _databaseService;
/// <summary>
/// Provides an IEnumerable set of Database information
/// </summary>
/// <param name="databaseService"></param>
public DatabasesController(IDatabaseService databaseService)
{
_databaseService = databaseService;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IEnumerable<Database>> GetAll(CancellationToken cancellationToken)
{
return await _databaseService.GetDatabasesAsync(cancellationToken);
}
}
}
@@ -0,0 +1,62 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.Departments;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class DepartmentMappingDetailsController : ControllerBase
{
private readonly IDepartmentMappingDetailService _departmentMappingDetailService;
public DepartmentMappingDetailsController(IDepartmentMappingDetailService accountMappingDetailService)
{
_departmentMappingDetailService = accountMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<DepartmentMappingDetail>> GetAll(DepartmentMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _departmentMappingDetailService.GetDepartmentMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(DepartmentMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _departmentMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _departmentMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _departmentMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class DepartmentMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public DepartmentMappingFilters FilterOptions { get; set; }
}
public class DepartmentMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public DepartmentMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,55 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class DischargeStatusMappingDetailsController : ControllerBase
{
private readonly IDischargeStatusMappingDetailService _dischargeStatusMappingDetailService;
public DischargeStatusMappingDetailsController(IDischargeStatusMappingDetailService dischargeStatusMappingDetailService)
{
_dischargeStatusMappingDetailService = dischargeStatusMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<DischargeStatusMappingDetail>> GetAll(DischargeStatusMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return
await _dischargeStatusMappingDetailService.GetDischargeStatusMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(DischargeStatusMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _dischargeStatusMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _dischargeStatusMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class DischargeStatusMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public DischargeStatusMappingFilters FilterOptions { get; set; }
}
public class DischargeStatusMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public DischargeStatusMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.Stratasphere.Biz.Mappings.Exports;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class ExportController : ControllerBase
{
private readonly IExportJobService _exportJobService;
public ExportController(IExportJobService exportJobService)
{
_exportJobService = exportJobService;
}
[HttpGet("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Download([FromQuery] string filename, CancellationToken cancellationToken)
{
var memoryStream = await _exportJobService.DownloadFile(filename, cancellationToken);
return new FileContentResult(memoryStream.ToArray(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
FileDownloadName = filename
};
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _exportJobService.GetExports(cancellationToken);
}
}
}
@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.Stratasphere.Biz.Github;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class GithubController : ControllerBase
{
private readonly IDataWranglerHistoryService _historyService;
public GithubController(
IDataWranglerHistoryService historyService)
{
_historyService = historyService;
}
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> ProcessHistory(int processId, CancellationToken cancellationToken)
=> Ok(await _historyService.ProcessHistory(processId, User?.Identity?.Name ?? ""));
[HttpGet("{queryId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> QueryHistory(int queryId, CancellationToken cancellationToken)
=> Ok(await _historyService.QueryHistory(queryId, User?.Identity?.Name ?? ""));
[HttpGet("{clientQueryId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> ClientQueryHistory(int clientQueryId, CancellationToken cancellationToken)
=> Ok(await _historyService.ClientQueryHistory(clientQueryId, User?.Identity?.Name ?? ""));
}
}
@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.JobCodes;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class JobCodeMappingDetailsController : ControllerBase
{
private readonly IJobCodeMappingDetailService _jobCodeMappingDetailService;
public JobCodeMappingDetailsController(IJobCodeMappingDetailService jobCodeMappingDetailService)
{
_jobCodeMappingDetailService = jobCodeMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<JobCodeMappingDetail>> GetAll(JobCodeMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _jobCodeMappingDetailService.GetJobCodeMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(JobCodeMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _jobCodeMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _jobCodeMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _jobCodeMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class JobCodeMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public JobCodeMappingFilters FilterOptions { get; set; }
}
public class JobCodeMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public JobCodeMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Strata.Stratasphere.Api.Dtos;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class ParametersController: ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly ILogger<ParametersController> _logger;
public ParametersController(DataManagementContext dataManagementContext, ILogger<ParametersController> logger)
{
_dataManagementContext = dataManagementContext;
_logger = logger;
}
[HttpGet("{processId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IEnumerable<Parameter>> GetById(int processId, CancellationToken cancellationToken)
{
var parameters = await _dataManagementContext.Parameters.Where(p => p.ProcessId == processId)
.ToListAsync(cancellationToken);
return parameters;
}
// I don't love this method, we need to discuss if we are bulk saving or saving as they manipulate the grid
[HttpPut()]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesDefaultResponseType]
public async Task<IActionResult> SaveParameters([FromBody] List<ParameterDto> parameterDtos, CancellationToken cancellationToken)
{
foreach(var newParam in parameterDtos.Where(x => x.IsNew))
{
newParam.ParameterId = 0;
}
_dataManagementContext.Parameters.AddRange(parameterDtos.Where(x => x.IsNew && !x.IsDeleted));
_dataManagementContext.Parameters.RemoveRange(parameterDtos.Where(x => x.IsDeleted && !x.IsNew));
foreach(var updatedParam in parameterDtos.Where(x => !x.IsNew && !x.IsDeleted))
{
var baseParam = await _dataManagementContext.Parameters.FindAsync(new object[] {updatedParam.ParameterId }, cancellationToken);
baseParam.Name = updatedParam.Name;
baseParam.Value = updatedParam.Value;
}
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return NoContent();
}
}
}
@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.PayCodes;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class PayCodeMappingDetailsController : ControllerBase
{
private readonly IPayCodeMappingDetailService _payCodeMappingDetailService;
public PayCodeMappingDetailsController(IPayCodeMappingDetailService payCodeMappingDetailService)
{
_payCodeMappingDetailService = payCodeMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<PayCodeMappingDetail>> GetAll(PayCodeMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _payCodeMappingDetailService.GetPayCodeMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(PayCodeMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _payCodeMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _payCodeMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _payCodeMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class PayCodeMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public PayCodeMappingFilters FilterOptions { get; set; }
}
public class PayCodeMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public PayCodeMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.PayorTypes;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class PayorTypeMappingDetailsController : ControllerBase
{
private readonly IPayorTypeMappingDetailService _payorTypeMappingDetailService;
public PayorTypeMappingDetailsController(IPayorTypeMappingDetailService payorTypeMappingDetailService)
{
_payorTypeMappingDetailService = payorTypeMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<PayorTypeMappingDetail>> GetAll(PayorTypeMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _payorTypeMappingDetailService.GetPayorTypeMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(PayorTypeMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _payorTypeMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _payorTypeMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _payorTypeMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class PayorTypeMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public PayorTypeMappingFilters FilterOptions { get; set; }
}
public class PayorTypeMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public PayorTypeMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class PresentOnAdmissionMappingDetailsController : ControllerBase
{
private readonly IPresentOnAdmissionMappingDetailService _presentOnAdmissionMappingDetailService;
public PresentOnAdmissionMappingDetailsController(IPresentOnAdmissionMappingDetailService presentOnAdmissionMappingDetailService)
{
_presentOnAdmissionMappingDetailService = presentOnAdmissionMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<PresentOnAdmissionMappingDetail>> GetAll(PresentOnAdmissionMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _presentOnAdmissionMappingDetailService.GetPresentOnAdmissionMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(PresentOnAdmissionMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _presentOnAdmissionMappingDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpGet("[action]")]
public async Task<IEnumerable<string>> GetExports(CancellationToken cancellationToken)
{
return await _presentOnAdmissionMappingDetailService.GetExports(User?.Identity?.Name ?? "", cancellationToken);
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _presentOnAdmissionMappingDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
public class PresentOnAdmissionMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public PresentOnAdmissionMappingFilters FilterOptions { get; set; }
}
public class PresentOnAdmissionMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public PresentOnAdmissionMappingFilters FilterOptions { get; set; }
}
}
@@ -0,0 +1,60 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Strata.Stratasphere.Api.DTOs;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.Parser;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static Strata.Stratasphere.Biz.Parser.DirectedAcyclicGraph<Strata.Stratasphere.Biz.DataManagement.Models.Query>;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class ProcessGraphsController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly ILogger<ProcessGraphsController> _logger;
public ProcessGraphsController(DataManagementContext dataManagementContext, ILogger<ProcessGraphsController> logger)
{
_dataManagementContext = dataManagementContext;
_logger = logger;
}
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<GraphDto>> GetEdgesAsync(int processId, CancellationToken cancellationToken)
{
var process = await _dataManagementContext.Processes.Include(x => x.Queries)
.SingleOrDefaultAsync(x => x.ProcessId == processId, cancellationToken);
if (process == null)
{
return NotFound();
}
var graph = process.Queries.ToDirectedAcyclicGraph();
var generationalLookup = graph.GetNodeGenerationLookup();
var edges = graph.Edges.ToList();
var queriesWithNoEdges = process.Queries.Where(q => edges.All(e => e.Source != q) && edges.All(e => e.Target != q));
foreach (var orphan in queriesWithNoEdges)
{
edges.Add(new Edge(orphan, null));
}
var graphDto = new GraphDto(edges, generationalLookup);
return Ok(graphDto);
}
}
}
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class ProcessHistoryController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
public ProcessHistoryController(DataManagementContext dataManagementContext)
{
_dataManagementContext = dataManagementContext;
}
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet("{processId}")]
public async Task<IEnumerable<ProcessExecutionResult>> GetHistoryAsync(int processId, CancellationToken cancellationToken)
{
var history = await _dataManagementContext.ProcessExecutionResults.Where(x => x.ProcessId == processId)
.Include(x => x.ProcessClientExecutionResults)
.ToListAsync(cancellationToken);
return history.OrderByDescending(x => x.EndTime);
}
}
}
@@ -0,0 +1,131 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.Stratasphere.Biz.DataManagement.Models;
using Strata.Stratasphere.Biz.Processes;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ProcessJobRequest = Strata.Stratasphere.Biz.Processes.ProcessJobRequest;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class ProcessesController : ControllerBase
{
private readonly IProcessService _processService;
public ProcessesController(IProcessService processesService)
{
_processService = processesService;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IEnumerable<Process>> GetAll(CancellationToken cancellationToken)
=> await _processService.GetAll(cancellationToken);
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<IEnumerable<Query>>> GetQueries(int processId, CancellationToken cancellationToken)
{
var queries = await _processService.GetQueries(processId, cancellationToken);
if (queries == null)
{
return NotFound();
}
return Ok(queries);
}
[HttpGet("{processId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Process>> GetById(int processId, CancellationToken cancellationToken)
{
var process = await _processService.GetById(processId, cancellationToken);
if (process == null)
{
return NotFound();
}
return process;
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Process>> Create([FromBody] ProcessData process, CancellationToken cancellationToken)
=> await _processService.Create(process, User, cancellationToken);
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Process>> Copy(int processId, CancellationToken cancellationToken)
{
var process = await _processService.Copy(processId, User, cancellationToken);
if (process == null) { return NotFound(); }
return process;
}
[HttpPut("{processId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Update(int processId, ProcessData processDto, CancellationToken cancellationToken)
{
if (processId != processDto.ProcessId)
{
return BadRequest();
}
var result = await _processService.Update(processDto, User, cancellationToken);
if (result == StatusCodes.Status404NotFound) { return NotFound(); }
return Ok(true);
}
[HttpGet("{processId}/[action]")]
public async Task<bool> SaveToGithub(int processId, CancellationToken cancellationToken)
{
if (processId < 0) { return false; }
var user = User?.Identity?.Name ?? "";
return await _processService.SaveToGithub(processId, user, cancellationToken);
}
[HttpDelete("{processId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete(int processId, CancellationToken cancellationToken)
=> await _processService.Delete(processId, cancellationToken) ? NoContent() : NotFound();
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> History(int processId, CancellationToken cancellationToken)
=> Ok(await _processService.History(processId, User));
[HttpPost("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Start(int processId, ProcessJobRequest processJobDto, CancellationToken cancellationToken)
{
var jobId = await _processService.Start(processId, processJobDto, User, cancellationToken);
if (string.IsNullOrEmpty(jobId))
{
return NotFound();
}
return Ok(new { jobId });
}
}
}
@@ -0,0 +1,68 @@
using Hangfire;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Strata.Stratasphere.Biz;
using Strata.Stratasphere.Biz.DataManagement;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class PromoteProcessController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly ILogger<PromoteProcessController> _logger;
private readonly IBackgroundJobClient _backgroundJobClient;
public PromoteProcessController(DataManagementContext dataManagementContext, IBackgroundJobClient backgroundJobClient,
ILogger<PromoteProcessController> logger)
{
_dataManagementContext = dataManagementContext;
_backgroundJobClient = backgroundJobClient;
_logger = logger;
}
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Promote(int processId, CancellationToken cancellationToken)
{
var process = await _dataManagementContext.Processes.SingleOrDefaultAsync(p => p.ProcessId == processId, cancellationToken);
if (process == null)
{
return NotFound();
}
var executingUser = User?.Identity?.Name;
var jobId = _backgroundJobClient.Enqueue<PromoteJob>(p => p.PromoteProcessFromStagingToProd(process.ProcessId, process.Name, executingUser, CancellationToken.None));
return Ok(new { jobId });
}
[HttpGet("{processId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Rollback(int processId, CancellationToken cancellationToken)
{
var process = await _dataManagementContext.Processes.SingleOrDefaultAsync(p => p.ProcessId == processId, cancellationToken);
if (process == null)
{
return NotFound();
}
var executingUser = User?.Identity?.Name;
var jobId = _backgroundJobClient.Enqueue<PromoteJob>(p => p.RollbackProcess(process.ProcessId, process.Name, executingUser, CancellationToken.None));
return Ok(new { jobId });
}
}
}
@@ -0,0 +1,124 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using Strata.Stratasphere.Biz.Queries;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class QueriesController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly IQueryService _queryService;
private bool QueryExists(int queryId) => _dataManagementContext.Queries.Any(e => e.QueryId == queryId);
public QueriesController(DataManagementContext dataManagementContext, IQueryService queryService)
{
_dataManagementContext = dataManagementContext;
_queryService = queryService;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IEnumerable<Query>> GetAll(CancellationToken cancellationToken)
{
var queries = await _dataManagementContext.Queries.ToListAsync(cancellationToken);
return queries;
}
[HttpGet("{queryId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Query>> GetById(int queryId, CancellationToken cancellationToken)
{
var query = await _dataManagementContext.Queries.SingleOrDefaultAsync(p => p.QueryId == queryId, cancellationToken);
if (query == null)
{
return NotFound();
}
return query;
}
[HttpGet("{queryId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Query>> Copy(int queryId, CancellationToken cancellationToken)
{
return await _queryService.Copy(queryId, cancellationToken);
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Query>> Create([FromBody] Query query, CancellationToken cancellationToken)
{
return await _queryService.Create(query, cancellationToken);
}
[HttpPut("{queryId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Update(int queryId, Query queryDto, CancellationToken cancellationToken)
{
if (queryId != queryDto.QueryId) { return BadRequest(); }
var updated = await _queryService.Update(queryDto, cancellationToken);
if (!updated) { return NotFound(); }
return NoContent();
}
[HttpGet("{queryId}/[action]")]
public async Task<bool> SaveToGithub(int queryId, CancellationToken cancellationToken)
{
if (queryId < 0) { return false; }
var user = User?.Identity?.Name ?? "";
return await _queryService.SaveToGithub(queryId, user, cancellationToken);
}
[HttpDelete("{queryId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Delete(int queryId, CancellationToken token)
{
var query = await _dataManagementContext.Queries.SingleOrDefaultAsync(p => p.QueryId == queryId, token);
if (query == null)
{
return NotFound();
}
_dataManagementContext.Remove(query);
await _dataManagementContext.SaveChangesAsync(token);
return NoContent();
}
[HttpGet("{queryId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> History(int queryId, CancellationToken cancellationToken)
=> Ok(await _queryService.History(queryId, User?.Identity?.Name ?? ""));
}
}
@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.Stratasphere.Biz.RunnableClients;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class RunnableClientsController : ControllerBase
{
private readonly IRunnableClientsService _runnableClientsService;
public RunnableClientsController(
IRunnableClientsService runnableClientsService)
{
_runnableClientsService = runnableClientsService;
}
[HttpGet("{processId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<IEnumerable<RunnableClientDto>>> GetRunnableClientsAsync(int processId, CancellationToken cancellationToken)
{
var result = await _runnableClientsService.GetRunnableClientsAsync(processId, cancellationToken);
return Ok(result);
}
}
}
@@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.DataManagement;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class SchemasController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
public SchemasController(DataManagementContext dataManagementContext)
{
_dataManagementContext = dataManagementContext;
}
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet]
public async Task<IEnumerable<string>> GetAll(CancellationToken cancellationToken)
{
return await _dataManagementContext.Processes.Select(x => x.TargetSchema).Distinct().OrderBy(x => x).ToListAsync(cancellationToken);
}
}
}
@@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Strata.SqlTools.EntityFramework.Pagination;
using Strata.Stratasphere.Biz.Mappings.SourceSystem;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class SourceSystemMappingDetailsController : ControllerBase
{
private readonly ISourceSystemMappingDetailService _sourceSystemDetailService;
public SourceSystemMappingDetailsController(ISourceSystemMappingDetailService sourceSysemMappingDetailService)
{
_sourceSystemDetailService = sourceSysemMappingDetailService;
}
[HttpPost()]
public async Task<PagedData<SourceSystemMappingDetail>> GetAll(SourceSystemMappingDetailLoadOptions loadOptions, CancellationToken cancellationToken)
{
return await _sourceSystemDetailService.GetSourceSystemMappingDetailsAsync(loadOptions.PagingOptions, loadOptions.FilterOptions, cancellationToken);
}
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Export(SourceSystemMappingDetailExportOptions exportOptions, CancellationToken cancellationToken)
{
await _sourceSystemDetailService.ExportAsync(exportOptions.ExportAll, exportOptions.FilterOptions, User?.Identity?.Name ?? "", cancellationToken);
return new AcceptedResult();
}
[HttpPost("[action]")]
public async Task<bool> Import(IFormFile file, CancellationToken cancellationToken)
{
return await _sourceSystemDetailService.ImportAsync(file, User?.Identity?.Name ?? "", cancellationToken);
}
}
}
public class SourceSystemMappingDetailLoadOptions
{
public PagingOptions PagingOptions { get; set; }
public SourceSystemMappingFilters FilterOptions { get; set; }
}
public class SourceSystemMappingDetailExportOptions
{
public bool ExportAll { get; set; }
public SourceSystemMappingFilters FilterOptions { get; set; }
}
@@ -0,0 +1,149 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Strata.Stratasphere.Api.Dtos;
using Strata.Id.Client;
using Strata.ApiCommunication.Http.Exceptions;
using Strata.FeatureFlags.Client;
using System;
using Hangfire;
using Microsoft.Extensions.Logging;
using Strata.SMC.Client;
using Strata.Stratasphere.Biz.Standards;
using System.Threading;
using System.Text.RegularExpressions;
namespace Strata.Stratasphere.Api.Controllers
{
/// <summary>
/// The controller method for launching any jobs for standards to support data science activities
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class StandardsController : ControllerBase
{
private readonly ILogger<StandardsController> _logger;
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly ISMCServiceClient _smcServiceClient;
/// <summary>
/// C-tor
/// </summary>
/// <param name="logger">logger object</param>
/// <param name="backgroundJobClient">Hangfire job client to enqueue work</param>
/// <param name="smcServiceClient">SMC to look up client information</param>
public StandardsController(ILogger<StandardsController> logger, IBackgroundJobClient backgroundJobClient, ISMCServiceClient smcServiceClient)
{
_logger = logger;
_backgroundJobClient = backgroundJobClient;
_smcServiceClient = smcServiceClient;
}
/// <summary>
/// Refreshes patient type calculation for all encounters in the target database. The patient types defined by the data science team based on UB Revenue code
/// </summary>
/// <param name="databaseGuid">the client to process for</param>
/// <returns></returns>
[HttpPost("patienttypes/{databaseGuid}/")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> PatientTypeFullRefresh(Guid databaseGuid)
{
var dbInfo = await _smcServiceClient.GetDatabaseAsync(databaseGuid);
if (dbInfo == null)
{
return new NotFoundResult();
}
_backgroundJobClient.Enqueue<PatientTypeJob>(j => j.ProcessPatientTypesForAllEncounters(databaseGuid, dbInfo.DatabaseName, null, CancellationToken.None));
return new AcceptedResult();
}
/// <summary>
/// Refreshes encounter standards calculations in the client database for all encounters
/// </summary>
/// <param name="databaseGuid">the client to process encounter standards</param>
/// <returns></returns>
[HttpPost("encounterstandards/{databaseGuid}/")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> EncounterStandardsFullRefresh(Guid databaseGuid)
{
var dbInfo = await _smcServiceClient.GetDatabaseAsync(databaseGuid);
if (dbInfo == null)
{
return new NotFoundResult();
}
_backgroundJobClient.Enqueue<EncounterStandardsJob>(j => j.ProcessEncounterStandardsForAllEncounters(databaseGuid, dbInfo.DatabaseName, null, CancellationToken.None));
return new AcceptedResult();
}
/// <summary>
/// Refreshes readmission calculations in the client database for all encounters. Calculating the CMS rules for 30 day readmission
/// </summary>
/// <param name="databaseGuid">the client to process for</param>
/// <returns></returns>
[HttpPost("readmission/{databaseGuid}/")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> ReadmissionFullRefresh(Guid databaseGuid)
{
var dbInfo = await _smcServiceClient.GetDatabaseAsync(databaseGuid);
if (dbInfo == null)
{
return new NotFoundResult();
}
_backgroundJobClient.Enqueue<ReadmissionJob>(j => j.ProcessReadmissionsForAllEncounters(databaseGuid, dbInfo.DatabaseName, null, CancellationToken.None));
return new AcceptedResult();
}
/// <summary>
/// Refreshes the Hospital Acquired condition calculation for all encounters in a client. The HAC calc is defined by CMS
/// </summary>
/// <param name="databaseGuid"></param>
/// <returns></returns>
[HttpPost("hacs/{databaseGuid}/")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> HACsFullRefresh(Guid databaseGuid)
{
var dbInfo = await _smcServiceClient.GetDatabaseAsync(databaseGuid);
if (dbInfo == null)
{
return new NotFoundResult();
}
_backgroundJobClient.Enqueue<HACsJob>(j => j.ProcessHACsForAllEncounters(databaseGuid, dbInfo.DatabaseName, null));
return new AcceptedResult();
}
/// <summary>
/// Refreshes one of the 14 HAC calculations for all encounters in a client. The HAC calculation is defined by CMS
/// </summary>
/// <param name="databaseGuid">the client to process for</param>
/// <param name="hacName">The name of the HAC in the format HACXX (i.e. 01,14)</param>
/// <returns></returns>
[HttpPost("hacs/{databaseGuid}/{hacName}")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> HACsFullRefresh(Guid databaseGuid, string hacName)
{
var dbInfo = await _smcServiceClient.GetDatabaseAsync(databaseGuid);
if (dbInfo == null)
{
return new NotFoundResult();
}
if (!Regex.IsMatch(hacName, @"HAC[\d][\d]\b", RegexOptions.IgnoreCase))
{
return new NotFoundResult();
}
_backgroundJobClient.Enqueue<HACsJob>(j => j.ProcessSingleHACForAllEncounters(databaseGuid, hacName.ToUpper(), null, CancellationToken.None));
return new AcceptedResult();
}
}
}
@@ -0,0 +1,272 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.ClientTags;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class TagsController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly IClientTagsService _clientTagsService;
private bool TagExists(int tagId) => _dataManagementContext.Tags.Any(e => e.TagId == tagId);
public TagsController(DataManagementContext dataManagementContext,
IClientTagsService tagsService)
{
_dataManagementContext = dataManagementContext;
_clientTagsService = tagsService;
}
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet]
public async Task<IEnumerable<Tag>> GetAll(CancellationToken cancellationToken)
{
var tag = await _dataManagementContext.Tags.Include(x => x.ClientTags)
.ToListAsync(cancellationToken);
return tag;
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Tag>> Create([FromBody] Tag tag, CancellationToken cancellationToken)
{
//https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.1&tabs=visual-studio
await _dataManagementContext.Tags.AddAsync(tag, cancellationToken);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return tag;
}
[HttpGet("{tagId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Tag>> GetById(int tagId, CancellationToken cancellationToken)
{
var tag = await _dataManagementContext.Tags.Include(x => x.ClientTags)
.SingleOrDefaultAsync(x => x.TagId == tagId, cancellationToken);
if (tag == null)
{
return NotFound();
}
return tag;
}
[HttpGet("{tagId}/[action]")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<Tag>> Copy(int tagId, CancellationToken cancellationToken)
{
var tag = await _dataManagementContext.Tags.AsNoTracking()
.Include(x => x.ClientTags)
.SingleOrDefaultAsync(x => x.TagId == tagId, cancellationToken);
if (tag == null)
{
return NotFound();
}
tag.TagName = $"{tag.TagName} Copy";
tag.TagId = 0;
foreach (var clientTag in tag.ClientTags)
{
clientTag.ClientTagId = 0;
}
_dataManagementContext.Add(tag);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return tag;
}
[HttpPatch("{tagId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Patch(int tagId, [FromBody] JsonPatchDocument<Tag> patchDoc,
CancellationToken cancellationToken)
{
if (patchDoc == null)
{
return BadRequest();
}
var tag = await _dataManagementContext.Tags.SingleOrDefaultAsync(p => p.TagId == tagId, cancellationToken);
if (tag == null)
{
return NotFound();
}
patchDoc.ApplyTo(tag);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return new ObjectResult(tag);
}
[HttpPut("{tagId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Update(int tagId, Tag tagDto, CancellationToken cancellationToken)
{
if (tagId != tagDto.TagId)
{
return BadRequest();
}
var tag = await _dataManagementContext.Tags.Include(t => t.ClientTags)
.SingleOrDefaultAsync(p => p.TagId == tagId, cancellationToken);
if (tag == null)
{
return NotFound();
}
tag.TagName = tagDto.TagName;
if (tagDto.ClientTags != null)
{
foreach (var existingTag in tag.ClientTags)
{
var matching = tagDto.ClientTags.FirstOrDefault(x => x.StrataId == existingTag.StrataId && x.TagId == existingTag.TagId);
if (matching == null)
{
_dataManagementContext.ClientTags.Remove(existingTag);
}
}
foreach (var clientTag in tagDto.ClientTags)
{
var matching = tag.ClientTags.FirstOrDefault(x => x.StrataId == clientTag.StrataId && x.TagId == clientTag.TagId);
if (matching == null)
{
_dataManagementContext.ClientTags.Add(clientTag);
}
}
}
try
{
await _dataManagementContext.SaveChangesAsync(cancellationToken);
}
catch (DbUpdateConcurrencyException) when (!TagExists(tagId))
{
return NotFound();
}
return NoContent();
}
[HttpDelete("{tagId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete(int tagId, CancellationToken cancellationToken)
{
var tag = await _dataManagementContext.Tags.SingleOrDefaultAsync(p => p.TagId == tagId, cancellationToken);
if (tag == null)
{
return NotFound();
}
_dataManagementContext.Tags.Remove(tag);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return NoContent();
}
[HttpPost("{tagName}/[action]/{databaseGuid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<IActionResult> AddByDatabase(string tagName, Guid databaseGuid, CancellationToken cancellationToken)
{
var clientTagId = await _clientTagsService.AddClientTag(tagName, databaseGuid, cancellationToken);
if (clientTagId == 0) { return NotFound(); }
else if (clientTagId > 0) { return NoContent(); }
else { return Conflict(); }
}
[HttpPost("{tagName}/[action]/{strataId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<IActionResult> AddByStrataId(string tagName, int strataId, CancellationToken cancellationToken)
{
var clientTagId = await _clientTagsService.AddClientTag(tagName, strataId, cancellationToken);
if (clientTagId == 0) { return NotFound(); }
else if (clientTagId > 0) { return NoContent(); }
else { return Conflict(); }
}
[HttpDelete("{tagName}/[action]/{databaseGuid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> DeleteByDatabase(string tagName, Guid databaseGuid, CancellationToken cancellationToken)
{
if (await _clientTagsService.RemoveTag(tagName, databaseGuid, cancellationToken))
{ return NoContent(); }
return NotFound();
}
[HttpPost("{tagName}/[action]/{strataId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> DeleteByStrataId(string tagName, int strataId, CancellationToken cancellationToken)
{
if (await _clientTagsService.RemoveTag(tagName, strataId, cancellationToken))
{ return NoContent(); }
return NotFound();
}
[HttpDelete("[action]/{databaseGuid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> DeleteByDatabase(Guid databaseGuid, CancellationToken cancellationToken)
{
if (await _clientTagsService.RemoveClientTags(databaseGuid, cancellationToken))
{ return NoContent(); }
return NotFound();
}
[HttpPost("[action]/{strataId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> DeleteByStrataId(int strataId, CancellationToken cancellationToken)
{
if (await _clientTagsService.RemoveClientTags(strataId, cancellationToken))
{ return NoContent(); }
return NotFound();
}
}
}
@@ -0,0 +1,72 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Strata.CoreLib.Claims.Extensions;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using Strata.Stratasphere.Biz.Users;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class UsersController : ControllerBase
{
private readonly DataManagementContext _dataManagementContext;
private readonly IUserService _userService;
public UsersController(DataManagementContext dataManagementContext, IUserService userService)
{
_dataManagementContext = dataManagementContext;
_userService = userService;
}
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpPost("")]
public async Task EnsureUserExists(CancellationToken cancellationToken)
{
var userName = User?.Identity?.Name ?? "";
if (userName == "") return;
var userEmail = User?.GetEmail();
if (userEmail == null) return;
var existingUser = await _dataManagementContext.Users.SingleOrDefaultAsync(u => u.UserName == userName);
if (existingUser == null)
{
var user = new User()
{
UserName = userName,
Email = userEmail,
GithubToken = "",
PreviousGithubToken = ""
};
await _dataManagementContext.Users.AddAsync(user);
}
else if (string.IsNullOrEmpty(existingUser.Email) || !userEmail.Equals(existingUser.Email, StringComparison.CurrentCultureIgnoreCase))
{
existingUser.Email = userEmail;
_dataManagementContext.Users.Update(existingUser);
}
await _dataManagementContext.SaveChangesAsync();
}
[HttpGet("[action]")]
public async Task<string> GetUserName(CancellationToken cancellationToken)
=> User?.Identity?.Name;
[HttpPost("[action]")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> SetGithubToken([FromBody] string githubToken, CancellationToken cancellationToken)
{
await _userService.SaveUserGithubToken(User?.Identity?.Name, githubToken, cancellationToken);
return new AcceptedResult();
}
}
}
@@ -0,0 +1,23 @@
using Strata.Stratasphere.Biz.DataManagement.Models;
using Strata.Stratasphere.Biz.Parser;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Api.DTOs
{
public class GraphDto
{
public GraphDto(IEnumerable<DirectedAcyclicGraph<Query>.Edge> edges, IDictionary<Query, int> generationalLookup)
{
Edges = edges;
GenerationalLookup = generationalLookup.GroupBy(x => x.Value).ToDictionary(x => x.Key, x => x.Select(x => x.Key.QueryId));
MaxGeneration = GenerationalLookup.Any() ? GenerationalLookup.Max(x => x.Key) : 0;
}
public IEnumerable<DirectedAcyclicGraph<Query>.Edge> Edges { get; }
public IDictionary<int, IEnumerable<int>> GenerationalLookup { get; }
public int MaxGeneration { get; }
}
}
@@ -0,0 +1,11 @@
using Strata.Stratasphere.Biz.DataManagement.Models;
namespace Strata.Stratasphere.Api.Dtos
{
public class ParameterDto : Parameter
{
public bool IsDeleted { get; set; }
public bool IsNew { get; set; }
}
}
@@ -0,0 +1,14 @@
using AutoMapper;
using Strata.SMC.Client;
using Strata.Stratasphere.Biz.Database;
namespace Strata.Stratasphere.Api
{
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<StrataSensitiveDatabaseDto, Database>();
}
}
}
+94
View File
@@ -0,0 +1,94 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Strata.Configuration.Client.DependencyInjection;
using Strata.Logging.DependencyInjection;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.Snowflake;
using System;
using System.Diagnostics.CodeAnalysis;
namespace Strata.Stratasphere.Api
{
[ExcludeFromCodeCoverage]
public class Program
{
public static void Main(string[] args)
{
try
{
var commandLineApplication = new CommandLineApplication(false);
var doMigrate = commandLineApplication.Option(
"--ef-migrate",
"Apply entity framework migrations and exit",
CommandOptionType.NoValue);
commandLineApplication.HelpOption("-? | -h | --help");
commandLineApplication.OnExecute(() =>
{
ExecuteApp(args, doMigrate);
return 0;
});
commandLineApplication.Execute(args);
}
catch (Exception ex)
{
Log.Error(ex, "There was an unhandled exception that caused the program to crash");
//This is for serilog to ensure that all of the cached logs are flushed when the app crashes
//This is useful so we can capture logs when the application crashes during startup:
Log.CloseAndFlush();
Environment.Exit(1);
}
}
public static void ExecuteApp(string[] args, CommandOption doMigrate)
{
var webHost = CreateWebHostBuilder(args).Build();
if (doMigrate.HasValue())
{
Log.Debug("Applying Entity Framework migrations");
using var scope = webHost.Services.CreateScope();
using var context = scope.ServiceProvider.GetService<DataManagementContext>();
var snowflakeContext = scope.ServiceProvider.GetService<ISnowflakeMigrationContext>();
var hostEnv = scope.ServiceProvider.GetService<IHostEnvironment>();
try
{
context.Database.SetCommandTimeout(TimeSpan.FromMinutes(10));
context.Database.Migrate();
try
{
snowflakeContext.Migrate().GetAwaiter().GetResult();
}
catch (Exception e)
{
Log.Error(e, "Unable to apply Snowflake migrations for environment {env}", hostEnv.EnvironmentName);
}
Log.Debug("All done, closing app");
Log.CloseAndFlush();
Environment.Exit(Environment.ExitCode);
}
catch (Exception ex)
{
Log.Error(ex, "There was an unhandled exception that caused the program to crash");
Log.CloseAndFlush();
Environment.Exit(1);
}
}
// no flags provided, so just run the webhost
webHost.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStrataConfiguration()
.UseStrataLogging()
.UseStartup<Startup>();
}
}
@@ -0,0 +1,33 @@
{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
//"commandLineArgs": "--ef-migrate",
"launchBrowser": true,
"environmentVariables": {
"Hangfire__RunLocally": "true",
"AWS_Profile": "sdt-data-wrangler-Service-Role",
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Strata.Stratasphere": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"Hangfire__RunLocally": "true",
"AWS_S3_US_EAST_1_REGIONAL_ENDPOINT": "regional",
"AWS_Profile": "sdt-data-wrangler-Service-Role",
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:44302;https://localhost:44303"
}
},
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:44302",
"sslPort": 0
}
}
}
+125
View File
@@ -0,0 +1,125 @@
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Prometheus;
using Strata.ApiLib.Core.Cors.Extensions;
using Strata.ApiLib.Core.ExceptionHandling.DependencyInjection.Bootstrappers;
using Strata.ApiLib.Core.StrataAuthentication.Bootstrappers;
using Strata.ApiLib.Core.Transformers;
using Strata.Identity.Client.Constants;
using Strata.Stratasphere.Biz.Configuration;
using Strata.Stratasphere.Biz.Configuration.SignalR;
using Strata.Stratasphere.Biz.Hubs;
using Strata.SwaggerExtensions;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
namespace Strata.Stratasphere.Api
{
[ExcludeFromCodeCoverage]
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddGlobalExceptionMiddleware(Configuration);
services.AddControllers(options =>
{
//Prevent browsers from caching API responses (this addresses an IE11 issue):
options.Filters.Add(
new ResponseCacheAttribute
{
Location = ResponseCacheLocation.None,
NoStore = false,
Duration = -1
});
options.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
})
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>())
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
}).AddMvcOptions(options =>
{
options.ReturnHttpNotAcceptable = true;
options.Filters.Add(new ProducesAttribute("application/json"));
options.Filters.Add(new ConsumesAttribute("application/json"));
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder =>
{
builder
.WithOrigins("http://localhost:3000", "http://localhost:3001")
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddAutoMapper(typeof(Startup).Assembly);
services.AddSwagger(Configuration);
services.AddStrataAuthentication(Configuration);
services.AddHealthChecks();
services.AddStrataHangfire();
services.AddStratasphere(Configuration);
services.AddStrataSignalR();
services.AddStrataCors(Configuration);
services.AddHttpContextAccessor();
services.AddAuthorization(options =>
{
options.AddPolicy("StrataSphereDataManagementOnly", policy => policy.RequireRole(StrataRoles.StrataSphereDataManagement));
});
services.AddFluentEmail("noreply@notifications.stratanetwork.com");
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
app.UseGlobalExceptionMiddleware();
app.UseRouting();
app.UseStrataAuthentication();
app.UseStrataCorsPolicy(env);
if (env.IsDevelopment())
{
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints => endpoints.MapControllers().RequireAuthorization());
}
else
{
app.UseHsts();
app.UseHttpsRedirection();
app.UseEndpoints(endpoints => endpoints.MapControllers().RequireAuthorization("StrataSphereDataManagementOnly"));
}
app.UseStaticFiles();
app.UseMetricServer();
app.UseHttpMetrics();
app.ConfigureSwagger(env, provider);
app.UseHealthChecks("/health");
app.UseEndpoints(endpoints => endpoints.MapHub<HangfireHub>(HangfireHub.HubURL));
app.UseEndpoints(endpoints => endpoints.MapNotificationHub());
}
}
}
@@ -0,0 +1,67 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Remove="DTOs\DatabaseDTO.cs" />
<Compile Remove="XlsxContentResult.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.100.21" />
<PackageReference Include="FluentEmail.Mailgun" Version="3.0.2" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.10" />
<PackageReference Include="Strata.ApiLib.Core" Version="5.2.0" />
<PackageReference Include="Strata.Hangfire.AspNetCore" Version="3.0.0" />
<PackageReference Include="Strata.Identity.Client" Version="2.80.0" />
<PackageReference Include="Strata.Logging" Version="3.5.1" />
<PackageReference Include="Strata.SignalR" Version="0.3.0" />
<PackageReference Include="Strata.SwaggerExtensions" Version="2.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="prometheus-net" Version="7.0.0" />
<PackageReference Include="prometheus-net.AspNetCore" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Strata.Stratasphere.Biz\Strata.Stratasphere.Biz.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="DataMigrations\Standards_Readmission_PlannedExclusions.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="DataMigrations\Standards_Readmission_ReadmissionExclusions.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,14 @@
using FluentValidation;
using Strata.Stratasphere.Biz.DataManagement.Models;
namespace Strata.Stratasphere.Api.Validators
{
public class ProcessValidator : AbstractValidator<Process>
{
public ProcessValidator()
{
RuleFor(x => x.Name).NotEmpty().WithMessage("Please specify a name");
RuleFor(x => x.Description).NotEmpty().WithMessage("Please specify a description");
}
}
}
@@ -0,0 +1,30 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"Snowflake": {
"Url": "https://stratadev.us-east-1.privatelink.snowflakecomputing.com",
"Account": "stratadev",
"StandardsWarehouseSize": "XSMALL",
"StandardsWarehouseMaxClusterSize": "1",
"StandardsWarehouse": "STANDARDS_WH",
"AdminRoleName": "DEVADMIN",
"SphCoreRoleName": "SPHCORE"
},
"s3": {
"bucketName": "sdt-dev-data-wrangler"
},
"configuration": {
"basicAuthUsername": "BkQsRDdmdjkFNhKVuTI.TpujQJXuKhGDcV.F_hjADMRTaEUWMJnviaesoOrhhfnz",
"basicAuthPassword": "GWPIIWECDqh.hjDNdpxVEfeFe-bYFwPSx-oBGFD_od_SUQVk-QqTIkZY_NXMeqeo"
},
"StrataConfigServerBaseUrl": "https://configuration.dev.stratanetwork.net"
}
@@ -0,0 +1,19 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"Snowflake": {
"Url": "https://pda64574.us-east-1.privatelink.snowflakecomputing.com",
"Account": "pda64574", //QA
"StandardsWarehouseSize": "XSMALL",
"StandardsWarehouseMaxClusterSize": "1",
"StandardsWarehouse": "STANDARDS_WH",
"AdminRoleName": "QAADMIN",
"SphCoreRoleName": "SPHCORE"
}
}
@@ -0,0 +1,40 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"Version": "0.0.0",
"Snowflake": {
"Url": "https://strata.us-east-1.privatelink.snowflakecomputing.com",
"Account": "strata",
"RoleName": "DATAADMIN",
"Warehouse": "DATA_ANALYSIS_WH",
"StandardsWarehouseSize": "XSMALL",
"StandardsWarehouseMaxClusterSize": "1",
"StandardsWarehouse": "STANDARDS_WH",
"SphCoreRoleName": "SPHCORE"
},
"aws": {
"masterEncounterListSQSQueueName": "sdt-masterencounterlist-queue",
"snowflakeAdminSecretName": "stratareplication/snowflake/automation/connectionstring"
},
"github": {
"Repositories": [
{
"Path": "DataWrangler",
"RepositoryId": 603055704,
"RepositoryName": "data-wrangler",
"AutoMerge": true,
"Reviewers": [],
"Assignees": []
}
]
}
}
@@ -0,0 +1,17 @@
namespace Strata.Stratasphere.Biz.Administration.Clients
{
public class ClientMappingSummary
{
public string Mapping { get; set; }
public int StrataId { get; set; }
public int WithoutRollup { get; set; }
public int WithRollup { get; set; }
public double RollupPct => 1d * WithRollup / TotalRollup;
public int NotReviewed { get; set; }
public int IsReviewed { get; set; }
public double ReviewedPct => 1d * IsReviewed / TotalRollup;
public int TotalRollup { get; set; }
public int Duplicates { get; set; }
public int Waiting { get; set; }
}
}
@@ -0,0 +1,16 @@
using ClosedXML.Excel;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.AwsS3
{
public interface IS3BucketService
{
Task<IEnumerable<string>> GetAll(CancellationToken cancellationToken);
Task<Stream> DownloadFileAsync(string filename, CancellationToken cancellationToken);
Task UploadFileAsync(MemoryStream memoryStream, string fileName, string groupName, CancellationToken cancellationToken);
Task UploadFileAsync(IXLWorkbook workbook, string fileName, string groupName, CancellationToken cancellationToken);
}
}
@@ -0,0 +1,162 @@
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using ClosedXML.Excel;
using Microsoft.AspNetCore.SignalR;
using Strata.Stratasphere.Biz.Configuration;
using Strata.Stratasphere.Biz.Notification;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.AwsS3
{
public class S3BucketService : IS3BucketService
{
private readonly ITransferUtility _transferUtility;
private readonly IAmazonS3 _amazonS3Client;
private readonly IHubContext<NotificationHub, INotificationHub> _notificationHubContext;
private readonly IStrataS3TransferConfiguration _s3TransferConfiguration;
private readonly Regex _nameParser;
public S3BucketService(ITransferUtility transferUtility, IAmazonS3 amazonS3Client,
IHubContext<NotificationHub, INotificationHub> notificationHubContext,
IStrataS3TransferConfiguration s3TransferConfiguration)
{
_transferUtility = transferUtility;
_amazonS3Client = amazonS3Client;
_notificationHubContext = notificationHubContext;
_s3TransferConfiguration = s3TransferConfiguration;
// Example file names (AWS key) is in the format:
// Account_Mapping_Export_All_{username}_2022_09_12_13_45_32_3333.xlsx, OR
// Account_Mapping_Export_Not_Reviewed_{username}_2022_09_12_13_45_32_3333.xlsx
// This regex gets two parts from this:
// 1. Account_Mapping_Export
// 2. All or Nor_Reviewed
_nameParser = new Regex(@"(.*)\s+(All|Filtered List)\s+[^\d]*\s+[\d ]*(\..*)", RegexOptions.Compiled);
}
/// <summary>
/// Get the list of object keys from the S3 bucket
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<IEnumerable<string>> GetAll(CancellationToken cancellationToken)
{
var objects = await _amazonS3Client.ListObjectsAsync(_s3TransferConfiguration.BucketName, cancellationToken).ConfigureAwait(false);
return objects.S3Objects.Select(o => Path.GetFileName(o.Key));
}
/// <summary>
/// Get the response stream for a file download from S3 by key
/// </summary>
/// <param name="filename">The key (name) of the file to be downloaded from the bucket</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<Stream> DownloadFileAsync(string filename, CancellationToken cancellationToken)
{
var request = new GetObjectRequest
{
BucketName = _s3TransferConfiguration.BucketName,
Key = filename
};
GetObjectResponse response = await _amazonS3Client.GetObjectAsync(request, cancellationToken);
return response.ResponseStream;
}
/// <summary>
/// Upload a file to the S3 bucket as a memoryStream
/// </summary>
/// <param name="memoryStream"></param>
/// <param name="fileName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task UploadFileAsync(MemoryStream memoryStream, string fileName, string groupName, CancellationToken cancellationToken)
{
var exportName = _nameParser.Replace(fileName.Replace("_", " "), "$1 $2");
var fileType = _nameParser.Replace(fileName.Replace("_", " "), "$3");
var hub = _notificationHubContext.Clients.Group(exportName);
await hub.SendExportBuildingNotification(exportName, fileType, 100);
var fileTransferUtilityRequest = new TransferUtilityUploadRequest
{
BucketName = _s3TransferConfiguration.BucketName,
StorageClass = S3StorageClass.Standard,
InputStream = memoryStream,
Key = fileName,
ServerSideEncryptionMethod = ServerSideEncryptionMethod.AWSKMS
};
fileTransferUtilityRequest.Metadata.Add(nameof(groupName), groupName);
fileTransferUtilityRequest.UploadProgressEvent += OnUploadProgressEvent;
try
{
await _transferUtility.UploadAsync(fileTransferUtilityRequest, cancellationToken);
}
catch (System.Exception ex)
{
//
}
}
/// <summary>
/// Update an excel workbook to the S3 bucket to the filename (key)
/// </summary>
/// <param name="workbook"></param>
/// <param name="fileName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task UploadFileAsync(IXLWorkbook workbook, string fileName, string groupName, CancellationToken cancellationToken)
{
using var memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream);
await UploadFileAsync(memoryStream, fileName, groupName, cancellationToken);
}
/// <summary>
/// Provide a SignalR notification on the progress of the upload to the S3 bucket
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnUploadProgressEvent(object sender, UploadProgressArgs args)
{
var currentobject = sender as TransferUtilityUploadRequest;
var groupName = currentobject.Metadata["groupName"];
// Calculate a reporting reference for percentage
var modBy = (args.TotalBytes / 10000000) switch
{
<= 3 => 50, // if less or equal to 30,000,000 then notify user every 50%, else
<= 5 => 30, // if less or equal to 50,000,000 then notify user every 30%, else
<= 7 => 25, // if less or equal to 70,000,000 then notify user every 25%, else
<= 10 => 20, // if less or equal to 100,000,000 then notify user every 20%, else
<= 20 => 15, // if less or equal to 200,000,000 then notify user every 15%, else
<= 30 => 10, // if less or equal to 300,000,000 then notify user every 10%, else
<= 40 => 7, // if less or equal to 400,000,000 then notify user every 7%, else
<= 50 => 5, // if less or equal to 500,000,000 then notify user every 5%, else
<= 60 => 3, // if less or equal to 600,000,000 then notify user every 3%, else
_ => 1 // notify user every 1% of the upload
};
// Get the notification group name from the file name (key)
// Use Regex to parse the filename for the group name
var exportName = _nameParser.Replace(currentobject.Key.Replace("_", " "), "$1 $2");
var fileType = _nameParser.Replace(currentobject.Key.Replace("_", " "), "$3");
var hub = _notificationHubContext.Clients.Group(groupName);
if (args.PercentDone == 0)
{
hub.SendExportContinuesNotification(exportName, fileType, args.PercentDone);
}
else if (args.PercentDone != 100)
{
if (args.PercentDone % modBy != 0) { return; }
hub.SendExportContinuesNotification(exportName, fileType, args.PercentDone);
}
else
{
hub.SendExportReadyNotification(exportName, fileType, currentobject.Key);
}
}
}
}
@@ -0,0 +1,79 @@
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Octokit;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using Strata.Stratasphere.Biz.Github;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.ClientQueries
{
public class ClientQueryService : IClientQueryService
{
private readonly DataManagementContext _dataManagementContext;
private readonly IDataWranglerHistoryService _historyService;
private readonly ISaveToGitHubService _saveToGitHubJob;
public ClientQueryService(DataManagementContext dataManagementContext,
IDataWranglerHistoryService historyService,
ISaveToGitHubService saveToGitHubJob)
{
_dataManagementContext = dataManagementContext;
_historyService = historyService;
_saveToGitHubJob = saveToGitHubJob;
}
public async Task<ClientQuery> Create(ClientQuery clientQuery, string user, CancellationToken cancellationToken)
{
await _dataManagementContext.ClientQueries.AddAsync(clientQuery, cancellationToken);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return clientQuery;
}
public async Task<bool> SaveToGithub(int clientQueryId, string user, CancellationToken cancellationToken)
{
await _saveToGitHubJob.SaveClientQueryToGithub(clientQueryId, user);
return true;
}
public async Task<bool> Update(ClientQuery clientQuery, string user, CancellationToken cancellationToken)
{
var ClientQueryEntity = await _dataManagementContext.ClientQueries
.SingleOrDefaultAsync(p => p.ClientQueryId == clientQuery.ClientQueryId, cancellationToken);
if (ClientQueryEntity == null) { return false; }
ClientQueryEntity.StrataId = clientQuery.StrataId;
ClientQueryEntity.QueryText = clientQuery.QueryText;
ClientQueryEntity.Description = clientQuery.Description;
try
{
await _dataManagementContext.SaveChangesAsync(cancellationToken);
}
catch (DbUpdateConcurrencyException)
{
return false;
}
return true;
}
public async Task<IEnumerable<GitHubCommit>> History(int clientQueryId, string user)
=> await _historyService.ClientQueryHistory(clientQueryId, user);
public async Task<ClientQuery> Patch(int clientQueryId, [FromBody] JsonPatchDocument<ClientQuery> patchDoc, string user,
CancellationToken cancellationToken)
{
var clientQuery = await _dataManagementContext.ClientQueries.SingleOrDefaultAsync(p => p.ClientQueryId == clientQueryId, cancellationToken);
if (clientQuery == null) { return null; }
patchDoc.ApplyTo(clientQuery);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return clientQuery;
}
}
}
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.JsonPatch;
using Octokit;
using Strata.Stratasphere.Biz.DataManagement.Models;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.ClientQueries
{
public interface IClientQueryService
{
Task<ClientQuery> Create(ClientQuery clientQuery, string user, CancellationToken cancellationToken);
Task<bool> SaveToGithub(int clientQueryId, string user, CancellationToken cancellationToken);
Task<bool> Update(ClientQuery clientQuery, string user, CancellationToken cancellationToken);
Task<ClientQuery> Patch(int clientQueryId, JsonPatchDocument<ClientQuery> patchDoc, string user, CancellationToken cancellationToken);
Task<IEnumerable<GitHubCommit>> History(int clientQueryId, string user);
}
}
@@ -0,0 +1,111 @@
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.Database;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DataManagement.Models;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.ClientTags
{
public class ClientTagsService : IClientTagsService
{
private readonly DataManagementContext _dataManagementContext;
private readonly IDatabaseService _databaseService;
public ClientTagsService(
DataManagementContext dataManagementContext,
IDatabaseService databaseService)
{
_dataManagementContext = dataManagementContext;
_databaseService = databaseService;
}
public async Task<int> AddClientTag(string tagName, Guid databaseGuid, CancellationToken cancellationToken)
{
var db = await _databaseService.GetDatabaseByDatabaseGuid(databaseGuid, cancellationToken);
if (db == null) { return 0; }
var tag = await _dataManagementContext.Tags.SingleOrDefaultAsync(p => p.TagName == tagName, cancellationToken);
if (tag == null) { return 0; }
return await AddClientTag(tag, db, cancellationToken);
}
public async Task<int> AddClientTag(string tagName, int strataId, CancellationToken cancellationToken)
{
var db = await _databaseService.GetDatabaseByStrataId(strataId, cancellationToken);
if (db == null) { return 0; }
var tag = await _dataManagementContext.Tags.SingleOrDefaultAsync(p => p.TagName == tagName, cancellationToken);
if (tag == null) { return 0; }
return await AddClientTag(tag, db, cancellationToken);
}
private async Task<int> AddClientTag(Tag tag, Database.Database db, CancellationToken cancellationToken)
{
var clientTag = await _dataManagementContext.ClientTags
.SingleOrDefaultAsync(p => p.TagId == tag.TagId && p.StrataId == db.StrataId, cancellationToken);
if (clientTag != null) { return -1; }
clientTag = _dataManagementContext.ClientTags.Add(new ClientTag { StrataId = db.StrataId, TagId = tag.TagId }).Entity;
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return clientTag.ClientTagId;
}
public async Task<bool> RemoveTag(string tagName, Guid databaseGuid, CancellationToken cancellationToken)
{
var db = await _databaseService.GetDatabaseByDatabaseGuid(databaseGuid, cancellationToken);
if (db == null) { return false; }
var tag = await _dataManagementContext.Tags.SingleOrDefaultAsync(p => p.TagName == tagName, cancellationToken);
if (tag == null) { return false; }
return await RemoveTag(tag, db, cancellationToken);
}
public async Task<bool> RemoveTag(string tagName, int strataId, CancellationToken cancellationToken)
{
var db = await _databaseService.GetDatabaseByStrataId(strataId, cancellationToken);
if (db == null) { return false; }
var tag = await _dataManagementContext.Tags.SingleOrDefaultAsync(p => p.TagName == tagName, cancellationToken);
if (tag == null) { return false; }
return await RemoveTag(tag, db, cancellationToken);
}
private async Task<bool> RemoveTag(Tag tag, Database.Database db, CancellationToken cancellationToken)
{
var clientTags = await _dataManagementContext.ClientTags
.Where(ct => ct.TagId == tag.TagId && ct.StrataId == db.StrataId).ToListAsync();
_dataManagementContext.ClientTags.RemoveRange(clientTags);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return true;
}
public async Task<bool> RemoveClientTags(Guid databaseGuid, CancellationToken cancellationToken)
{
var db = await _databaseService.GetDatabaseByDatabaseGuid(databaseGuid, cancellationToken);
if (db == null) { return false; }
return await RemoveClientTags(db, cancellationToken);
}
public async Task<bool> RemoveClientTags(int strataId, CancellationToken cancellationToken)
{
var db = await _databaseService.GetDatabaseByStrataId(strataId, cancellationToken);
if (db == null) { return false; }
return await RemoveClientTags(db, cancellationToken);
}
private async Task<bool> RemoveClientTags(Database.Database db, CancellationToken cancellationToken)
{
var clientTags = await _dataManagementContext.ClientTags.Where(p => p.StrataId == db.StrataId).ToListAsync();
if (!clientTags.Any()) { return false; }
_dataManagementContext.ClientTags.RemoveRange(clientTags);
await _dataManagementContext.SaveChangesAsync(cancellationToken);
return true;
}
}
}
@@ -0,0 +1,16 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.ClientTags
{
public interface IClientTagsService
{
Task<int> AddClientTag(string tagName, Guid databaseGuid, CancellationToken cancellationToken);
Task<int> AddClientTag(string tagName, int strataId, CancellationToken cancellationToken);
Task<bool> RemoveTag(string tagName, Guid databaseGuid, CancellationToken cancellationToken);
Task<bool> RemoveTag(string tagName, int strataId, CancellationToken cancellationToken);
Task<bool> RemoveClientTags(Guid databaseGuid, CancellationToken cancellationToken);
Task<bool> RemoveClientTags(int strataId, CancellationToken cancellationToken);
}
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Configuration
{
public class AWSOptions
{
[Required(ErrorMessage = "Missing the Sqs Queue Name for listening for new encounters")]
public string MasterEncounterListSQSQueueName { get; set; }
[Required(ErrorMessage = "Missing the Snowflake Admin Secret name")]
public string SnowflakeAdminSecretName { get; set; }
}
}
@@ -0,0 +1,22 @@
namespace Strata.Stratasphere.Biz.Configuration
{
internal static class Constants
{
internal static readonly string ApplicationName = "stratasphere";
/// <summary>
/// The name of the Stratasphere Sandbox database
/// </summary>
internal const string SandboxDatabaseName = "DATALAKE_SANDBOX";
/// <summary>
/// The name of the Stratasphere Staging database
/// </summary>
internal const string StagingDatabaseName = "DATALAKE_STAGING";
/// <summary>
/// The name of the Stratasphere Production database
/// </summary>
internal const string ProductionDatabaseName = "DATALAKE_PROD";
}
}
@@ -0,0 +1,60 @@
using Hangfire.Common;
using Hangfire.Server;
using Strata.CoreLib.Claims;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Claims;
using System.Threading;
namespace Strata.Stratasphere.Biz.Configuration.Hangfire
{
/// <summary>
/// Captures Job parameters as Claims on the ThreadPrincipal running the job
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method)]
public class CaptureJobParameterAttribute : JobFilterAttribute, IServerFilter
{
public int DatabaseGuidArgumentPosition { get; set; } = -1;
public int StrataIdArgumentPosition { get; set; } = -1;
// server filters
public void OnPerforming(PerformingContext filterContext)
{
var claims = new List<Claim>();
var args = filterContext.BackgroundJob.Job.Args.ToArray();
if (StrataIdArgumentPosition >= 0)
{
var strataIdValue = string.Format(CultureInfo.CurrentCulture, $"{{{StrataIdArgumentPosition}}}", args);
if (int.TryParse(strataIdValue, out var strataId))
{
claims.Add(new Claim(StrataClaims.StrataId, strataId.ToString()));
}
}
if (DatabaseGuidArgumentPosition >= 0)
{
var databaseGuidValue = string.Format(CultureInfo.CurrentCulture, $"{{{DatabaseGuidArgumentPosition}}}", args);
if (Guid.TryParse(databaseGuidValue, out var databaseGuid))
{
claims.Add(new Claim(StrataClaims.DatabaseGuid, databaseGuid.ToString()));
}
}
if (claims.Count == 0)
{
return;
}
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "hangfire_impersonation"));
Thread.CurrentPrincipal = principal;
}
public void OnPerformed(PerformedContext filterContext)
{
Thread.CurrentPrincipal = null;
}
}
}
@@ -0,0 +1,16 @@
using Hangfire.Common;
using Hangfire.States;
namespace Strata.Stratasphere.Biz.Configuration.Hangfire
{
public class DeleteOnSuccessAttribute : JobFilterAttribute, IElectStateFilter
{
public void OnStateElection(ElectStateContext context)
{
if (context.CandidateState.Name == SucceededState.StateName)
{
context.CandidateState = new DeletedState { Reason = "This job is deleted on success." };
}
}
}
}
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Strata.Stratasphere.Biz.Notification;
namespace Strata.Stratasphere.Biz.Configuration
{
public static class HubEndpointRouteBuilderExtensions
{
public static HubEndpointConventionBuilder MapNotificationHub(this IEndpointRouteBuilder endpoints)
{
return endpoints.MapHub<NotificationHub>("/api/NotificationHub", configureOptions: null);
}
}
}
@@ -0,0 +1,10 @@
namespace Strata.Stratasphere.Biz.Configuration
{
/// <summary>
/// This provides the setting in the json file for the S3 bucket name
/// </summary>
public interface IStrataS3TransferConfiguration
{
public string BucketName { get; set; }
}
}
@@ -0,0 +1,49 @@
using System;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.StackExchangeRedis;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using Strata.ElastiCache.Redis;
using Strata.Hangfire.Configuration;
namespace Strata.Stratasphere.Biz.Configuration.SignalR
{
internal class HangfireRedisHubLifetimeManager<THub> : RedisHubLifetimeManager<THub> where THub : Hub
{
public HangfireRedisHubLifetimeManager(ILogger<RedisHubLifetimeManager<THub>> logger, IAwsRedisConfigurationOptionsFactory awsRedisConfigurationOptionsFactory, IOptions<HangfireOptions> hangfireOptions, IHubProtocolResolver hubProtocolResolver)
: base(logger,
new OptionsWrapper<RedisOptions>(new RedisOptions { Configuration = GetConfigOptions(awsRedisConfigurationOptionsFactory, hangfireOptions) }),
hubProtocolResolver)
{
}
public HangfireRedisHubLifetimeManager(ILogger<RedisHubLifetimeManager<THub>> logger, IAwsRedisConfigurationOptionsFactory awsRedisConfigurationOptionsFactory, IOptions<HangfireOptions> hangfireOptions, IHubProtocolResolver hubProtocolResolver, IOptions<HubOptions> globalHubOptions, IOptions<HubOptions<THub>> hubOptions)
: base(logger,
new OptionsWrapper<RedisOptions>(new RedisOptions { Configuration = GetConfigOptions(awsRedisConfigurationOptionsFactory, hangfireOptions) }),
hubProtocolResolver , globalHubOptions, hubOptions)
{
}
private static ConfigurationOptions GetConfigOptions(IAwsRedisConfigurationOptionsFactory awsRedisConfigurationOptionsFactory, IOptions<HangfireOptions> hangfireOptions)
{
var configOptions = awsRedisConfigurationOptionsFactory
.GetRedisConfigurationOptionsAsync("sdt-redis-hangfire-shared",
AwsRedisConfigurationOptionsFactory.GetSecretIdByDefaultFormat("common",
"sdt-redis-hangfire-shared")).GetAwaiter().GetResult();
// first set the redis prefix based on environment and if running locally
var prefix = $"{Environment.MachineName}_{hangfireOptions.Value.Schema}";
if (hangfireOptions.Value.RunLocally)
{
prefix = $"{prefix}_{Environment.MachineName.ToLowerInvariant()}";
}
configOptions.ChannelPrefix = $"{{{prefix}}}-signalr:";
return configOptions;
}
}
}
@@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
namespace Strata.Stratasphere.Biz.Configuration.SignalR
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddStrataSignalR(this IServiceCollection services)
{
services.AddSignalR().AddStrataRedis();
return services;
}
}
}
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
namespace Strata.Stratasphere.Biz.Configuration.SignalR
{
public static class SignalROptionsServiceCollectionExtensions
{
/// <summary>
/// Adds scale-out to a <see cref="ISignalRServerBuilder"/>, using a shared Redis server.
/// </summary>
/// <param name="signalrBuilder">The <see cref="ISignalRServerBuilder"/>.</param>
/// <returns>The same instance of the <see cref="ISignalRServerBuilder"/> for chaining.</returns>
public static ISignalRServerBuilder AddStrataRedis(this ISignalRServerBuilder signalrBuilder)
{
signalrBuilder.Services.AddSingleton(typeof(HubLifetimeManager<>), typeof(HangfireRedisHubLifetimeManager<>));
return signalrBuilder;
}
}
}
@@ -0,0 +1,19 @@
using System;
namespace Strata.Stratasphere.Biz.Configuration
{
public class SnowflakeEnvironmentOptions : SnowflakeLib.Configuration.SnowflakeOptions
{
public string StandardsWarehouse { get; set; }
public string StandardsWarehouseSize { get; set; }
public string StandardsWarehouseMaxClusterSize { get; set; }
public string Warehouse { get; set; }
public string RoleName { get; set; }
public string AdminRoleName { get; set; }
public string SphCoreRoleName { get; set; }
public string GetClientDatabaseName(string environmentName, Guid clientDbGuid) => $"{environmentName.Substring(0, 1)}_{clientDbGuid:N}".ToUpper();
}
}
@@ -0,0 +1,250 @@
using Amazon.S3;
using Amazon.S3.Transfer;
using Amazon.SQS;
using Hangfire;
using Hangfire.Annotations;
using Hangfire.Throttling;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Strata.Hangfire.Configuration;
using Strata.Id.Client;
using Strata.SnowflakeLib.Configuration;
using Strata.SqlTools.Configuration.Common.AsyncFactory;
using Strata.SqlTools.Configuration.Postgres;
using Strata.SqlTools.Configuration.SqlServer;
using Strata.Stratasphere.Biz.AwsS3;
using Strata.Stratasphere.Biz.ClientQueries;
using Strata.Stratasphere.Biz.ClientTags;
using Strata.Stratasphere.Biz.Configuration.SignalR;
using Strata.Stratasphere.Biz.Database;
using Strata.Stratasphere.Biz.DataManagement;
using Strata.Stratasphere.Biz.DbContexts;
using Strata.Stratasphere.Biz.Email;
using Strata.Stratasphere.Biz.Encryption;
using Strata.Stratasphere.Biz.FiscalTime;
using Strata.Stratasphere.Biz.Github;
using Strata.Stratasphere.Biz.Mappings;
using Strata.Stratasphere.Biz.Mappings.Accounts;
using Strata.Stratasphere.Biz.Mappings.Accounts.Predictions;
using Strata.Stratasphere.Biz.Mappings.Accounts.SphAccountRollup;
using Strata.Stratasphere.Biz.Mappings.AdmitType;
using Strata.Stratasphere.Biz.Mappings.AdmitType.Predictions;
using Strata.Stratasphere.Biz.Mappings.AdmitType.SphAdmitTypeRollup;
using Strata.Stratasphere.Biz.Mappings.Departments;
using Strata.Stratasphere.Biz.Mappings.Departments.Prediction;
using Strata.Stratasphere.Biz.Mappings.Departments.Predictions;
using Strata.Stratasphere.Biz.Mappings.Departments.SphDepartmentRollup;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus.Predictions;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus.SphDischargeStatusRollup;
using Strata.Stratasphere.Biz.Mappings.Exports;
using Strata.Stratasphere.Biz.Mappings.JobCodes;
using Strata.Stratasphere.Biz.Mappings.JobCodes.Predictions;
using Strata.Stratasphere.Biz.Mappings.JobCodes.SphJobCodeRollup;
using Strata.Stratasphere.Biz.Mappings.PayCodes;
using Strata.Stratasphere.Biz.Mappings.PayCodes.Predictions;
using Strata.Stratasphere.Biz.Mappings.PayCodes.SphPayCodeRollup;
using Strata.Stratasphere.Biz.Mappings.PayorTypes;
using Strata.Stratasphere.Biz.Mappings.PayorTypes.Predictions;
using Strata.Stratasphere.Biz.Mappings.PayorTypes.SphPayorTypeRollup;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission.Predictions;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission.SphPresentOnAdmissionCodeRollup;
using Strata.Stratasphere.Biz.Mappings.SourceSystem;
using Strata.Stratasphere.Biz.Mappings.SourceSystem.Predictions;
using Strata.Stratasphere.Biz.Mappings.SourceSystem.SphSourceSystemCategory;
using Strata.Stratasphere.Biz.Processes;
using Strata.Stratasphere.Biz.Queries;
using Strata.Stratasphere.Biz.RunnableClients;
using Strata.Stratasphere.Biz.Snowflake;
using Strata.Stratasphere.Biz.Standards;
using Strata.Stratasphere.Biz.Standards.Commands.StartupCommands;
using Strata.Stratasphere.Biz.Users;
using System;
using ConnectionStringBuilder = Strata.SqlTools.Configuration.Postgres.ConnectionStringBuilder;
namespace Strata.Stratasphere.Biz.Configuration
{
public static class StratasphereServiceExtensions
{
private const string CacheProviderName = "stratasphere_cache";
public static IServiceCollection AddStratasphere([NotNull] this IServiceCollection services,
IConfiguration configuration)
{
if (services == null)
throw new ArgumentNullException(nameof(services));
services.AddOptions<AWSOptions>().BindConfiguration("aws").ValidateDataAnnotations(); //bind the options for aws and validates for missing values
services.AddOptions<SnowflakeEnvironmentOptions>().BindConfiguration("Snowflake").ValidateDataAnnotations(); //bind the options for aws and validates for missing values
//Important step for In-Memory Caching
services.AddEasyCaching(options =>
{
// use memory cache with your own configuration
options.UseInMemory(config =>
{
config.EnableLogging = true;
}, CacheProviderName);
});
//hangfire
services.AddTransient<IBatchJobClient, BatchJobClient>();
services.AddTransient<IThrottlingManager, ThrottlingManager>();
services.ConfigureHangfireOptionsFromAws(options =>
{
options.Schema = Constants.ApplicationName;
});
//aws
services.AddScoped<IStrataS3TransferConfiguration, StrataS3TransferConfiguration>();
services.AddAWSService<IAmazonS3>();
services.AddSingleton<ITransferUtility, TransferUtility>();
services.AddScoped<IS3BucketService, S3BucketService>();
services.AddStrataSignalR();
services.AddTransient<IAmazonSQS, AmazonSQSClient>();
//Snowflake
services.AddSnowflake(configuration);
services.AddSingleton<SnowflakeDatalakeConnectionStringBuilderFactory>();
services.AddTransient<ISnowflakeCommandHandler, SnowflakeCommandHandler>();
services.AddTransient<ISnowflakeMigrationContext, SnowflakeMigrationContext>();
services.AddTransient<IStandardsClientValidator, StandardsClientValidator>();
services.AddScoped<IDatalakeConnection, DatalakeConnection>();
//Services
services.AddScoped<IRunnableClientsService, RunnableClientsService>();
services.AddScoped<IProcessService, ProcessService>();
services.AddScoped<IExportJobService, ExportJobService>();
services.AddScoped<IStrataS3TransferConfiguration, StrataS3TransferConfiguration>();
services.AddScoped<IEmailService, EmailService>();
services.AddScoped<IAccountService, AccountService>();
services.AddScoped<IAccountMappingService, AccountMappingService>();
services.AddScoped<ISphAccountRollupService, SphAccountRollupService>();
services.AddScoped<IAccountMappingDetailService, AccountMappingDetailService>();
services.AddScoped<IAccountMappingPredictionService, AccountMappingPredictionService>();
services.AddScoped<IDepartmentService, DepartmentService>();
services.AddScoped<IDepartmentMappingService, DepartmentMappingService>();
services.AddScoped<ISphDepartmentRollupService, SphDepartmentRollupService>();
services.AddScoped<IDepartmentMappingPredictionService, DepartmentMappingPredictionService>();
services.AddScoped<IDepartmentMappingDetailService, DepartmentMappingDetailService>();
services.AddScoped<IFiscalTimeService, FiscalTimeService>();
services.AddScoped<IJobCodeService, JobCodeService>();
services.AddScoped<IJobCodeMappingService, JobCodeMappingService>();
services.AddScoped<ISphJobCodeRollupService, SphJobCodeRollupService>();
services.AddScoped<IJobCodeMappingPredictionService, JobCodeMappingPredictionService>();
services.AddScoped<IJobCodeMappingDetailService, JobCodeMappingDetailService>();
services.AddScoped<IPayCodeService, PayCodeService>();
services.AddScoped<IPayCodeMappingService, PayCodeMappingService>();
services.AddScoped<ISphPayCodeRollupService, SphPayCodeRollupService>();
services.AddScoped<IPayCodeMappingPredictionService, PayCodeMappingPredictionService>();
services.AddScoped<IPayCodeMappingDetailService, PayCodeMappingDetailService>();
services.AddScoped<IInsurancePlanService, InsurancePlanService>();
services.AddScoped<IPayorTypeMappingService, PayorTypeMappingService>();
services.AddScoped<ISphPayorTypeService, SphPayorTypeService>();
services.AddScoped<IPayorTypeMappingPredictionService, PayorTypeMappingPredictionService>();
services.AddScoped<IPayorTypeMappingDetailService, PayorTypeMappingDetailService>();
services.AddScoped<ISourceSystemService, SourceSystemService>();
services.AddScoped<ISourceSystemMappingService, SourceSystemMappingService>();
services.AddScoped<ISphSourceSystemCategoryService, SphSourceSystemCategoryService>();
services.AddScoped<ISourceSystemMappingPredictionService, SourceSystemMappingPredictionService>();
services.AddScoped<ISourceSystemMappingDetailService, SourceSystemMappingDetailService>();
services.AddScoped<IDischargeStatusService, DischargeStatusService>();
services.AddScoped<IDischargeStatusMappingService, DischargeStatusMappingService>();
services.AddScoped<ISphDischargeStatusRollupService, SphDischargeStatusRollupService>();
services.AddScoped<IDischargeStatusMappingPredictionService, DischargeStatusMappingPredictionService>();
services.AddScoped<IDischargeStatusMappingDetailService, DischargeStatusMappingDetailService>();
services.AddScoped<IPresentOnAdmissionService, PresentOnAdmissionService>();
services.AddScoped<IPresentOnAdmissionMappingService, PresentOnAdmissionMappingService>();
services.AddScoped<ISphPresentOnAdmissionService, SphPresentOnAdmissionService>();
services.AddScoped<IPresentOnAdmissionMappingPredictionService, PresentOnAdmissionMappingPredictionService>();
services.AddScoped<IPresentOnAdmissionMappingDetailService, PresentOnAdmissionMappingDetailService>();
services.AddScoped<IAdmitTypeService, AdmitTypeService>();
services.AddScoped<IAdmitTypeMappingService, AdmitTypeMappingService>();
services.AddScoped<ISphAdmitTypeRollupService, SphAdmitTypeRollupService>();
services.AddScoped<IAdmitTypeMappingPredictionService, AdmitTypeMappingPredictionService>();
services.AddScoped<IAdmitTypeMappingDetailService, AdmitTypeMappingDetailService>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<IEncryptionService, EncryptionService>();
services.AddScoped<IDatabaseService, DatabaseService>();
services.AddScoped<IClientTagsService, ClientTagsService>();
//Add the startup commands that will run when migration is run
//Order matters and these will be executed on migrate in this order
services.AddTransient<StartupCommandBase, EnsureStandardsWarehouseCommand>();
services.AddTransient<StartupCommandBase, EnsureStandardsWarehouseGrantsCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionDatalakeProdGrantsCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionDatalakeSchemaGrantsCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionPlannedExclusionTableCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionPlannedExclusionTableGrantsCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionTriggerExclusionTableCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionTriggerExclusionTableGrantsCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionPlannedExclusionDataCommand>();
services.AddTransient<StartupDatalakeCommandBase, EnsureReadmissionTriggerExclusionDataCommand>();
//Postgres
var connectionString = ConnectionStringBuilder.Build(configuration, "dataOrchestration");
services.AddPostgres<DataManagementContext>((options, builder) =>
{
options.ConnectionString = connectionString;
});
// Jazz databases
services.AddScoped<IJazzDbContextFactory, JazzDbContextFactory>();
// Import Export Mapping Managers
services.AddTransient<IImportManager, ImportManager>();
services.AddTransient<IExportManager, ExportManager>();
//strata service clients
services.AddIdServiceClient();
services.AddCachedSmcServiceClient();
services.AddAsyncDbContextFactory<JazzDbContext>(options =>
{
options
.UseSqlServer()
.WithConnectionString((provider, cancellationToken) => provider.GetConnectionStringFromSmc(cancellationToken));
});
services.AddScoped(provider =>
{
var factory = provider.GetRequiredService<IAsyncDbContextFactory<JazzDbContext>>();
try
{
//we should think about making a repository factory classes and getting the repositories in the controllers
return factory.CreateDbContextAsync(default).GetAwaiter().GetResult();
}
catch (Exception)
{
return default;
}
});
services.AddFeatureFlagServiceClient();
services.AddSchemaServiceClient();
services.AddOptions<PredictionModelSection>().BindConfiguration("PredictionModel").ValidateDataAnnotations();
var githubSection = configuration.GetSection("github");
services.Configure<GithubSection>(githubSection);
services.AddScoped<ISaveToGitHubService, SaveToGitHubService>();
services.AddScoped<IDataWranglerHistoryService, DataWranglerHistoryService>();
services.AddScoped<IQueryService, QueryService>();
services.AddScoped<IClientQueryService, ClientQueryService>();
return services;
}
}
}
@@ -0,0 +1,332 @@
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.Administration.Clients;
using Strata.Stratasphere.Biz.DataManagement.Models;
using Strata.Stratasphere.Biz.Mappings.Accounts;
using Strata.Stratasphere.Biz.Mappings.Accounts.SphAccountRollup;
using Strata.Stratasphere.Biz.Mappings.AdmitType;
using Strata.Stratasphere.Biz.Mappings.AdmitType.SphAdmitTypeRollup;
using Strata.Stratasphere.Biz.Mappings.Departments;
using Strata.Stratasphere.Biz.Mappings.Departments.SphDepartmentRollup;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus.SphDischargeStatusRollup;
using Strata.Stratasphere.Biz.Mappings.JobCodes;
using Strata.Stratasphere.Biz.Mappings.JobCodes.SphJobCodeRollup;
using Strata.Stratasphere.Biz.Mappings.PayCodes;
using Strata.Stratasphere.Biz.Mappings.PayCodes.SphPayCodeRollup;
using Strata.Stratasphere.Biz.Mappings.PayorTypes;
using Strata.Stratasphere.Biz.Mappings.PayorTypes.SphPayorTypeRollup;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission.SphPresentOnAdmissionCodeRollup;
using Strata.Stratasphere.Biz.Mappings.SourceSystem;
using Strata.Stratasphere.Biz.Mappings.SourceSystem.SphSourceSystemCategory;
using System.Collections.Generic;
namespace Strata.Stratasphere.Biz.DataManagement
{
public class DataManagementContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Query>()
.HasIndex(p => new { p.TargetTable, p.ProcessId })
.IsUnique();
modelBuilder.Entity<Query>()
.Property(c => c.MaterializationType)
.HasConversion<int>();
modelBuilder.Entity<Process>().Property(p => p.TargetSchema).HasDefaultValue(Process.DefaultSchema);
modelBuilder.Entity<Process>()
.Property(p => p.IsGithubManaged)
.HasDefaultValue(true);
modelBuilder.Entity<AccountMappingDetail>()
.ToView("account_mapping_details")
.HasKey(amr => amr.AccountMappingId);
modelBuilder.Entity<JobCodeMappingDetail>()
.ToView("job_code_mapping_details")
.HasKey(jc => jc.JobCodeMappingId);
modelBuilder.Entity<DepartmentMappingDetail>()
.ToView("department_mapping_details")
.HasKey(jc => jc.DepartmentMappingId);
modelBuilder.Entity<PayCodeMappingDetail>()
.ToView("pay_code_mapping_details")
.HasKey(pc => pc.PayCodeMappingId);
modelBuilder.Entity<PayorTypeMappingDetail>()
.ToView("payor_type_mapping_details")
.HasKey(pc => pc.PayorTypeMappingId);
modelBuilder.Entity<SourceSystemMappingDetail>()
.ToView("source_system_mapping_details")
.HasKey(ssm => ssm.SourceSystemMappingId);
modelBuilder.Entity<PresentOnAdmissionMappingDetail>()
.ToView("present_on_admission_mapping_details")
.HasKey(poam => poam.PresentOnAdmissionMappingId);
modelBuilder.Entity<DischargeStatusMappingDetail>()
.ToView("discharge_status_mapping_details")
.HasKey(ssm => ssm.DischargeStatusMappingId);
modelBuilder.Entity<AdmitTypeMappingDetail>()
.ToView("admit_type_mapping_details")
.HasKey(atm => atm.AdmitTypeMappingId);
modelBuilder.Entity<ClientMappingSummary>()
.ToView("client_mapping_summary")
.HasKey(key => new { key.StrataId, key.Mapping });
modelBuilder.Entity<SphDischargeStatusRollup>()
.HasData(new List<SphDischargeStatusRollup>()
{
new(){ SphDischargeStatusRollupId = 0, SphDischargeStatusRollupCode = "0" ,Description = "Not Specified", Name = "0 - Not Specified"},
new(){ SphDischargeStatusRollupId = 1, SphDischargeStatusRollupCode = "ACH", Description = "Acute Care Hospital", Name = "ACH - Acute Care Hospital"},
new(){ SphDischargeStatusRollupId = 2, SphDischargeStatusRollupCode = "Exp", Description = "Expired", Name = "Exp - Expired"},
new(){ SphDischargeStatusRollupId = 3, SphDischargeStatusRollupCode = "Home", Description = "Home", Name = "Home - Home"},
new(){ SphDischargeStatusRollupId = 4, SphDischargeStatusRollupCode = "Hospice", Description = "Hospice", Name = "Hospice - Hospice"},
new(){ SphDischargeStatusRollupId = 5, SphDischargeStatusRollupCode = "Rehab", Description = "IP Rehab", Name = "Rehab - IP Rehab"},
new(){ SphDischargeStatusRollupId = 6, SphDischargeStatusRollupCode = "LTAC", Description = "LTAC", Name = "LTAC - LTAC"},
new(){ SphDischargeStatusRollupId = 7, SphDischargeStatusRollupCode = "Other", Description = "Other Healthcare Facility", Name = "Other - Other Healthcare Facility"},
new(){ SphDischargeStatusRollupId = 8, SphDischargeStatusRollupCode = "PDC", Description = "Patient Discontinued Care", Name = "PDC - Patient Discontinued Care"},
new(){ SphDischargeStatusRollupId = 9, SphDischargeStatusRollupCode = "Psych", Description = "Psych", Name = "Psych - Psych"},
new(){ SphDischargeStatusRollupId = 10, SphDischargeStatusRollupCode = "SNF", Description = "SNF", Name = "SNF - SNF"},
new(){ SphDischargeStatusRollupId = 11, SphDischargeStatusRollupCode = "UK", Description = "Unknown", Name = "UK - Unknown"}
});
modelBuilder.Entity<Process>()
.HasOne(p => p.Author)
.WithMany(b => b.Processes)
.HasForeignKey(b => b.AuthorId)
.IsRequired(false);
modelBuilder.Entity<User>()
.HasData(new List<User>()
{
new() {UserId = 1, UserName = "sdt\\xpei", Email = "xpei@stratadecision.com"},
new() {UserId = 2, UserName = "sdt\\tcleary", Email = "tcleary@stratadecision.com"},
new() {UserId = 3, UserName = "sdt\\slyons", Email = "slyons@stratadecision.com"},
new() {UserId = 4, UserName = "sdt\\mlipps", Email = "mlipps@stratadecision.com"},
new() {UserId = 5, UserName = "sdt\\ltruong", Email = "ltruong@stratadecision.com"},
new() {UserId = 6, UserName = "sdt\\cburke", Email = "cburke@stratadecision.com"},
new() {UserId = 7, UserName = "sdt\\bhu", Email = "bhu@stratadecision.com"},
new() {UserId = 8, UserName = "sdt\\tdebolt", Email = "tdebolt@stratadecision.com"},
new() {UserId = 9, UserName = "sdt\\mdraper", Email = "mdraper@stratadecision.com"},
new() {UserId = 10, UserName = "sdt\\mleitch", Email = "mleitch@stratadecision.com"}
});
modelBuilder.Entity<SphPresentOnAdmission>()
.HasData(new List<SphPresentOnAdmission>()
{
new() {
SphPresentOnAdmissionCodeRollupId = 0,
SphPoaDescription = "Not Specified",
MemberGUID = "7f745fc7-5b60-4cae-a1d1-0bd15d02e590",
SphPoaCode = "0",
SphPoaCodeRollup = "Not Specified",
SortOrder = 0 },
new() {
SphPresentOnAdmissionCodeRollupId = 1,
SphPoaDescription = "Unreported/exempt",
MemberGUID = "e3902b5e-9b8e-4d4a-85e9-1270dfc6e07b",
SphPoaCode = "1",
SphPoaCodeRollup = "Unreported/Not used",
SortOrder = 1
},
new() {
SphPresentOnAdmissionCodeRollupId = 2,
SphPoaDescription = "Yes",
MemberGUID = "a0d3e992-7fec-49b7-912b-fa7500e93373",
SphPoaCode = "Y",
SphPoaCodeRollup = "DIagnosis was present",
SortOrder = 2
},
new() {
SphPresentOnAdmissionCodeRollupId = 3,
SphPoaDescription = "No",
MemberGUID = "96f26278-aac6-4b16-abaa-9a2d38d7c615",
SphPoaCode = "N",
SphPoaCodeRollup = "Diagnosis was not present",
SortOrder = 3
},
new() {
SphPresentOnAdmissionCodeRollupId = 4,
SphPoaDescription = "Documentation undetermined",
MemberGUID = "998c145b-bbbc-42b1-81c5-6e19f8091328",
SphPoaCode = "U",
SphPoaCodeRollup = "Documentation insufficient",
SortOrder = 4
},
new() {
SphPresentOnAdmissionCodeRollupId = 5,
SphPoaDescription = "Clinically undetermined",
MemberGUID = "8b936afd-85c4-435f-bfea-b5d033991996",
SphPoaCode = "W",
SphPoaCodeRollup = "Clinically undetermined",
SortOrder = 5
}
});
modelBuilder.Entity<SphAdmitTypeRollup>()
.HasData(new List<SphAdmitTypeRollup>()
{
new() {
SphAdmitTypeRollupId = 0,
SphAdmitTypeDescription = "Not Specified",
MemberGUID = "c0ead3a0-bfc8-45ed-bae2-377954ff54dd",
SphAdmitTypeCode = "0",
SphAdmitTypeRollupName = "0 - Not Specified",
SortOrder = 0
},
new() {
SphAdmitTypeRollupId = 1,
SphAdmitTypeDescription = "Inpatient",
MemberGUID = "44A1F798-06CA-44C0-B58F-EDE981298922",
SphAdmitTypeCode = "1",
SphAdmitTypeRollupName = "1 - Inpatient",
SortOrder = 1
},
new() {
SphAdmitTypeRollupId = 2,
SphAdmitTypeDescription = "Urgent",
MemberGUID = "94c62434-c2b8-4ad3-b76f-5534912186c9",
SphAdmitTypeCode = "2",
SphAdmitTypeRollupName = "2 - Urgent",
SortOrder = 2
},
new() {
SphAdmitTypeRollupId = 3,
SphAdmitTypeDescription = "Elective",
MemberGUID = "12b13eee-fe8c-4ef8-a44f-e3a86e9adb37",
SphAdmitTypeCode = "3",
SphAdmitTypeRollupName = "3 - Elective",
SortOrder = 3
},
new() {
SphAdmitTypeRollupId = 4,
SphAdmitTypeDescription = "Newborn",
MemberGUID = "69e7c2de-bfcc-4ea9-8319-594709095201",
SphAdmitTypeCode = "4",
SphAdmitTypeRollupName = "4 - Newborn",
SortOrder = 4
},
new() {
SphAdmitTypeRollupId = 5,
SphAdmitTypeDescription = "Trauma",
MemberGUID = "D532F8BC-64E5-4301-A1C7-EA3A50FA1D90",
SphAdmitTypeCode = "5",
SphAdmitTypeRollupName = "5 - Trauma",
SortOrder = 5
},
new() {
SphAdmitTypeRollupId = 6,
SphAdmitTypeDescription = "Reserved",
MemberGUID = "047ebba4-313d-4922-8a1c-24076fb988ae",
SphAdmitTypeCode = "6",
SphAdmitTypeRollupName = "6 - Reserved",
SortOrder = 6
},
new() {
SphAdmitTypeRollupId = 7,
SphAdmitTypeDescription = "Reserved",
MemberGUID = "f7217436-7e33-49f7-bf00-44205877ee60",
SphAdmitTypeCode = "7",
SphAdmitTypeRollupName = "7 - Reserved",
SortOrder = 7
},
new() {
SphAdmitTypeRollupId = 8,
SphAdmitTypeDescription = "Reserved",
MemberGUID = "7a88491f-b472-46c3-b43a-52ad6b2ef43a",
SphAdmitTypeCode = "8",
SphAdmitTypeRollupName = "8 - Reserved",
SortOrder = 8
},
new() {
SphAdmitTypeRollupId = 9,
SphAdmitTypeDescription = "Unknown",
MemberGUID = "871e2044-a52b-489c-9710-9e71d005e75d",
SphAdmitTypeCode = "9",
SphAdmitTypeRollupName = "9 - Unknown",
SortOrder = 9
}
});
}
public DataManagementContext(DbContextOptions<DataManagementContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Intenionally left empty
}
public virtual DbSet<Process> Processes { get; set; }
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Parameter> Parameters { get; set; }
public virtual DbSet<Query> Queries { get; set; }
public virtual DbSet<ClientQuery> ClientQueries { get; set; }
public virtual DbSet<Tag> Tags { get; set; }
public virtual DbSet<ClientTag> ClientTags { get; set; }
public virtual DbSet<QueryTag> QueryTags { get; set; }
public virtual DbSet<ProcessTag> ProcessTags { get; set; }
public virtual DbSet<ProcessExecutionResult> ProcessExecutionResults { get; set; }
public virtual DbSet<ProcessClientExecutionResult> ProcessClientExecutionResults { get; set; }
public virtual DbSet<AccountMapping> AccountMappings { get; set; }
public virtual DbSet<SphAccountRollup> SphAccountRollups { get; set; }
public virtual DbSet<AccountMappingDetail> AccountMappingDetails { get; set; }
public virtual DbSet<DepartmentMapping> DepartmentMappings { get; set; }
public virtual DbSet<SphDepartmentRollup> SphDepartmentRollups { get; set; }
public virtual DbSet<DepartmentMappingDetail> DepartmentMappingDetails { get; set; }
public virtual DbSet<JobCodeMapping> JobCodeMappings { get; set; }
public virtual DbSet<SphJobCodeRollup> SphJobCodeRollups { get; set; }
public virtual DbSet<JobCodeMappingDetail> JobCodeMappingDetails { get; set; }
public virtual DbSet<PayCodeMapping> PayCodeMappings { get; set; }
public virtual DbSet<SphPayCodeRollup> SphPayCodeRollups { get; set; }
public virtual DbSet<PayCodeMappingDetail> PayCodeMappingDetails { get; set; }
public virtual DbSet<PayorTypeMapping> PayorTypeMappings { get; set; }
public virtual DbSet<SphPayorType> SphPayorTypes { get; set; }
public virtual DbSet<PayorTypeMappingDetail> PayorTypeMappingDetails { get; set; }
public virtual DbSet<SourceSystemMapping> SourceSystemMappings { get; set; }
public virtual DbSet<SphSourceSystemCategory> SphSourceSystemCategories { get; set; }
public virtual DbSet<SourceSystemMappingDetail> SourceSystemMappingDetails { get; set; }
public virtual DbSet<PresentOnAdmissionMapping> PresentOnAdmissionMappings { get; set; }
public virtual DbSet<SphPresentOnAdmission> SphPresentOnAdmissions { get; set; }
public virtual DbSet<PresentOnAdmissionMappingDetail> PresentOnAdmissionMappingDetails { get; set; }
public virtual DbSet<DischargeStatusMapping> DischargeStatusMappings { get; set; }
public virtual DbSet<SphDischargeStatusRollup> SphDischargeStatusRollups { get; set; }
public virtual DbSet<DischargeStatusMappingDetail> DischargeStatusMappingDetails { get; set; }
public virtual DbSet<AdmitTypeMapping> AdmitTypeMappings { get; set; }
public virtual DbSet<SphAdmitTypeRollup> SphAdmitTypeRollups { get; set; }
public virtual DbSet<AdmitTypeMappingDetail> AdmitTypeMappingDetails { get; set; }
public virtual DbSet<ClientMappingSummary> ClientMappingSummaries { get; set; }
}
}
@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class ClientQuery
{
public int ClientQueryId { get; set; }
public int QueryId { get; set; }
[Required(AllowEmptyStrings = false)]
public string QueryText { get; set; }
public string Description { get; set; }
public int StrataId { get; set; }
internal string MetaData()
{
return JsonConvert.SerializeObject(new
{
description = Description,
strataId = StrataId
}, Formatting.Indented);
}
}
}
@@ -0,0 +1,11 @@
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class ClientTag
{
public int ClientTagId {get; set; }
public int TagId { get; set; }
public int StrataId { get; set; }
}
}
@@ -0,0 +1,8 @@
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public enum MaterializationType
{
Table,
Ephemeral
}
}
@@ -0,0 +1,34 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class Parameter : IEquatable<Parameter>
{
public int ParameterId { get; set; }
[Required(AllowEmptyStrings = false)]
public string Name { get; set; }
[Required(AllowEmptyStrings = false)]
public string Value { get; set; }
public int ProcessId { get; set; }
[NotMapped]
public string SqlName => Name.Replace(" ", string.Empty);
public bool Equals(Parameter other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return ParameterId == other.ParameterId && Name == other.Name && ProcessId == other.ProcessId;
}
public override string ToString()
{
return Name;
}
}
}
@@ -0,0 +1,146 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public enum ProcessEnvironment
{
Sandbox,
Staging
}
public enum ScheduleInterval
{
None,
Daily,
Weekly,
Monthly
}
public enum DayOfWeek
{
Sunday = 1,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
public class Process
{
public Process() : this(1, DayOfWeek.Sunday)
{
}
public Process(int dayOfMonth, DayOfWeek dayOfWeek)
{
DayOfMonth = dayOfMonth;
DayOfWeek = dayOfWeek;
ScheduleInterval = ScheduleInterval.None;
}
public const string DefaultSchema = "DATA";
public int ProcessId { get; set; }
[Required(AllowEmptyStrings = false)]
public string Name { get; set; }
[Required(AllowEmptyStrings = false)]
public string Description { get; set; }
public ICollection<Query> Queries { get; set; }
public ICollection<Parameter> Parameters { get; set; }
public ICollection<ProcessTag> ProcessTags { get; set; }
[NotMapped]
public string Tags { get; set; }
public ProcessEnvironment Environment { get; set; }
[Required(AllowEmptyStrings = false)]
public string TargetSchema { get; set; }
public ScheduleInterval ScheduleInterval { get; set; }
public int TimeOfDay { get; set; }
public DayOfWeek DayOfWeek { get; set; }
public int DayOfMonth { get; set; }
public int? AuthorId { get; set; } = null!;
#nullable enable
[ForeignKey("AuthorId")]
public virtual User? Author { get; set; }
#nullable disable
[NotMapped]
public string AuthorName => Author?.UserName ?? "";
public bool IsGithubManaged { get; set; } = true;
public string GetCronExpression()
{
var cronTimeOfDayMinute = TimeOfDay % 2 * 30;
var cronTimeOfDayHour = TimeOfDay / 2;
string cronDayOfMonth = "*";
string cronDayOfWeek = "*";
switch (ScheduleInterval)
{
case ScheduleInterval.None:
return "";
case ScheduleInterval.Daily:
break;
case ScheduleInterval.Weekly:
cronDayOfWeek = System.Enum.GetName(typeof(Biz.DataManagement.Models.DayOfWeek), DayOfWeek).Substring(0, 3);
break;
case ScheduleInterval.Monthly:
cronDayOfMonth = DayOfMonth != 0 ? $"{DayOfMonth}" : "*";
break;
}
return $"{cronTimeOfDayMinute} {cronTimeOfDayHour} {cronDayOfMonth} * {cronDayOfWeek}";
}
internal string MetaData(IEnumerable<Tag> tags)
{
if (ScheduleInterval == ScheduleInterval.None)
{
return JsonConvert.SerializeObject(new
{
description = Description,
defaultSchema = DefaultSchema,
parameters = Parameters?.Select(p => new { name = p.Name, value = p.Value }),
environment = Enum.GetName<ProcessEnvironment>(Environment),
targetSchema = TargetSchema,
scheduleInterval = Enum.GetName<ScheduleInterval>(ScheduleInterval),
author = AuthorName,
processTags = string.Join(", ", tags.Where(t => ProcessTags.Select(qt => qt.TagId).Contains(t.TagId)).Select(t => t.TagName)),
}, Formatting.Indented);
}
return JsonConvert.SerializeObject(new
{
description = Description,
defaultSchema = DefaultSchema,
parameters = Parameters?.Select(p => new { name = p.Name, value = p.Value }),
environment = Enum.GetName<ProcessEnvironment>(Environment),
targetSchema = TargetSchema,
scheduleInterval = Enum.GetName<ScheduleInterval>(ScheduleInterval),
timeOfDay = TimeOfDay,
dayofWeek = Enum.GetName<DayOfWeek>(DayOfWeek),
dayOfMonth = DayOfMonth,
author = AuthorName,
processTags = string.Join(", ", tags.Where(t => ProcessTags.Select(qt => qt.TagId).Contains(t.TagId)).Select(t => t.TagName)),
}, Formatting.Indented);
}
}
}
@@ -0,0 +1,21 @@
using System;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class ProcessClientExecutionResult
{
public int ProcessExecutionResultId { get; set; }
public int ProcessClientExecutionResultId { get; set; }
public int ProcessId { get; set; }
public int StrataId { get; set; }
public string Error { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
}
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public enum ProcessHistoryEnvironment
{
Sandbox,
Staging,
Production,
Rollback
}
public class ProcessExecutionResult
{
public int ProcessExecutionResultId { get; set; }
public int ProcessId { get; set; }
public ProcessHistoryEnvironment Environment { get; set; }
public string EnvironmentValue => Environment.ToString();
public string StartedByUserName { get; set; }
public string ParameterJson { get; set; }
public DateTime StartTime { get; set; }
public ICollection<ProcessClientExecutionResult> ProcessClientExecutionResults { get; set; }
public bool IsErrored
{
get
{
if (Environment == ProcessHistoryEnvironment.Production || Environment == ProcessHistoryEnvironment.Rollback)
{
return false;
}
return ProcessClientExecutionResults == null || ProcessClientExecutionResults.Any(x => !string.IsNullOrEmpty(x.Error));
}
}
public string Status => IsErrored ? "Error" : "Success";
public DateTime EndTime => ProcessClientExecutionResults != null && ProcessClientExecutionResults.Any() ? ProcessClientExecutionResults.Max(x => x.EndTime) : !IsErrored ? StartTime : default;
}
}
@@ -0,0 +1,17 @@
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class ProcessTag
{
public int ProcessTagId { get; set; }
public int TagId { get; set; }
public int ProcessId { get; set; }
public ProcessTag(int processId, int tagId)
{
ProcessId = processId;
TagId = tagId;
}
}
}
@@ -0,0 +1,76 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class Query : IEquatable<Query>
{
private readonly string RollbackTable_Suffix = "_last";
public int QueryId { get; set; }
[Required(AllowEmptyStrings = false)]
public string QueryText { get; set; }
[Required(AllowEmptyStrings = false)]
public string TargetTable { get; set; }
[Required(AllowEmptyStrings = false)]
public string Description { get; set; }
public MaterializationType MaterializationType { get; set; }
public int ProcessId { get; set; }
public int DisplayOrder { get; set; }
[NotMapped]
internal string SessionTableName => TargetTable + "_temp";
public ICollection<ClientQuery> ClientQueries { get; set; }
public ICollection<QueryTag> QueryTags { get; set; }
public string GetQualifedTableName(Process process)
{
return $"{process.TargetSchema}.{TargetTable}";
}
public string GetQualifedRollbackTableName(Process process)
{
return $"{process.TargetSchema}.{TargetTable}{RollbackTable_Suffix}";
}
public string GetRollbackTableName()
{
return $"{TargetTable}{RollbackTable_Suffix}";
}
public bool Equals(Query other)
{
return other != null && QueryId == other.QueryId &&
QueryText == other.QueryText &&
TargetTable == other.TargetTable &&
MaterializationType == other.MaterializationType &&
ProcessId == other.ProcessId;
}
public override string ToString()
{
return TargetTable;
}
internal string MetaData(IEnumerable<Tag> tags)
{
return JsonConvert.SerializeObject(new
{
description = Description,
materializationType = MaterializationType.ToString(),
queryTags = string.Join(", ", tags.Where(t => QueryTags.Select(qt => qt.TagId).Contains(t.TagId)).Select(t => t.TagName))
}, Formatting.Indented);
}
}
}
@@ -0,0 +1,11 @@
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class QueryTag
{
public int QueryTagId { get; set; }
public int TagId { get; set; }
public int QueryId { get; set; }
}
}
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class Tag
{
public int TagId { get; set; }
[Required(AllowEmptyStrings = false)]
public string TagName { get; set; }
public ICollection<ClientTag> ClientTags { get; set; }
public ICollection<QueryTag> QueryTags { get; set; }
public ICollection<ProcessTag> ProcessTags { get; set; }
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace Strata.Stratasphere.Biz.DataManagement.Models
{
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string GithubToken { get; set; } = "";
public string PreviousGithubToken { get; set; }
public DateTimeOffset GithubTokenExpiry { get; set; }
[JsonIgnore]
public virtual ICollection<Process> Processes { get; set; }
}
}
@@ -0,0 +1,21 @@
using System;
namespace Strata.Stratasphere.Biz.Database
{
public class Database
{
public string ServerName { get; set; }
public string PhysicalName { get; set; }
public string DatabaseName { get; set; }
public Guid DatabaseGuid { get; set; }
public bool IsClientDb { get; set; }
public int StrataId { get; set; }
public string OrgPin { get; set; }
}
}
@@ -0,0 +1,98 @@
using EasyCaching.Core;
using Strata.FeatureFlags.Client;
using Strata.Id.Client;
using Strata.SqlTools.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Database
{
public class DatabaseService : IDatabaseService
{
private readonly string _databaseListCacheKey = "databaseList";
private readonly IEasyCachingProvider _easyCachingProvider;
private readonly IFeatureFlagServiceClient _featureFlagServiceClient;
private readonly IIdServiceClient _idServiceClient;
public DatabaseService(IEasyCachingProvider easyCachingProvider,
IFeatureFlagServiceClient featureFlagServiceClient,
IIdServiceClient idServiceClient)
{
_easyCachingProvider = easyCachingProvider;
_featureFlagServiceClient = featureFlagServiceClient;
_idServiceClient = idServiceClient;
}
public async Task<IEnumerable<Database>> GetDatabasesAsync(CancellationToken cancellationToken)
=> await GetDatabasesAsync(default, cancellationToken);
public async Task<Database> GetDatabaseByStrataId(int strataId, CancellationToken cancellationToken)
{
var databases = await GetDatabasesAsync(cancellationToken);
return databases.FirstOrDefault(database => database.StrataId == strataId);
}
public async Task<IEnumerable<Database>> GetDatabasesByStrataId(IEnumerable<int> strataIds, CancellationToken cancellationToken)
{
var databases = await GetDatabasesAsync(cancellationToken);
return databases.Where(database => strataIds.Contains(database.StrataId));
}
public async Task<Database> GetDatabaseByDatabaseGuid(Guid databaseGuid, CancellationToken cancellationToken)
{
var databases = await GetDatabasesAsync(cancellationToken);
return databases.FirstOrDefault(database => database.DatabaseGuid == databaseGuid);
}
public async Task<IEnumerable<Database>> GetDatabasesAsync(IDatabaseFilters filters, CancellationToken cancellationToken)
{
var cacheResult = await _easyCachingProvider.GetAsync(_databaseListCacheKey, async () =>
{
var dbStates = await _featureFlagServiceClient.GetClientStatesByFeatureFlagAsync("datauseaddendumexecuted");
var dbInfo = await _idServiceClient.GetStrataIds(cancellationToken);
var validDtos = new List<Database>();
foreach (var db in dbStates.Where(x => x.Enabled))
{
var strata = dbInfo.FirstOrDefault(x => x.DatabaseGUID == db.DatabaseGuid);
if (strata == null) continue;
var dto = new Database
{
DatabaseGuid = db.DatabaseGuid,
PhysicalName = strata?.PhysicalName ?? "",
DatabaseName = strata?.DatabaseName ?? "",
ServerName = strata?.ServerName ?? "",
OrgPin = strata.OrgPin,
StrataId = strata.StrataId
};
validDtos.Add(dto);
}
return validDtos;
}, TimeSpan.FromMinutes(10));
if (filters != null && cacheResult.HasValue)
{
var orgPins = filters.OrgPin?.ToLower().Split(',').Select(op => op.Trim()).Where(op => !string.IsNullOrEmpty(op)).ToList()
?? new List<string>();
var physicalName = filters.DatabaseName?.ToLower() ?? "";
var databases = cacheResult.Value;
if (orgPins.Any())
{
databases = databases.Where(db => orgPins.Contains(db.OrgPin)).ToList();
}
if (!string.IsNullOrEmpty(physicalName))
{
databases = databases.Where(db => db.PhysicalName.ToLower().Contains(physicalName)).ToList();
}
return databases;
}
return cacheResult.Value;
}
}
}
@@ -0,0 +1,8 @@
namespace Strata.Stratasphere.Biz.Database
{
public interface IDatabaseFilters
{
public string OrgPin { get; set; }
public string DatabaseName { get; set; }
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Database
{
public interface IDatabaseService
{
Task<IEnumerable<Database>> GetDatabasesAsync(CancellationToken cancellationToken);
Task<IEnumerable<Database>> GetDatabasesAsync(IDatabaseFilters filters, CancellationToken cancellationToken);
Task<Database> GetDatabaseByStrataId(int strataId, CancellationToken cancellationToken);
Task<IEnumerable<Database>> GetDatabasesByStrataId(IEnumerable<int> strataIds, CancellationToken cancellationToken);
Task<Database> GetDatabaseByDatabaseGuid(Guid databaseGuid, CancellationToken cancellationToken);
}
}
@@ -0,0 +1,13 @@
using Strata.Stratasphere.Biz.DbContexts;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Database
{
public interface IJazzDbContextFactory
{
Task<JazzDbContext> CreateContextFromDatabase(Guid databaseGuid, CancellationToken cancellationToken);
Task<string> GetConnectionString(Guid databaseGuid, CancellationToken cancellationToken);
}
}
@@ -0,0 +1,34 @@
using Strata.SMC.Client;
using Strata.Stratasphere.Biz.DbContexts;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Database
{
public class JazzDbContextFactory : IJazzDbContextFactory
{
private readonly ISMCServiceClient _smcServiceClient;
public JazzDbContextFactory(ISMCServiceClient smcServiceClient)
{
_smcServiceClient = smcServiceClient;
}
public async Task<JazzDbContext> CreateContextFromDatabase(Guid databaseGuid, CancellationToken cancellationToken = default(CancellationToken))
{
if (databaseGuid == Guid.Empty)
{
throw new ArgumentException(nameof(databaseGuid));
}
return new JazzDbContext(await GetConnectionString(databaseGuid, cancellationToken));
}
public async Task<string> GetConnectionString(Guid databaseGuid, CancellationToken cancellationToken = default(CancellationToken))
{
var db = await _smcServiceClient.GetDatabaseAsync(databaseGuid, cancellationToken);
return db.ConnectionString;
}
}
}
@@ -0,0 +1,11 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.DbContexts
{
public interface IJazzDbContext
{
Task<int> ScoreDimensionCacheRefresh(Guid dimensionGuid, CancellationToken cancellationToken);
}
}
@@ -0,0 +1,96 @@
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.FiscalTime;
using Strata.Stratasphere.Biz.Mappings;
using Strata.Stratasphere.Biz.Mappings.Accounts;
using Strata.Stratasphere.Biz.Mappings.AdmitType;
using Strata.Stratasphere.Biz.Mappings.Departments;
using Strata.Stratasphere.Biz.Mappings.DischargeStatus;
using Strata.Stratasphere.Biz.Mappings.JobCodes;
using Strata.Stratasphere.Biz.Mappings.PayCodes;
using Strata.Stratasphere.Biz.Mappings.PayorTypes;
using Strata.Stratasphere.Biz.Mappings.PresentOnAdmission;
using Strata.Stratasphere.Biz.Mappings.SourceSystem;
using Strata.Stratasphere.Biz.Mappings.SourceSystem.SphSourceSystemCategory;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.DbContexts
{
public class JazzDbContext : DbContext, IJazzDbContext
{
public JazzDbContext(DbContextOptions<JazzDbContext> options) : base(options)
{
}
public JazzDbContext(string connectionString) : base(GetOptions(connectionString)) { }
private static DbContextOptions GetOptions(string connectionString)
=> SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
public DbSet<ICD10DXCount> ICD10DXCounts { get; set; }
public DbSet<UBRevVolume> UbRevVolumes { get; set; }
public DbSet<GLAccountDollars> GLAccountDollars { get; set; }
public DbSet<JobCodeCount> JobCodeCounts { get; set; }
public DbSet<Accounting> Accounting { get; set; }
public DbSet<FiscalMonth> FiscalMonths { get; set; }
public DbSet<Account> Accounts { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<JobCode> JobCodes { get; set; }
public DbSet<PayrollData> PayrollData { get; set; }
public DbSet<PayCode> PayCodes { get; set; }
public DbSet<InsurancePlan> InsurancePlans { get; set; }
public DbSet<SPHPayorType> SPHPayorTypes { get; set; }
public DbSet<SourceSystem> SourceSystem { get; set; }
public DbSet<SphSourceSystemCategory> SphSourceSystemCategories { get; set; }
public DbSet<PresentOnAdmission> PresentOnAdmissions { get; set; }
public DbSet<DischargeStatus> DischargeStatus { get; set; }
public DbSet<AdmitType> AdmitTypes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Account>().HasAlternateKey(key => new { key.AccountId, key.AccountCode });
modelBuilder.Entity<Department>().HasAlternateKey(key => new { key.DepartmentId, key.DepartmentCode });
modelBuilder.Entity<JobCode>().HasAlternateKey(key => new { key.JobCodeId, key.JobCodeCode });
modelBuilder.Entity<PayrollData>().HasNoKey();
modelBuilder.Entity<PayCode>().HasAlternateKey(key => new { key.PayCodeId, key.Paycode });
modelBuilder.Entity<InsurancePlan>().HasAlternateKey(key => new { key.InsurancePlanId, key.InsurancePlanCode });
modelBuilder.Entity<UBRevVolume>().HasNoKey();
modelBuilder.Entity<ICD10DXCount>().HasNoKey();
modelBuilder.Entity<GLAccountDollars>().HasNoKey();
modelBuilder.Entity<JobCodeCount>().HasNoKey();
modelBuilder.Entity<Accounting>().HasNoKey();
}
public async Task<int> ScoreDimensionCacheRefresh(Guid dimensionGuid, CancellationToken cancellationToken)
{
var dimensionGuidParam = new SqlParameter("@dimensionGuid", dimensionGuid);
var isSecurityDirty = new SqlParameter("@isSecurityDirty", true);
return await Database.ExecuteSqlRawAsync("EXEC dbo.procScoreDimensionCacheRefresh @dimensionGuid=@dimensionGuid, @isSecurityDirty=@isSecurityDirty",
new[] { dimensionGuidParam, isSecurityDirty }, cancellationToken);
}
/// <summary>
/// Validate that this Jazz Context and the Strata Database are the same client
/// </summary>
/// <param name="db">The Database <see cref="Database.Database"/>that is being updated from</param>
/// <param name="timeoutMinutes">The timeout in minutes for the jazz context</param>
/// <exception cref="DatabaseContextException"></exception>
public void ValidateContextWithDb(Database.Database db, int timeoutMinutes)
{
var connection = Database.GetConnectionString();
if (!connection.Contains($"\"{db.PhysicalName}\""))
{
throw new DatabaseContextException(db.PhysicalName, connection);
}
Database.SetCommandTimeout(TimeSpan.FromMinutes(timeoutMinutes));
}
}
}
@@ -0,0 +1,17 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Strata.Stratasphere.Biz.DbContexts
{
[Table("DimSPHPayorType", Schema = "DSS")]
public class SPHPayorType
{
[Key]
public Guid MemberGuid { get; set; }
public int SphPayorTypeId { get; set; }
public string SphPayorTypeCode { get; set; }
public string SphPayorGroup { get; set; }
public string SphPayorType { get; set; }
}
}
@@ -0,0 +1,78 @@
using System;
using FluentEmail.Mailgun;
using Microsoft.EntityFrameworkCore;
using Strata.Stratasphere.Biz.DataManagement;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Email
{
public class EmailService : IEmailService
{
private readonly DataManagementContext _dataManagementContext;
public EmailService([NotNull] DataManagementContext dataManagementContext)
{
_dataManagementContext = dataManagementContext;
}
public async Task ProcessEmail(string processName, IEnumerable<string> recipients, int logId, string batchGuid)
{
var result = await _dataManagementContext.ProcessExecutionResults
.Include(r => r.ProcessClientExecutionResults)
.SingleAsync(r => r.ProcessExecutionResultId == logId);
var hasErrors = result.IsErrored;
var batchJobPage = Guid.TryParse(batchGuid, out _) ? batchGuid : "started";
var diff = result.EndTime.Subtract(result.StartTime);
var totalMinutes = diff.TotalMinutes;
if (totalMinutes > 1.0d)
{
if (hasErrors)
{
await SendPostProcessJobFailedEmail(processName, recipients, batchJobPage);
}
else
{
await SendPostProcessJobEmail(processName, recipients, batchJobPage);
}
}
}
public async Task SendPostProcessJobFailedEmail(string processName, IEnumerable<string> recipients, string batchJobPage)
{
await SendEmail(recipients,
$"Data Wrangler - {processName} failed. Please check hangfire.",
@$"<p>The process {processName} has failed. Please log into hangfire to view the result.</p>
<a href = ""https://stratasphere.prod.stratanetwork.net/dashboard/batches/{batchJobPage}""> Hangfire Job {processName} </a>");
}
public async Task SendPostProcessJobEmail(string processName, IEnumerable<string> recipients, string batchJobPage)
{
await SendEmail(recipients,
$"Data Wrangler - {processName} successfully completed.",
@$"<p>The process {processName} has successfully completed. Please log into hangfire to view the result.</p>
<a href = ""https://stratasphere.prod.stratanetwork.net/dashboard/batches/{batchJobPage}""> Hangfire Job {processName} </a>");
}
internal static async Task SendEmail(IEnumerable<string> recipients, string subject, string body)
{
var sender = new MailgunSender(
"notifications-dev.stratanetwork.com",
"key-12ea6389d906cef290ad8a0557a3a8c4"
);
FluentEmail.Core.Email.DefaultSender = sender;
var email = new FluentEmail.Core.Email()
.SetFrom("noreply@notifications.stratanetwork.com")
.To(string.Join(';', recipients.Where(r => !string.IsNullOrEmpty(r))))
.Subject(subject)
.Body(body, true);
await email.SendAsync();
}
}
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Strata.Stratasphere.Biz.Email
{
public interface IEmailService
{
Task ProcessEmail(string processName, IEnumerable<string> recipients, int logId, string batchGuid);
Task SendPostProcessJobFailedEmail(string processName, IEnumerable<string> recipients, string batchJobPage);
Task SendPostProcessJobEmail(string processName, IEnumerable<string> recipients, string batchJobPage);
}
}
@@ -0,0 +1,67 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Strata.Stratasphere.Biz.Encryption
{
public class EncryptionService : IEncryptionService
{
private readonly string _key = "babel encrypting";
public string EncryptString(string plainText)
{
if (string.IsNullOrEmpty(plainText)) { return plainText; }
byte[] iv = new byte[16];
byte[] array;
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(_key);
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
{
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
public string DecryptString(string cipherText)
{
if (string.IsNullOrEmpty(cipherText)) { return cipherText; }
byte[] iv = new byte[16];
byte[] buffer = Convert.FromBase64String(cipherText);
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(_key);
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
}
}
@@ -0,0 +1,8 @@
namespace Strata.Stratasphere.Biz.Encryption
{
public interface IEncryptionService
{
string DecryptString(string cipherText);
string EncryptString(string plainText);
}
}
@@ -0,0 +1,8 @@
namespace Strata.Stratasphere.Biz.Extensions
{
public static class BooleanExtensions
{
public static string ToYesNoString(this bool value)
=> value ? "Yes" : "No";
}
}
@@ -0,0 +1,15 @@
using Strata.SqlTools.EntityFramework.Pagination;
using System.Collections.Generic;
namespace Strata.Stratasphere.Biz.Extensions
{
public static class EmptyPageDataExtensions
{
public static PagedData<T> EmptyPageData<T>(this IEnumerable<Database.Database> databases)
=> new PagedData<T>
{
Data = new List<T>(),
Total = 0
};
}
}
@@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.Linq;
namespace Strata.Stratasphere.Biz.Extensions
{
public static class FilterExtensions
{
public static IEnumerable<string> CSVValues(this string csv)
=> csv.ToLower().Split(',').Select(csv => csv.Trim());
}
}
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Strata.Stratasphere.Biz.Extensions
{
[ExcludeFromCodeCoverage]
public static class ListExtensions
{
/// <summary>
/// Batches the source sequence into sized buckets.
/// </summary>
/// <typeparam name="TSource">Type of elements in <paramref name="source"/> sequence.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="size">Size of buckets.</param>
/// <returns>A sequence of equally sized buckets containing elements of the source collection.</returns>
/// <remarks>
/// This operator uses deferred execution and streams its results (buckets and bucket content).
/// It is also identical to <see cref="Partition{TSource}(System.Collections.Generic.IEnumerable{TSource},int)"/>.
/// </remarks>
//https://code.google.com/p/morelinq/source/browse/MoreLinq/Batch.cs
public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(this IEnumerable<TSource> source, int size)
{
return Batch(source, size, x =>
{
var enumerable = x as IList<TSource> ?? x.ToList();
return enumerable;
});
}
/// <summary>
/// Batches the source sequence into sized buckets and applies a projection to each bucket.
/// </summary>
/// <typeparam name="TSource">Type of elements in <paramref name="source"/> sequence.</typeparam>
/// <typeparam name="TResult">Type of result returned by <paramref name="resultSelector"/>.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="size">Size of buckets.</param>
/// <param name="resultSelector">The projection to apply to each bucket.</param>
/// <returns>A sequence of projections on equally sized buckets containing elements of the source collection.</returns>
/// <remarks>
/// This operator uses deferred execution and streams its results (buckets and bucket content).
/// It is also identical to <see cref="Partition{TSource}(System.Collections.Generic.IEnumerable{TSource},int)"/>.
/// </remarks>
public static IEnumerable<TResult> Batch<TSource, TResult>(this IEnumerable<TSource> source, int size,
Func<IEnumerable<TSource>, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (size <= 0) throw new ArgumentOutOfRangeException(nameof(size));
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
return BatchImpl(source, size, resultSelector);
}
private static IEnumerable<TResult> BatchImpl<TSource, TResult>(this IEnumerable<TSource> source, int size,
Func<IEnumerable<TSource>, TResult> resultSelector)
{
TSource[] bucket = null;
var count = 0;
foreach (var item in source)
{
if (bucket == null)
{
bucket = new TSource[size];
}
bucket[count++] = item;
// The bucket is fully buffered before it's yielded
if (count != size)
{
continue;
}
// Select is necessary so bucket contents are streamed too
yield return resultSelector(bucket.Select(x => x));
bucket = null;
count = 0;
}
// Return the last bucket with all remaining elements
if (bucket != null && count > 0)
{
yield return resultSelector(bucket.Take(count));
}
}
public static Dictionary<string, int> ColumnDictionary<T>(this IEnumerable<T> data)
{
return data.FirstOrDefault()?.GetType().GetProperties()
.Select((p, i) => new { i, p.Name }).ToDictionary(key => key.Name, value => value.i + 1)
?? new Dictionary<string, int>();
}
public static bool IsAny<T>(this IEnumerable<T> data)
=> data != null && data.Any();
}
}
@@ -0,0 +1,394 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Strata.Stratasphere.Biz.DbContexts;
using Strata.Stratasphere.Biz.Mappings;
using Strata.Stratasphere.Biz.Mappings.Accounts.Predictions;
using Strata.Stratasphere.Biz.RunnableClients;
using System;
using System.Collections.Generic;
using System.Linq;
using Process = Strata.Stratasphere.Biz.DataManagement.Models.Process;
using Query = Strata.Stratasphere.Biz.DataManagement.Models.Query;
namespace Strata.Stratasphere.Biz.Extensions
{
internal static class LogUtilsExtensions
{
public static Dictionary<string, object> DatabaseDictionary(this Database.Database database, string service)
{
var dictionary = new Dictionary<string, object> { { "service", service } };
if (database != null)
{
dictionary.Add("db", new Dictionary<string, object> {
{ "guid", database.DatabaseGuid },
{ "instance", database.PhysicalName },
{ "server", database.ServerName },
{ "strata_id", database.StrataId },
{ "org_pin", database.OrgPin },
{ "name", database.DatabaseName }
});
}
return dictionary;
}
/// <summary>
/// <para>
/// This turns the dbContext connction string into a dictionary of elements.
/// </para>
/// <para>
/// It splits the string by semi-colons, then splits each of those by the equal symbol.
/// </para>
/// <para>
/// The left side is the dictionary key, the right side is the dictionary value, ignoring the Password (if present).
/// </para>
/// </summary>
/// <param name="dbContext"></param>
/// <returns></returns>
public static Dictionary<string, object> DbContextDictionary(this DatabaseFacade dbContext)
{
var dictionary = dbContext?.GetConnectionString().Split(';')
.Select(x => x.Split('='))
.Select(y => new { key = y[0].Replace(" ", ""), value = y[1] })
.Where(x => !new[] { "password" }.Contains(x.key.ToLowerInvariant()))
.ToDictionary(x => x.key, x => x.value) ?? new Dictionary<string, string>();
return new Dictionary<string, object> { { "dbContext", dictionary } };
}
public static void LogMappingJobError<T>(this ILogger<T> _logger, Exception ex, Database.Database database, string jobName)
=> _logger.LogMappingError<T>(ex, database, $"{jobName} Job Failed");
public static void LogMappingCodesRemoved<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<string> codes)
=> _logger.LogMappingJobInfo(database, codes, "Codes were removed from the client");
public static void LogMappingMissingRollups<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<string> codes)
=> _logger.LogMappingJobInfo(database, codes, "Rollups not found for these codes");
public static void LogMappingUpdatedCodes<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<string> codes)
=> _logger.LogMappingJobInfo(database, codes, "Codes to update in Jazz");
private static void LogMappingJobInfo<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<string> codes, string message)
{
message = $"{codes?.Count() ?? 0} {message} on {database.DatabaseName}";
var scopeDictionary = database.DatabaseDictionary(typeof(T).Name)
.Union(new Dictionary<string, object> { { "message", message }, { "codes", codes?.OrderBy(code => code) } });
using (_logger.BeginScope(scopeDictionary))
_logger.LogInformation(message);
}
public static void LogPredictionWithNoMatchingRollup<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<GLAccountClassification> predictions)
=> _logger.LogMappingJobPredictionInfo(database, predictions, "Prediction(s) had no matching rollups, cannot assign a rollup id.");
private static void LogMappingJobPredictionInfo<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<GLAccountClassification> predictions, string message)
{
message = $"{predictions?.Count() ?? 0} {message} on {database.DatabaseName}";
var predictionJson = predictions?.OrderBy(prediction => prediction.AccountId).Select(prediction => JsonConvert.SerializeObject(prediction));
var scopeDictionary = database.DatabaseDictionary(typeof(T).Name)
.Union(new Dictionary<string, object> {
{ "message", message },
{ "predictions", predictions?.OrderBy(prediction => prediction.AccountId)
.Select(prediction => new Dictionary<string, object> {
{ "AccountId", prediction.AccountId },
{ "Description", prediction.Description },
{ "Prediction", prediction.Prediction },
{ "Probability", prediction.Probability }
}
)}
});
using (_logger.BeginScope(scopeDictionary))
_logger.LogInformation(message);
}
public static void LogMappingMetaDataError<T>(this ILogger<T> _logger, Exception ex, Database.Database database, string sql, string query)
{
var meta = new Dictionary<string, object> { { "query", sql } };
using (_logger.BeginScope(database.DatabaseDictionary(typeof(T).Name).Union(meta)))
_logger.LogError(ex, query);
}
public static void LogMappingError<T>(this ILogger<T> _logger, Exception ex, Database.Database database, string jobName)
{
using (_logger.BeginScope(database.DatabaseDictionary(typeof(T).Name)))
_logger.LogError(ex, jobName);
}
public static void LogJazzUpdateError<T>(this ILogger<T> _logger, Exception ex, Database.Database database, DatabaseFacade dbContext, string jobName)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Union(dbContext.DbContextDictionary());
using (_logger.BeginScope(dictionary))
_logger.LogError(ex, jobName);
}
public static void LogJazzUpdateInfo<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext, string message)
=> _logger.LogJazzUpdateInfo(database, dbContext.Database, message);
public static void LogJazzUpdateInfo<T>(this ILogger<T> _logger, Database.Database database, DatabaseFacade dbContext, string message)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Union(dbContext.DbContextDictionary());
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
public static void LogJazzUpdateAwaitingUpdate<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<string> codes)
=> _logger.LogJazzUpdateDetails(database, codes, "Items awaiting jazz update");
public static void LogJazzUpdateAwaitingUpdate<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<int> ids)
=> _logger.LogJazzUpdateDetails(database, ids, "Items awaiting jazz update");
public static void LogJazzUpdateAwaitingReset<T>(this ILogger<T> _logger, Database.Database database, IEnumerable<string> codes)
=> _logger.LogJazzUpdateDetails(database, codes, "Items awaiting jazz update, reset to false");
public static void LogJazzUpdateCodesNotFound<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext,
IEnumerable<string> codes)
=> _logger.LogJazzUpdateDetails(database, dbContext, codes, "Codes not found");
public static void LogJazzUpdateNotChanged<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext,
IEnumerable<LogInfo> items)
=> _logger.LogJazzUpdateDetails(database, dbContext, items, "Not Changed");
public static void LogJazzUpdateIdChanged<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext,
IEnumerable<LogInfo> items)
=> _logger.LogJazzUpdateDetails(database, dbContext, items, "Id Changed");
public static void LogJazzUpdateUpdated<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext,
IEnumerable<LogInfo> items)
=> _logger.LogJazzUpdateDetails(database, dbContext, items, "Updated");
private static void LogJazzUpdateDetails<T>(this ILogger<T> _logger, Database.Database database,
IEnumerable<LogInfo> items, string context)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Add(context.Replace(" ", "_").ToLower(),
items.OrderBy(item => item.Code).Select(item => item.KeyValuePairs));
var message = $"{items.Count()} Items {context} on {database.DatabaseName}";
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
private static void LogJazzUpdateDetails<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext,
IEnumerable<LogInfo> items, string context)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Union(dbContext.Database.DbContextDictionary());
dictionary.Add(context.Replace(" ", "_").ToLower(),
items.OrderBy(item => item.Code).Select(item => item.KeyValuePairs));
var message = $"{items.Count()} Items {context} on {database.DatabaseName}";
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
private static void LogJazzUpdateDetails<T>(this ILogger<T> _logger, Database.Database database, JazzDbContext dbContext,
IEnumerable<string> codes, string context)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Union(dbContext.Database.DbContextDictionary());
dictionary.Add(context.Replace(" ", "_").ToLower(),
codes.OrderBy(code => code).Select(item => item));
using (_logger.BeginScope(dictionary))
_logger.LogInformation($"{codes.Count()} Items {context} on {database.DatabaseName}");
}
private static void LogJazzUpdateDetails<T>(this ILogger<T> _logger, Database.Database database,
IEnumerable<string> codes, string context)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Add(context.Replace(" ", "_").ToLower(),
codes.OrderBy(code => code).Select(item => item));
using (_logger.BeginScope(dictionary))
_logger.LogInformation($"{codes.Count()} Items {context} on {database.DatabaseName}");
}
private static void LogJazzUpdateDetails<T>(this ILogger<T> _logger, Database.Database database,
IEnumerable<int> ids, string context)
{
var dictionary = database.DatabaseDictionary(typeof(T).Name);
dictionary.Add(context.Replace(" ", "_").ToLower(),
ids.OrderBy(id => id).Select(item => item));
using (_logger.BeginScope(dictionary))
_logger.LogInformation($"{ids.Count()} Items {context} on {database.DatabaseName}");
}
public static void LogProcessInfo<T>(this ILogger<T> _logger, Process process, string message)
{
var dictionary = new Dictionary<string, object> { { "service", typeof(T).Name },
{ "process", new Dictionary<string, object>{
{ "id", process.ProcessId },
{ "name", process.Name } }
} };
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
public static void LogProcessRunnables<T>(this ILogger<T> _logger, Process process, IEnumerable<RunnableClientDto> runnables, string message)
{
var dictionary = new Dictionary<string, object> { { "service", typeof(T).Name },
{ "process", new Dictionary<string, object>{
{ "id", process.ProcessId },
{ "name", process.Name } }
},
{ "runnables", runnables.OrderBy(r => r.Index).Select(r => r.KeyValuePairs) } };
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
public static void LogProcessRunnables<T>(this ILogger<T> _logger, int processId, string processName, IEnumerable<RunnableClientDto> runnables, string message)
{
var dictionary = new Dictionary<string, object> { { "service", typeof(T).Name },
{ "process", new Dictionary<string, object>{
{ "id", processId },
{ "name", processName } }
},
{ "runnables", runnables.OrderBy(r => r.Index).Select(r => r.KeyValuePairs) } };
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
public static void LogUnrunnableIds<T>(this ILogger<T> _logger, Process process, IEnumerable<int> strataIds, string message)
{
var dictionary = new Dictionary<string, object> { { "service", typeof(T).Name },
{ "process", new Dictionary<string, object>{
{ "id", process.ProcessId },
{ "name", process.Name } }
},
{ "strataIds", strataIds } };
using (_logger.BeginScope(dictionary))
_logger.LogInformation(message);
}
public static void LogServiceError<T>(this ILogger<T> _logger, Exception ex, string message)
{
using (_logger.BeginScope(new Dictionary<string, object> { { "service", typeof(T).Name } }))
_logger.LogError(ex, message);
}
public static void LogServiceError<T>(this ILogger<T> _logger, Exception ex, string query, string message)
{
using (_logger.BeginScope(new Dictionary<string, object>
{
{ "service", typeof(T).Name },
{ "query", query }
}))
_logger.LogError(ex, message);
}
public static void LogDebugInfo<T>(this ILogger<T> _logger, Database.Database db, string fileName, string message)
{
var dbDictionary = db.DatabaseDictionary(typeof(T).Name);
dbDictionary.Add("fileName", fileName);
using (_logger.BeginScope(dbDictionary))
_logger.LogInformation(message);
}
public static void LogDebugInfo<T>(this ILogger<T> _logger, string fileName, string message)
=> _logger.LogDebugInfo(null, fileName, message);
public static void LogImportError<T>(this ILogger<T> _logger, Exception ex, Database.Database db, string fileName, string message)
{
var dbDictionary = db.DatabaseDictionary(typeof(T).Name);
dbDictionary.Add("fileName", fileName);
using (_logger.BeginScope(dbDictionary))
_logger.LogError(ex, message);
}
public static void LogImportError<T>(this ILogger<T> _logger, Exception ex, string fileName, string message)
=> _logger.LogImportError(ex, null, fileName, message);
public static void LogImportError<T>(this ILogger<T> _logger, string fileName, IEnumerable<IMapping> batch, Database.Database db, string message)
{
var dictionary = db.DatabaseDictionary(typeof(T).Name);
dictionary.GetBatchDictionary(batch)
.Add("fileName", fileName);
using (_logger.BeginScope(dictionary))
_logger.LogError(message);
}
public static void LogImportError<T>(this ILogger<T> _logger, Exception ex, string fileName, IEnumerable<object> batch, Database.Database db, string message)
{
var dictionary = db.DatabaseDictionary(typeof(T).Name);
dictionary.GetBatchDictionary(batch)
.Add("fileName", fileName);
using (_logger.BeginScope(dictionary))
_logger.LogError(ex, message);
}
private static Dictionary<string, object> GetBatchDictionary(this Dictionary<string, object> dictionary, IEnumerable<object> batch)
{
dictionary.Add("batch", JsonConvert.SerializeObject(batch, Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
return dictionary;
}
public static void LogPredictionServiceError<T>(this ILogger<T> _logger, Exception ex, string prediction, string orgPin, int strataId)
{
var dictionary = new Dictionary<string, object>
{
{ "strataId", strataId },
{ "orgPin", orgPin }
};
using (_logger.BeginScope(new Dictionary<string, object> { { "service", typeof(T).Name }, { "db", dictionary } }))
_logger.LogError(ex, "{prediction} Prediction failed.", new[] { prediction });
}
public static void LogGithubUserTokenMissing<T>(this ILogger<T> _logger, string user, Process process)
{
using (_logger.BeginScope(new Dictionary<string, object>
{
{ "service", typeof(T).Name },
{ "user", user },
{ "process", JsonConvert.SerializeObject(process) }
}))
_logger.LogInformation("User '{user}' doesn't have a github token.", new[] { user });
}
public static void LogGithubUserTokenMissing<T>(this ILogger<T> _logger, string user, Query query)
{
using (_logger.BeginScope(new Dictionary<string, object>
{
{ "service", typeof(T).Name },
{ "user", user },
{ "query", JsonConvert.SerializeObject(query) }
}))
_logger.LogInformation("User '{user}' doesn't have a github token.", new[] { user });
}
}
public class LogInfo
{
public string Code { get; set; }
public int RollupId { get; set; }
public string RollupCode { get; set; }
public string Name { get; set; }
public bool IsValidated { get; set; }
public LogInfo(string code, int rollupId, string name, bool isValidated)
{
Code = code;
RollupId = rollupId;
Name = name;
IsValidated = isValidated;
}
public LogInfo(string code, string rollupCode, string name, bool isValidated)
{
Code = code;
RollupCode = rollupCode;
Name = name;
IsValidated = isValidated;
}
public Dictionary<string, object> KeyValuePairs
=> RollupCode == null ? new()
{
{ "code", Code } ,
{ "rollupId", RollupId},
{ "name", Name },
{ "isValidated", IsValidated }
} : new()
{
{ "code", Code } ,
{ "rollupCode", RollupCode},
{ "name", Name },
{ "isValidated", IsValidated }
};
}
}

Some files were not shown because too many files have changed in this diff Show More