2023-12-14 10:46:10 +01:00

282 lines
12 KiB
VB.net

Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Base
Imports GdPicture14
Imports Quartz
Imports System.Security.Cryptography
Imports System.IO
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument.FinalizeDocumentExceptions
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument
Imports System.Web.Caching
Imports System.Web.UI
Namespace Jobs
Public Class FinalizeDocumentJob
Implements IJob
Private ReadOnly LicenseManager As New LicenseManager()
Private GdViewer As GdViewer
Private LogConfig As LogConfig
Private Logger As Logger
Private Database As MSSQLServer
Private Config As DbConfig
Private ConfigModel As ConfigModel
Private EnvelopeModel As EnvelopeModel
Private ReportModel As ReportModel
Private ActionService As ActionService
Private PDFBurner As PDFBurner
Private ReportCreator As ReportCreator
Private Class EnvelopeData
Public EnvelopeId As Integer
Public DocumentPath As String
Public AnnotationData As List(Of String)
End Class
Public Function Execute(pContext As IJobExecutionContext) As Task Implements IJob.Execute
Dim oGdPictureKey As String = pContext.MergedJobDataMap.Item(Constants.GDPICTURE)
LogConfig = pContext.MergedJobDataMap.Item(Constants.LOGCONFIG)
Logger = LogConfig.GetLogger()
Dim JobId = pContext.JobDetail.Key
Logger.Info("Starting job {0}", JobId)
Try
Logger.Debug("Loading GdViewer..")
GdViewer = New GdViewer()
LicenseManager.RegisterKEY(oGdPictureKey)
Logger.Debug("Loading Database..")
Database = GetDatabase(pContext, LogConfig)
Logger.Debug("Loading Models & Services")
Dim oState = GetState()
InitializeModels(oState)
InitializeServices(oState)
Logger.Debug("Loading PDFBurner..")
PDFBurner = New PDFBurner(LogConfig, oGdPictureKey)
Logger.Debug("Loading ReportCreator..")
ReportCreator = New ReportCreator(LogConfig, oState)
Logger.Debug("Loading Configuration..")
Config = ConfigModel.LoadConfiguration()
Logger.Debug("DocumentPath: [{0}]", Config.DocumentPath)
Logger.Debug("ExportPath: [{0}]", Config.ExportPath)
Dim oCompleteStatus As Integer = Constants.EnvelopeStatus.EnvelopeCompletelySigned
Dim oSql = $"SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = {oCompleteStatus}"
Dim oTable = Database.GetDatatable(oSql)
Dim oEnvelopeIds As List(Of Integer) = oTable.Rows.Cast(Of DataRow).
Select(Function(r) r.Item("GUID")).
Cast(Of Integer).
ToList()
Logger.Info("Found [{0}] completed envelopes.", oEnvelopeIds.Count)
Dim oTotal As Integer = oEnvelopeIds.Count
Dim oCurrent As Integer = 1
For Each oId In oEnvelopeIds
Logger.Info("Finalizing Envelope [{0}] ({1}/{2})", oId, oCurrent, oTotal)
Logger.Debug("Loading Envelope..")
Dim oEnvelope = EnvelopeModel.GetById(oId)
If oEnvelope Is Nothing Then
Logger.Warn("Envelope could not be loaded for Id [{0}]!", oId)
Throw New ArgumentNullException("EnvelopeData")
End If
Logger.Debug("Loading Envelope Data..")
Dim oEnvelopeData = GetEnvelopeData(oId)
If oEnvelopeData Is Nothing Then
Logger.Warn("EnvelopeData could not be loaded for Id [{0}]!", oId)
Throw New ArgumentNullException("EnvelopeData")
End If
Logger.Debug("Burning Annotations to pdf")
Dim oBurnedDocument As Byte() = BurnAnnotationsToPdf(oEnvelopeData)
If oBurnedDocument Is Nothing Then
Logger.Warn("Document could not be finalized!")
Throw New ApplicationException("Document could not be finalized")
End If
Logger.Debug("Creating report..")
Dim oReport As Byte() = ReportCreator.CreateReport(oEnvelope)
Logger.Debug("Merging documents..")
Dim oMergedDocument As Byte() = MergeDocuments(oBurnedDocument, oReport)
Dim oOutputDirectoryPath = Config.ExportPath
Dim oOutputFilePath = Path.Combine(oOutputDirectoryPath, $"{oEnvelope.Uuid}.pdf")
Logger.Info("Writing finalized Pdf to disk..")
Logger.Info("Output path is [{0}]", oOutputFilePath)
Try
File.WriteAllBytes(oOutputFilePath, oMergedDocument)
Catch ex As Exception
Throw New ExportDocumentException("Could not export final document to disk!", ex)
Logger.Error(ex)
End Try
Logger.Debug("Setting envelope status..")
If ActionService.FinalizeEnvelope(oEnvelope) = False Then
Logger.Warn("Envelope could not be finalized!")
Throw New ApplicationException("Envelope could not be finalized")
End If
oCurrent += 1
Logger.Info("Envelope finalized!")
Next
Logger.Info("Completed job {0} successfully!", JobId)
Catch ex As MergeDocumentException
Logger.Warn("Certificate Document job failed at step: Merging documents!")
Logger.Error(ex)
Catch ex As Exception
Logger.Warn("Certificate Document job failed!")
Logger.Error(ex)
End Try
Logger.Info("Job execution for [{0}] ended", JobId)
End Function
Private Function MergeDocuments(pDocument As Byte(), pReport As Byte()) As Byte()
Using oDocumentStream As New MemoryStream(pDocument)
Using oReportStream As New MemoryStream(pReport)
Using oFinalStream As New MemoryStream()
Using oDocumentPDF As New GdPicturePDF()
Using oReportPDF As New GdPicturePDF()
Dim oStatus As GdPictureStatus = GdPictureStatus.OK
' Load the source file into memory
oDocumentPDF.LoadFromStream(oDocumentStream, True)
oStatus = oDocumentPDF.GetStat()
If oStatus <> GdPictureStatus.OK Then
Throw New MergeDocumentException($"Document could not be loaded: {oStatus}")
End If
' Load the report file into memory
oReportPDF.LoadFromStream(oReportStream, True)
oStatus = oReportPDF.GetStat()
If oStatus <> GdPictureStatus.OK Then
Throw New MergeDocumentException($"Report could not be loaded: {oStatus}")
End If
' Merge the documents
Dim oMergedPDF = oDocumentPDF.Merge2Documents(oDocumentPDF, oReportPDF)
oStatus = oMergedPDF.GetStat()
If oStatus <> GdPictureStatus.OK Then
Throw New MergeDocumentException($"Documents could not be merged: {oStatus}")
End If
' Convert to PDF/A
oMergedPDF.ConvertToPDFA(oFinalStream, PdfConversionConformance.PDF_A_1b, True, True)
oStatus = oDocumentPDF.GetStat()
If oStatus <> GdPictureStatus.OK Then
Throw New MergeDocumentException($"Document could not be converted to PDF/A: {oStatus}")
End If
Return oFinalStream.ToArray()
End Using
End Using
End Using
End Using
End Using
End Function
Private Function BurnAnnotationsToPdf(pData As EnvelopeData) As Byte()
Dim pEnvelopeId = pData.EnvelopeId
Logger.Info("Burning [{0}] signatures", pData.AnnotationData.Count)
Dim oAnnotations = pData.AnnotationData
Dim oInputPath = pData.DocumentPath
Logger.Info("Input path: [{0}]", oInputPath)
Dim oInputDocumentBuffer As Byte()
Try
oInputDocumentBuffer = File.ReadAllBytes(oInputPath)
Catch ex As Exception
Logger.Error(ex)
Throw New BurnAnnotationException("Source document could not be read from disk!", ex)
End Try
Return PDFBurner.BurnInstantJSONAnnotationsToPDF(oInputDocumentBuffer, oAnnotations)
End Function
Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData
Dim oSql = $"SELECT T.GUID, T2.FILEPATH FROM [dbo].[TBSIG_ENVELOPE] T
JOIN TBSIG_ENVELOPE_DOCUMENT T2 ON T.GUID = T2.ENVELOPE_ID
WHERE T.GUID = {pEnvelopeId}"
Dim oTable As DataTable = Database.GetDatatable(oSql)
Dim oRow As DataRow = oTable.Rows.Cast(Of DataRow).SingleOrDefault()
If oRow Is Nothing Then
Return Nothing
End If
Dim oAnnotationData = GetAnnotationData(pEnvelopeId)
Dim oData As New EnvelopeData With {
.EnvelopeId = pEnvelopeId,
.DocumentPath = oRow.ItemEx("FILEPATH", ""),
.AnnotationData = oAnnotationData
}
Logger.Debug("Document path: [{0}]", oData.DocumentPath)
Return oData
End Function
Private Function GetAnnotationData(pEnvelopeId As Integer) As List(Of String)
Dim oSql = $"SELECT VALUE FROM TBSIG_DOCUMENT_STATUS WHERE ENVELOPE_ID = {pEnvelopeId}"
Dim oTable As DataTable = Database.GetDatatable(oSql)
Return oTable.Rows.Cast(Of DataRow).
Select(Function(r) r.ItemEx("VALUE", String.Empty)).
Cast(Of String).
ToList()
End Function
Private Sub InitializeServices(pState As State)
ActionService = New ActionService(pState)
End Sub
Private Sub InitializeModels(pState As State)
ConfigModel = New ConfigModel(pState)
EnvelopeModel = New EnvelopeModel(pState)
ReportModel = New ReportModel(pState)
End Sub
Private Function GetDatabase(pContext As IJobExecutionContext, pLogConfig As LogConfig) As MSSQLServer
Dim oConnectionString As String = pContext.MergedJobDataMap.Item(Constants.DATABASE)
Dim Database = New MSSQLServer(pLogConfig, MSSQLServer.DecryptConnectionString(oConnectionString))
Return Database
End Function
Private Function GetState() As State
Return New State With {
.LogConfig = LogConfig,
.Database = Database,
.UserId = 0,
.Config = Nothing,
.DbConfig = Nothing
}
End Function
End Class
End Namespace