This commit is contained in:
SchreiberM 2024-03-20 10:34:25 +01:00
commit c30f11b82e
31 changed files with 423 additions and 307 deletions

View File

@ -146,4 +146,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -177,7 +177,6 @@ Public Class FilesystemEx
''' somestring~3 --> somestring~3 --> ['somestring', '3'] --> version 3
''' </example>
''' <param name="pString">The string to versioned</param>
''' <param name="pSeparator">The character to split at</param>
''' <returns>Tuple of string and version</returns>
Public Function GetVersionedString(pString As String) As Tuple(Of String, Integer)
Dim oSplitString = pString.Split(VERSION_SEPARATOR).ToList()
@ -265,7 +264,7 @@ Public Class FilesystemEx
_Logger.Warn("Deleting files was aborted at file {0}.", oFile.FullName)
Return False
End If
oUnableToDeleteCounter = oUnableToDeleteCounter + 1
oUnableToDeleteCounter += 1
_Logger.Warn("File {0} could not be deleted!")
End Try
Next

View File

@ -65,6 +65,30 @@ Public Module ModuleExtensions
Return (pString.Trim().ToLower() = "true") OrElse (pString.Trim() = "1")
End Function
''' <summary>
''' Checks if a string is null or empty
''' </summary>
''' <param name="pString">The input string</param>
''' <returns>True string is null or empty, otherwise false.</returns>
<Extension()>
Public Function IsNullOrEmpty(pString As String) As Boolean
Return String.IsNullOrEmpty(pString)
End Function
''' <summary>
''' Checks if a string is NOT null or empty
''' </summary>
''' <param name="pString">The input string</param>
''' <returns>True string is null or empty, otherwise false.</returns>
<Extension()>
Public Function IsNotNullOrEmpty(pString As String) As Boolean
If String.IsNullOrEmpty(pString) Then
Return False
Else
Return True
End If
End Function
' ======================================================
' === DICTIONARY
' ======================================================

View File

@ -119,9 +119,9 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Encryption\Encryption.vbproj">
<ProjectReference Include="..\Encryption\NNEncryption.vbproj">
<Project>{8a8f20fc-c46e-41ac-bee7-218366cfff99}</Project>
<Name>Encryption</Name>
<Name>NNEncryption</Name>
</ProjectReference>
<ProjectReference Include="..\Logging\Logging.vbproj">
<Project>{903b2d7d-3b80-4be9-8713-7447b704e1b0}</Project>
@ -129,4 +129,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -146,9 +146,9 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Encryption\Encryption.vbproj">
<ProjectReference Include="..\Encryption\NNEncryption.vbproj">
<Project>{8a8f20fc-c46e-41ac-bee7-218366cfff99}</Project>
<Name>Encryption</Name>
<Name>NNEncryption</Name>
</ProjectReference>
<ProjectReference Include="..\Logging\Logging.vbproj">
<Project>{903b2d7d-3b80-4be9-8713-7447b704e1b0}</Project>
@ -164,4 +164,7 @@
<Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
</Target>
<Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -3,7 +3,6 @@ Imports DigitalData.Modules.EDMI.API
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language.Utils
Public Class DatabaseWithFallback
Private ReadOnly _Logger As Logger

View File

@ -314,4 +314,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -37,23 +37,22 @@ Public Class ActiveDirectoryInterface
_logger.Info("Using RootPath {0}", _rootPath)
End Sub
Public Function SyncUsersForGroup(GroupName As String, Firebird As Firebird, MSSQL As MSSQLServer) As List(Of ADUser)
Public Function SyncUsersForGroup(GroupName As String, MSSQL As MSSQLServer) As List(Of ADUser)
Try
Return SyncUsersForGroup(GroupName, New List(Of AttributeMapping), Firebird, MSSQL)
Return SyncUsersForGroup(GroupName, New List(Of AttributeMapping), MSSQL)
Catch ex As Exception
_logger.Error(ex)
Return Nothing
End Try
End Function
Public Function SyncUsersForGroup(GroupName As String, AttributeMappings As List(Of AttributeMapping), Firebird As Firebird, MSSQL As MSSQLServer, Optional Filter As String = DEFAULT_USER_FILTER) As List(Of ADUser)
Public Function SyncUsersForGroup(GroupName As String, AttributeMappings As List(Of AttributeMapping), MSSQL As MSSQLServer, Optional Filter As String = DEFAULT_USER_FILTER) As List(Of ADUser)
Dim oUsers As New List(Of ADUser)
Dim oSyncedUsers As New List(Of ADUser)
Dim oGroupId As Int64 = Nothing
Dim oFirebirdSync As New SyncUsers.SyncUsersFirebird(_logConfig, Firebird)
Dim oSQLSync As New SyncUsers.SyncUsersMSSQL(_logConfig, MSSQL)
Dim oSyncedUsersFirebird, oSyncedUsersMSSQL As List(Of ADUser)
Dim oSyncedUsersMSSQL As List(Of ADUser)
Try
_logger.Debug("Fetching users from ActiveDirectory")
@ -64,16 +63,6 @@ Public Class ActiveDirectoryInterface
Return Nothing
End Try
' Do the actual sync into firebird
If Firebird IsNot Nothing Then
oSyncedUsersFirebird = oFirebirdSync.SyncUsers(GroupName, oUsers, AttributeMappings)
If oSyncedUsersFirebird.Count > 0 Then
_logger.Debug("Synced {0} users to Firebird", oSyncedUsersFirebird.Count)
End If
Else
_logger.Debug("SyncUsersForGroup: _firebird is nothing. ")
End If
' Do the actual sync into MSSQL
If MSSQL IsNot Nothing Then
oSyncedUsersMSSQL = oSQLSync.SyncUsers(GroupName, oUsers, AttributeMappings)
@ -81,7 +70,7 @@ Public Class ActiveDirectoryInterface
_logger.Debug("Synced {0} users to MSSQLServer", oSyncedUsersMSSQL.Count)
End If
Else
_logger.Debug("SyncUsersForGroup: _mssql is nothing. ")
_logger.Debug("SyncUsersForGroup: _mssql is nothing.")
End If
Return oUsers

View File

@ -1,145 +0,0 @@
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Logging
Namespace SyncUsers
Public Class SyncUsersFirebird
Implements ISyncUsers
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Private ReadOnly _firebird As Database.Firebird
Public Sub New(LogConfig As LogConfig, Firebird As Database.Firebird)
_logConfig = LogConfig
_logger = LogConfig.GetLogger()
_firebird = Firebird
End Sub
Public Function SyncUsers(GroupName As String, Users As List(Of ADUser), PropertyMapping As List(Of AttributeMapping)) As List(Of ADUser) Implements ISyncUsers.SyncUsers
Dim oGroupId As Integer
Dim oSyncedUsers As New List(Of ADUser)
Try
_logger.Debug("Getting group Id for group [{0}]", GroupName)
oGroupId = GetGroupId(GroupName)
If oGroupId = 0 Then
_logger.Debug("Group [{0}] does not exist in database or is not enabled for sync.", GroupName)
Return oSyncedUsers
End If
_logger.Debug("Using group Id [{0}]", oGroupId)
Catch ex As Exception
_logger.Error(ex)
Return oSyncedUsers
End Try
For Each oUser In Users
Dim oUserId As Int64
Dim oUserExists As Boolean = False
' Check if user already exists
Try
_logger.Debug("Checking if user [{0}] exists", oUser)
oUserId = GetUserId(oUser.samAccountName)
oUserExists = Not IsNothing(oUserId)
_logger.Debug("User [{0}] exists in database: ", oUser, oUserExists)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not get UserId for user. Skipping")
Continue For
End Try
' I user does not exist, create a new user
Try
If Not oUserExists Then
_logger.Debug("Creating new user for [{0}]", oUser)
oUserId = CreateUser(oUser)
_logger.Debug("User created with Id [{0}]", oUserId)
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not create user. Skipping")
Continue For
End Try
' Add the user to group
Try
AddUserToGroup(oUserId, oGroupId)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not add user to group. Skipping")
Continue For
End Try
oSyncedUsers.Add(oUser)
Next
Return oSyncedUsers
End Function
Private Function AddUserToGroup(UserId As Integer, GroupId As Integer) As Boolean Implements ISyncUsers.AddUserToGroup
Try
Dim oSQL = $"SELECT FNICM_RADM_NEW_USER2GROUP({UserId}, {GroupId}, 'AD-Sync') from RDB$DATABASE"
Dim oRecordId = _firebird.GetScalarValue(oSQL)
If IsDBNull(oRecordId) Then
_logger.Warn("UserId {0} - GroupId {1} relation already exists.", UserId, GroupId)
Return False
End If
Return True
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetGroupId(GroupName As String) As Integer Implements ISyncUsers.GetGroupId
Try
Dim oSQL As String = $"SELECT FNICM_GET_RECORD4SYSKEY('{GroupName}','002-NAME') from RDB$DATABASE"
Dim oGroupId = _firebird.GetScalarValue(oSQL)
If IsDBNull(oGroupId) OrElse oGroupId = 0 Then
_logger.Debug("Group {0} not found in database", GroupName)
Return Nothing
End If
Return oGroupId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetUserId(UserName As String) As Integer Implements ISyncUsers.GetUserId
Try
Dim oSQL As String = $"SELECT FNICM_GET_RECORD4SYSKEY('{UserName}','001-USRNAME') from RDB$DATABASE"
Dim oResult = _firebird.GetScalarValue(oSQL)
If IsDBNull(oResult) Then
Return Nothing
End If
Return oResult
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function CreateUser(User As ADUser) As Integer Implements ISyncUsers.CreateUser
Try
Dim oSQL = $"SELECT FNICM_RADM_NEW_USER('{User?.GivenName}', '{User?.Surname}', '{User?.samAccountName}', 'AD-Sync') from RDB$DATABASE"
Dim oUserId As Integer = _firebird.GetScalarValue(oSQL)
Return oUserId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Sub AddCustomAttributesToUser(User As ADUser, UserId As Integer) Implements ISyncUsers.AddCustomAttributesToUser
Throw New NotImplementedException()
End Sub
End Class
End Namespace

View File

@ -86,7 +86,6 @@
<Compile Include="ActiveDirectoryInterface\ActiveDirectoryUser.vb" />
<Compile Include="ActiveDirectoryInterface\AttributeMap.vb" />
<Compile Include="ActiveDirectoryInterface\ISyncUsers.vb" />
<Compile Include="ActiveDirectoryInterface\SyncUsers.Firebird.vb" />
<Compile Include="ActiveDirectoryInterface\SyncUsers.MSSQL.vb" />
<Compile Include="ActiveDirectoryInterface\UserEqualityComparer.vb" />
<Compile Include="ActiveDirectoryInterface\UserPrincipalEx.vb" />
@ -170,4 +169,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -149,6 +149,7 @@ Public Class PDFEmbeds
GDPicturePDF.DeleteEmbeddedFile(0)
End While
Return True
End Function
Private Function DoExtract(GDPicturePDF As GdPicturePDF, pExtensions As List(Of String)) As List(Of EmbeddedFile)

View File

@ -8,8 +8,8 @@ Public Class ADSyncJob
Inherits JobBase
Implements IJob(Of ADSyncArgs)
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, MSSQL As MSSQLServer)
MyBase.New(LogConfig, Firebird, MSSQL)
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer)
MyBase.New(LogConfig, MSSQL)
End Sub
Public Sub Start(Arguments As ADSyncArgs) Implements IJob(Of ADSyncArgs).Start
@ -31,7 +31,7 @@ Public Class ADSyncJob
For Each oGroup In oGroups
_Logger.Debug("Syncing Group [{0}]", oGroup)
Dim oSyncedUsers = oSync.SyncUsersForGroup(oGroup, oAttributeMappings, _Firebird, _MSSQL, Arguments.UserFilter)
Dim oSyncedUsers = oSync.SyncUsersForGroup(oGroup, oAttributeMappings, _MSSQL, Arguments.UserFilter)
If oSyncedUsers Is Nothing Then
_Logger.Warn("Group [{0}] could not be synced!", oGroup)

View File

@ -1,28 +1,24 @@
Option Explicit On
Imports System.Collections.Generic
Imports System.Data
Imports System.IO
Imports System.Linq
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Config
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Jobs.GraphQL
Imports DigitalData.Modules.Logging
Imports Newtonsoft.Json.Linq
Public Class GraphQLJob
Inherits JobBase
Implements IJob(Of GraphQLArgs)
Private _GraphQL As GraphQLInterface = Nothing
Private _Model As GraphQLModel
Private _Writer As GraphQLWriter
Private Const PLACEHOLDER_STATIC = "STATIC:"
Private Const JOB_NAME = "GraphQL Job"
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer)
MyBase.New(LogConfig, Nothing, MSSQL)
MyBase.New(LogConfig, MSSQL)
End Sub
Public Sub Start(Args As GraphQLArgs) Implements IJob(Of GraphQLArgs).Start
@ -34,6 +30,9 @@ Public Class GraphQLJob
_GraphQL = New GraphQLInterface(_LogConfig, .BaseUrl, .Email, .Password, .CertificateFingerprint)
End With
_Model = New GraphQLModel(_LogConfig, _MSSQL)
_Writer = New GraphQLWriter(_LogConfig, _MSSQL)
' Login to get cookie
_Logger.Debug("Logging in")
Dim oLoginResponse = _GraphQL.Login()
@ -43,41 +42,7 @@ Public Class GraphQLJob
_Logger.Debug("Loading Queries")
' Load query data from TBCUST_JOBRUNNER_QUERY
Dim oQueryTable As DataTable = _MSSQL.GetDatatable("SELECT * FROM TBCUST_JOBRUNNER_QUERY ORDER BY SEQUENCE")
Dim oQueryList As New List(Of Query)
' Save query data to business objects
For Each oRow As DataRow In oQueryTable.Rows
Dim oQuery As New Query With {
.Id = oRow.Item("GUID"),
.Name = oRow.Item("TITLE"),
.ClearBeforeFill = oRow.ItemEx("CLEAR_BEFORE_FILL", False),
.ConnectionId = oRow.ItemEx("CON_ID", 1), ' TODO: Connection String?
.DestinationTable = oRow.ItemEx("DESTINATION_TABLE", String.Empty),
.OperationName = oRow.ItemEx("OPERATION_NAME", String.Empty),
.MappingBasePath = oRow.ItemEx("MAPPING_BASE_PATH", String.Empty),
.QueryString = oRow.ItemEx("QUERY_STRING", String.Empty)
}
If oQuery.DestinationTable = String.Empty Then
_Logger.Warn("Value [DestinationTable] could not be read. Configuration incomplete.")
End If
If oQuery.OperationName = String.Empty Then
_Logger.Warn("Value [OperationName] could not be read. Configuration incomplete.")
End If
If oQuery.MappingBasePath = String.Empty Then
_Logger.Warn("Value [MappingBasePath] could not be read. Configuration incomplete.")
End If
If oQuery.QueryString = String.Empty Then
_Logger.Warn("Value [QueryString] could not be read. Configuration incomplete.")
End If
oQueryList.Add(oQuery)
Next
Dim oQueryList = _Model.GetQueryList()
_Logger.Debug("Running [{0}] queries.", oQueryList.Count)
@ -119,13 +84,17 @@ Public Class GraphQLJob
' Clear Table before inserting
If pQuery.ClearBeforeFill = True Then
If DeleteWithQueryName(pQuery) = False Then
If DeleteHistoryTable(pQuery) = False Then
Throw New ApplicationException($"Error while dropping history table before fill for Query [{pQuery.Name}]")
End If
If CreateHistoryTable(pQuery) = False Then
Throw New ApplicationException($"Error while creating history table before fill for Query [{pQuery.Name}]")
End If
If TruncateTable(pQuery) = False Then
Throw New ApplicationException($"Error while truncating table before fill for Query [{pQuery.Name}]")
End If
End If
' Reset all records to status = 0
@ -137,31 +106,22 @@ Public Class GraphQLJob
End If
' get the data from GraphQL
_Logger.Info("Getting data..", pQuery.Name)
_Logger.Info("Getting data from GraphQL..", pQuery.Name)
Dim oDataResponse = _GraphQL.GetData(pQuery.QueryString, pQuery.OperationName)
Dim oResult As String
Dim oJsonResult As String
' write data to string
Using oStream = oDataResponse.GetResponseStream()
Using oReader As New StreamReader(oStream)
oResult = oReader.ReadToEnd()
oJsonResult = oReader.ReadToEnd()
End Using
End Using
' Fill the query object with field mapping data from TBCUST_JOBRUNNER_QUERY_MAPPING
Dim oSQL As String = "SELECT t2.* FROM TBCUST_JOBRUNNER_QUERY_MAPPING t
JOIN TBCUST_JOBRUNNER_MAPPING t2 ON t.MAPPING_ID = t2.GUID
WHERE t.QUERY_ID = {0}"
Dim oMappingTable As DataTable = _MSSQL.GetDatatable(String.Format(oSQL, pQuery.Id))
For Each oMapping As DataRow In oMappingTable.Rows
pQuery.MappingFields.Add(New GraphQL.FieldMapping With {
.DestinationColumn = oMapping.Item("DestinationColumn"),
.SourcePath = oMapping.Item("SourcePath")
})
Next
_Logger.Debug("Writing JSON data to database..")
' Handle the response from GraphQL and insert Data
Dim oWriteDataResult As GraphQL.Query = WriteNewQueryData(oResult, pQuery, oDatabase)
'Dim oWriteDataResult As Query = WriteNewQueryData(oResult, pQuery, oDatabase)
Dim oWriteDataResult As Query = _Writer.WriteNewQueryData(oJsonResult, pQuery, JOB_NAME)
If IsNothing(oWriteDataResult) Then
Throw New ApplicationException($"Error while handling Result of Query [{pQuery.Name}]")
@ -200,7 +160,7 @@ Public Class GraphQLJob
End Try
End Function
Private Function DeleteWithQueryName(pQuery As GraphQL.Query) As Boolean
Private Function DeleteHistoryTable(pQuery As Query) As Boolean
Dim oHistoryTableName = $"{pQuery.DestinationTable}_HISTORY"
Dim oDeleteHistorySQL = $"
IF (EXISTS (SELECT *
@ -214,6 +174,12 @@ Public Class GraphQLJob
Return _MSSQL.ExecuteNonQuery(oDeleteHistorySQL)
End Function
Private Function TruncateTable(pQuery As Query)
Dim oDeleteTableSQL = $"TRUNCATE TABLE {pQuery.DestinationTable}"
Return _MSSQL.ExecuteNonQuery(oDeleteTableSQL)
End Function
Private Function CreateHistoryTable(pQuery As Query) As Boolean
Dim oHistoryTableName = $"{pQuery.DestinationTable}_HISTORY"
Dim oFillHistorySQL = $"SELECT * INTO {oHistoryTableName} FROM {pQuery.DestinationTable}"
@ -231,72 +197,6 @@ Public Class GraphQLJob
Return _MSSQL.ExecuteNonQuery(oResetSQL)
End Function
Private Function WriteNewQueryData(JsonString As String, QueryData As GraphQL.Query, DB As Database.MSSQLServer) As GraphQL.Query
Dim oObj As JObject = JObject.Parse(JsonString)
Dim oResultList As JToken
If _GraphQL.ReadJSONPathFragmented(oObj, QueryData.MappingBasePath) = False Then
_Logger.Warn("There is an error in the MappingBasePath [{1}] configuration of query [{0}]", QueryData.Name, QueryData.MappingBasePath)
End If
Try
oResultList = oObj.SelectToken(QueryData.MappingBasePath, errorWhenNoMatch:=True)
Catch ex As Exception
_Logger.Warn("WriteNewQueryData: Could not find BasePath: [{0}] for query [{1}]", QueryData.MappingBasePath, QueryData.Name)
_Logger.Error(ex)
Return Nothing
End Try
If oResultList Is Nothing Then
_Logger.Warn("WriteNewQueryData: Could not find BasePath: [{0}] for query [{1}]", QueryData.MappingBasePath, QueryData.Name)
Return Nothing
End If
_Logger.Info("WriteNewQueryData: Processing Queue [{0}] with [{1}] Items", QueryData.Name, oResultList.Count)
For Each oResultItem As JToken In oResultList
Try
' ADDED_WHO, ADDED_QUERY_ID are system fields which are used to correctly fill
' and delete rows in the destination table without touching rows from other queries
Dim oKeys As New List(Of String) From {"ADDED_WHO", "ADDED_QUERY_ID", "STATUS"}
Dim oValues As New List(Of String) From {JOB_NAME, QueryData.Id, "1"}
For Each oMapping In QueryData.MappingFields
Dim oValue As String = String.Empty
If oMapping.SourcePath.StartsWith(PLACEHOLDER_STATIC) Then
oValue = oMapping.SourcePath.Replace(PLACEHOLDER_STATIC, String.Empty)
Else
Dim oToken = oResultItem.SelectToken(oMapping.SourcePath)
If oToken Is Nothing Then
_Logger.Warn("WriteNewQueryData: Could not find value at SourcePath: {0}", oMapping.SourcePath)
oValue = String.Empty
Else
oValue = oToken.ToString
End If
End If
oValues.Add(oValue)
oKeys.Add(oMapping.DestinationColumn)
Next
Dim oColumnString = String.Join(",", oKeys.ToArray)
Dim oValueList = oValues.Select(Function(Value) $"'{Value.EscapeForSQL}'").ToList()
Dim oValueString = String.Join(",", oValueList)
Dim oSQL As String = $"INSERT INTO {QueryData.DestinationTable} ({oColumnString}) VALUES ({oValueString})"
DB.ExecuteNonQuery(oSQL)
Catch ex As Exception
_Logger.Error(ex)
End Try
Next
Return QueryData
End Function
Public Function ShouldStart(Arguments As GraphQLArgs) As Boolean Implements IJob(Of GraphQLArgs).ShouldStart
Return Arguments.Enabled
End Function

View File

@ -0,0 +1,86 @@
Imports System.Collections.Generic
Imports System.Data
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Jobs.GraphQL
Imports DigitalData.Modules.Logging
Public Class GraphQLModel
Private Database As MSSQLServer
Private LogConfig As LogConfig
Private Logger As Logger
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer)
Database = pDatabase
LogConfig = pLogConfig
Logger = pLogConfig.GetLogger()
End Sub
Public Function GetQueryList() As List(Of Query)
Try
Dim oQueryTable As DataTable = Database.GetDatatable("SELECT * FROM TBCUST_JOBRUNNER_QUERY WHERE ACTIVE = 1 ORDER BY SEQUENCE")
Dim oQueryList As New List(Of Query)
For Each oRow As DataRow In oQueryTable.Rows
Dim oQuery As New Query With {
.Id = oRow.Item("GUID"),
.Name = oRow.Item("TITLE"),
.ClearBeforeFill = oRow.ItemEx("CLEAR_BEFORE_FILL", False),
.ConnectionId = oRow.ItemEx("CON_ID", 1), ' TODO: Connection String?
.DestinationTable = oRow.ItemEx("DESTINATION_TABLE", String.Empty),
.OperationName = oRow.ItemEx("OPERATION_NAME", String.Empty),
.MappingBasePath = oRow.ItemEx("MAPPING_BASE_PATH", String.Empty),
.QueryString = oRow.ItemEx("QUERY_STRING", String.Empty)
}
If oQuery.DestinationTable = String.Empty Then
Logger.Warn("Value [DestinationTable] could not be read. Configuration incomplete.")
End If
If oQuery.OperationName = String.Empty Then
Logger.Warn("Value [OperationName] could not be read. Configuration incomplete.")
End If
If oQuery.MappingBasePath = String.Empty Then
Logger.Warn("Value [MappingBasePath] could not be read. Configuration incomplete.")
End If
If oQuery.QueryString = String.Empty Then
Logger.Warn("Value [QueryString] could not be read. Configuration incomplete.")
End If
oQuery.MappingFields = GetQueryMapping(oQuery.Id)
oQueryList.Add(oQuery)
Next
Return oQueryList
Catch ex As Exception
Logger.Error(ex)
Return New List(Of Query)
End Try
End Function
Public Function GetQueryMapping(pQueryId As Integer) As List(Of FieldMapping)
Try
Dim oSQL As String = "SELECT t2.* FROM TBCUST_JOBRUNNER_QUERY_MAPPING t
JOIN TBCUST_JOBRUNNER_MAPPING t2 ON t.MAPPING_ID = t2.GUID
WHERE t.QUERY_ID = {0}"
Dim oMappingTable As DataTable = Database.GetDatatable(String.Format(oSQL, pQueryId))
Dim oMappings As New List(Of FieldMapping)
For Each oMapping As DataRow In oMappingTable.Rows
oMappings.Add(New FieldMapping With {
.DestinationColumn = oMapping.Item("DestinationColumn"),
.SourcePath = oMapping.Item("SourcePath")
})
Next
Return oMappings
Catch ex As Exception
Logger.Error(ex)
Return New List(Of FieldMapping)
End Try
End Function
End Class

View File

@ -0,0 +1,178 @@
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Jobs.GraphQL
Imports DigitalData.Modules.Logging
Imports Newtonsoft.Json.Linq
Public Class GraphQLWriter
Private ReadOnly Database As MSSQLServer
Private ReadOnly LogConfig As LogConfig
Private ReadOnly Logger As Logger
Private Const PLACEHOLDER_STATIC = "STATIC:"
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer)
Database = pDatabase
LogConfig = pLogConfig
Logger = pLogConfig.GetLogger()
End Sub
Public Function WriteNewQueryData(pJsonString As String, pQueryData As Query, pJobName As String) As GraphQL.Query
Try
Logger.Debug("Parsing JSON...")
Dim oObj As JObject = JObject.Parse(pJsonString)
Dim oResultList As JToken
If ValidateJSONPath(oObj, pQueryData.MappingBasePath) = False Then
Logger.Warn("There is an error in the MappingBasePath [{1}] configuration of query [{0}]", pQueryData.Name, pQueryData.MappingBasePath)
End If
Try
oResultList = oObj.SelectToken(pQueryData.MappingBasePath, errorWhenNoMatch:=True)
Catch ex As Exception
Logger.Warn("Could not find BasePath: [{0}] for query [{1}]", pQueryData.MappingBasePath, pQueryData.Name)
Logger.Error(ex)
Return Nothing
End Try
If oResultList Is Nothing Then
Logger.Warn("Could not find BasePath: [{0}] for query [{1}]", pQueryData.MappingBasePath, pQueryData.Name)
Return Nothing
End If
Logger.Info("Processing Query [{0}] with [{1}] Items", pQueryData.Name, oResultList.Count)
Dim oTable As New DataTable
Dim oColumnList = pQueryData.MappingFields.Select(Function(f) f.DestinationColumn).ToList()
For Each oColumnName In oColumnList
oTable.Columns.Add(oColumnName)
Next
oTable.Columns.Add("ADDED_WHO")
oTable.Columns.Add("ADDED_QUERY_ID")
oTable.Columns.Add("STATUS")
Logger.Debug("Creating DataTable..")
For Each oResultItem As JToken In oResultList
Dim oRow = FillRowFromJson(pQueryData, oResultItem, pJobName, oTable)
If oRow Is Nothing Then
Logger.Error("DataRow could not be created!")
Continue For
End If
oTable.Rows.Add(oRow)
Next
oTable.AcceptChanges()
Logger.Debug("Starting Bulk Insert..")
'Bulk insert
Dim oBulkResult = BulkInsert(oTable, pQueryData.DestinationTable, oColumnList)
If oBulkResult = False Then
Logger.Error("Bulk Insert for Query [{0}] failed!", pQueryData.Name)
End If
Logger.Info("Bulk Insert finished. [{0}] rows inserted.", oTable.Rows.Count)
Return pQueryData
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function FillRowFromJson(pQueryData As Query, pToken As JToken, pJobName As String, pTable As DataTable) As DataRow
Try
Dim oValuesNew As New Dictionary(Of String, String)
Dim oRow As DataRow = pTable.NewRow()
For Each oMapping In pQueryData.MappingFields
Dim oValue As String = String.Empty
If oMapping.SourcePath.StartsWith(PLACEHOLDER_STATIC) Then
oValue = oMapping.SourcePath.Replace(PLACEHOLDER_STATIC, String.Empty)
Else
Dim oToken = pToken.SelectToken(oMapping.SourcePath)
If oToken Is Nothing Then
Logger.Warn("WriteNewQueryData: Could not find value at SourcePath: {0}", oMapping.SourcePath)
oValue = String.Empty
Else
oValue = oToken.ToString
End If
End If
oValuesNew.Add(oMapping.DestinationColumn, oValue)
Next
oValuesNew.Add("ADDED_WHO", pJobName)
oValuesNew.Add("ADDED_QUERY_ID", pQueryData.Id)
oValuesNew.Add("STATUS", "1")
For Each oColumn As DataColumn In pTable.Columns
oRow.Item(oColumn.ColumnName) = oValuesNew.Item(oColumn.ColumnName)
Next
Return oRow
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function BulkInsert(pTable As DataTable, pDestinationTable As String, pColumns As List(Of String)) As Boolean
Using oConnection = Database.GetConnection()
Using oBulkCopy = New SqlBulkCopy(oConnection)
oBulkCopy.DestinationTableName = pDestinationTable
For Each oColumn In pColumns
oBulkCopy.ColumnMappings.Add(New SqlBulkCopyColumnMapping(oColumn, oColumn))
Next
Try
oBulkCopy.WriteToServer(pTable)
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Using
End Using
Return True
End Function
Public Function ValidateJSONPath(pObject As Newtonsoft.Json.Linq.JObject, pJsonPath As String) As Boolean
Dim oSplitPath As List(Of String) = pJsonPath.Split(".").ToList()
Dim oCurrentPath As String = String.Empty
For Each oPart In oSplitPath
If oCurrentPath = String.Empty Then
oCurrentPath = oPart
Else
oCurrentPath &= "." & oPart
End If
Logger.Debug("Selecting Path Fragment [{0}]", oCurrentPath)
Try
pObject.SelectToken(oCurrentPath, errorWhenNoMatch:=True)
Catch ex As Exception
Logger.Warn("Path Fragment [{0}] did not return a valid token", oCurrentPath)
Return False
End Try
Next
Return True
End Function
End Class

View File

@ -4,13 +4,11 @@ Imports DigitalData.Modules.Logging
Public Class JobBase
Protected _LogConfig As LogConfig
Protected _Logger As Logger
Protected _Firebird As Firebird
Protected _MSSQL As MSSQLServer
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, MSSQL As MSSQLServer)
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer)
_LogConfig = LogConfig
_Logger = LogConfig.GetLogger()
_Firebird = Firebird
_MSSQL = MSSQL
End Sub
End Class

View File

@ -4,6 +4,8 @@ Public Class JobConfig
Public Property Name As JobType
Public Property Enabled As Boolean = False
Public Property StartWithoutDelay As Boolean = False
' https://www.quartz-scheduler.net/documentation/quartz-3.x/how-tos/crontrigger.html
Public Property CronSchedule As String = ""
Public Property ArgsString As String = ""

View File

@ -92,7 +92,9 @@
<Compile Include="GraphQL\GraphQLArgs.vb" />
<Compile Include="GraphQL\GraphQLConfig.vb" />
<Compile Include="GraphQL\GraphQLJob.vb" />
<Compile Include="GraphQL\GraphQLModel.vb" />
<Compile Include="GraphQL\GraphQLQuery.vb" />
<Compile Include="GraphQL\GraphQLWriter.vb" />
<Compile Include="ZUGFeRD\EmailData.vb" />
<Compile Include="ZUGFeRD\EmailFunctions.vb" />
<Compile Include="ZUGFeRD\EmailStrings.vb" />
@ -136,4 +138,7 @@
<Reference Include="System.XML.Linq" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyCompany("Digital Data")>
<Assembly: AssemblyProduct("Modules.Jobs")>
<Assembly: AssemblyCopyright("Copyright © 2024")>
<Assembly: AssemblyTrademark("2.4.0.0")>
<Assembly: AssemblyTrademark("2.5.3.0")>
<Assembly: ComVisible(False)>
@ -30,5 +30,5 @@ Imports System.Runtime.InteropServices
' Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
' übernehmen, indem Sie "*" eingeben:
<Assembly: AssemblyVersion("2.4.0.1")>
<Assembly: AssemblyFileVersion("2.4.0.1")>
<Assembly: AssemblyVersion("2.5.3.0")>
<Assembly: AssemblyFileVersion("2.5.3.0")>

View File

@ -3,7 +3,7 @@
Public Const EMAIL_WRAPPING_TEXT = "<html><body style=''font-family:""Arial"";font-size:10.0pt''>Sehr geehrte Damen und Herren,<br/><br/>
das @NAME_ZUGFERD_PORTAL zur Verarbeitung der Eingangsrechnungen im ZUGFeRD-Format konnte die von Ihnen gesandte Rechnung
leider nicht verarbeiten! <br><br> Grund: {0}<p>Bitte prüfen Sie die Datei und nehmen Sie bei Bedarf mit uns Kontakt auf.<p>
Vielen Dank für Ihr Verständnis.<br>Mit freundlichen Grüßen<br>Ihre IT-Abteilung</body></html>"
Vielen Dank für Ihr Verständnis.<br>Mit freundlichen Grüßen<br>Ihre WISAG</body></html>"
Public Const EMAIL_SUBJECT_TEXT = "<p>Der Betreff der Original-Email war: <em>{0}</em></p>"
Public Const EMAIL_SUBJECT_REJECTED = "@NAME_ZUGFERD_PORTAL: Beleg abgelehnt"
@ -37,8 +37,9 @@
Public Const EMAIL_INVALID_DOCUMENT = "
<p>Ihre Email ({0}) enthielt ein ZUGFeRD Dokument, welches aber inkorrekt formatiert wurde.</p>
<p>Mögliche Gründe für ein inkorrektes Format:<ul>
<li>Betrags-Werte weisen ungültiges Format auf (z.B. 25,01 anstatt 25.01)</li>
<p>Mögliche Gründe für ein inkorrektes Format sind:<ul>
<li>Betragswerte weisen ein ungültiges Format auf (z.B. 25,01 anstatt 25.01)</li>
<li>Eins der folgenden Zeichen wird nicht XML-codiert verwendet: &amp;, &lt;, &gt; oder &quot;.</li>
</ul></p>
"

View File

@ -128,4 +128,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -116,4 +116,7 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -151,4 +151,7 @@
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -11,7 +11,7 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Database", "Database\Databa
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EDMI.API", "EDMIAPI\EDMI.API.vbproj", "{25017513-0D97-49D3-98D7-BA76D9B251B0}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Encryption", "Encryption\Encryption.vbproj", "{8A8F20FC-C46E-41AC-BEE7-218366CFFF99}"
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "NNEncryption", "Encryption\NNEncryption.vbproj", "{8A8F20FC-C46E-41AC-BEE7-218366CFFF99}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Interfaces", "Interfaces\Interfaces.vbproj", "{AB6F09BF-E794-4F6A-94BB-C97C0BA84D64}"
EndProject

View File

@ -153,4 +153,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

11
README.md Normal file
View File

@ -0,0 +1,11 @@
# Modules
Diese Projektmappe enthält die Grundfunktionen für alle Produkte in Form von Modulen.
## Deploy Skript
Das Skript `copy-binary.ps1` liegt im Hauptverzeichnis und kann über den folgenden Befehl aufgerufen werden. Der Befehl wird pro Projekt in den Projekteinstellungen unter `Kompilieren > Buildereignisse > Postbuildereignis` eingetragen und sorgt dafür, dass die Assembly des Projekts in ein Deploy Verzeichnis kopiert wird.
```cmd
powershell.exe -command "& { &'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' }"
```

View File

@ -173,4 +173,7 @@
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -154,4 +154,11 @@
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -142,4 +142,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<PropertyGroup>
<PostBuildEvent>powershell.exe -command "&amp; { &amp;'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }"</PostBuildEvent>
</PropertyGroup>
</Project>

29
copy-binary.ps1 Normal file
View File

@ -0,0 +1,29 @@
param(
[String]$SourcePath,
[String]$FileName,
[String]$Configuration,
[String]$ProjectName
)
$ArchiveFolderName = "Archiv"
$DestinationPath = "P:\Install .Net\0 DD - Bibliotheken\Modules\$ProjectName\"
$DestinationFilePath = [IO.Path]::Combine($DestinationPath, $FileName)
$ArchiveBasePath = [IO.Path]::Combine($DestinationPath, $ArchiveFolderName)
if ($Configuration -eq "Release") {
$DateFolderName = $((Get-Date).ToString('yyyy-MM-dd_hh-mm'))
$ArchivePath = [IO.Path]::Combine($ArchiveBasePath, $DateFolderName)
if (!(Test-Path -Path $ArchiveBasePath)) {
New-Item -Path $ArchiveBasePath -Type Directory
}
if (Test-Path -Path $DestinationFilePath) {
if (!(Test-Path -Path $ArchivePath)) {
New-Item -Path $ArchivePath -Type Directory
}
Copy-Item $DestinationFilePath -Destination $ArchivePath
}
Copy-Item $SourcePath -Destination $DestinationFilePath
}