diff --git a/EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj b/EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj
deleted file mode 100644
index 1779441d..00000000
--- a/EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs b/EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs
deleted file mode 100644
index 7f8fac2b..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using System.Collections.Generic;
-using System.Data;
-using System.Threading.Tasks;
-using EnvelopeGenerator.Domain.Constants;
-using Microsoft.Data.SqlClient;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Quartz;
-
-namespace EnvelopeGenerator.Jobs.APIBackendJobs;
-
-public class APIEnvelopeJob(ILogger? logger = null) : IJob
-{
- private readonly ILogger _logger = logger ?? NullLogger.Instance;
-
- public async Task Execute(IJobExecutionContext context)
- {
- var jobId = context.JobDetail.Key.ToString();
- _logger.LogDebug("API Envelopes - Starting job {JobId}", jobId);
-
- try
- {
- var connectionString = context.MergedJobDataMap.GetString(Value.DATABASE);
- if (string.IsNullOrWhiteSpace(connectionString))
- {
- _logger.LogWarning("API Envelopes - Connection string missing");
- return;
- }
-
- await using var connection = new SqlConnection(connectionString);
- await connection.OpenAsync(context.CancellationToken);
-
- await ProcessInvitationsAsync(connection, context.CancellationToken);
- await ProcessWithdrawnAsync(connection, context.CancellationToken);
-
- _logger.LogDebug("API Envelopes - Completed job {JobId} successfully", jobId);
- }
- catch (System.Exception ex)
- {
- _logger.LogError(ex, "API Envelopes job failed");
- }
- finally
- {
- _logger.LogDebug("API Envelopes execution for {JobId} ended", jobId);
- }
- }
-
- private async Task ProcessInvitationsAsync(SqlConnection connection, System.Threading.CancellationToken cancellationToken)
- {
- const string sql = "SELECT GUID FROM TBSIG_ENVELOPE WHERE SOURCE = 'API' AND STATUS = 1003 ORDER BY GUID";
- var envelopeIds = new List();
-
- await using (var command = new SqlCommand(sql, connection))
- await using (var reader = await command.ExecuteReaderAsync(cancellationToken))
- {
- while (await reader.ReadAsync(cancellationToken))
- {
- if (reader[0] is int id)
- {
- envelopeIds.Add(id);
- }
- }
- }
-
- if (envelopeIds.Count == 0)
- {
- _logger.LogDebug("SendInvMail - No envelopes found");
- return;
- }
-
- _logger.LogInformation("SendInvMail - Found {Count} envelopes", envelopeIds.Count);
- var total = envelopeIds.Count;
- var current = 1;
-
- foreach (var id in envelopeIds)
- {
- _logger.LogInformation("SendInvMail - Processing Envelope {EnvelopeId} ({Current}/{Total})", id, current, total);
- try
- {
- // Placeholder for invitation email sending logic.
- _logger.LogDebug("SendInvMail - Marking envelope {EnvelopeId} as queued", id);
- const string updateSql = "UPDATE TBSIG_ENVELOPE SET CURRENT_WORK_APP = @App WHERE GUID = @Id";
- await using var updateCommand = new SqlCommand(updateSql, connection);
- updateCommand.Parameters.AddWithValue("@App", "signFLOW_API_EnvJob_InvMail");
- updateCommand.Parameters.AddWithValue("@Id", id);
- await updateCommand.ExecuteNonQueryAsync(cancellationToken);
- }
- catch (System.Exception ex)
- {
- _logger.LogWarning(ex, "SendInvMail - Unhandled exception while working envelope {EnvelopeId}", id);
- }
-
- current++;
- _logger.LogInformation("SendInvMail - Envelope finalized");
- }
- }
-
- private async Task ProcessWithdrawnAsync(SqlConnection connection, System.Threading.CancellationToken cancellationToken)
- {
- const string sql = @"SELECT ENV.GUID, REJ.COMMENT AS REJECTION_REASON FROM
- (SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = 1009 AND SOURCE = 'API') ENV INNER JOIN
- (SELECT MAX(GUID) GUID, ENVELOPE_ID, MAX(ADDED_WHEN) ADDED_WHEN, MAX(ACTION_DATE) ACTION_DATE, COMMENT FROM TBSIG_ENVELOPE_HISTORY WHERE STATUS = 1009 GROUP BY ENVELOPE_ID, COMMENT ) REJ ON ENV.GUID = REJ.ENVELOPE_ID LEFT JOIN
- (SELECT * FROM TBSIG_ENVELOPE_HISTORY WHERE STATUS = 3004 ) M_Send ON ENV.GUID = M_Send.ENVELOPE_ID
- WHERE M_Send.GUID IS NULL";
-
- var withdrawn = new List<(int EnvelopeId, string Reason)>();
- await using (var command = new SqlCommand(sql, connection))
- await using (var reader = await command.ExecuteReaderAsync(cancellationToken))
- {
- while (await reader.ReadAsync(cancellationToken))
- {
- var id = reader.GetInt32(0);
- var reason = reader.IsDBNull(1) ? string.Empty : reader.GetString(1);
- withdrawn.Add((id, reason));
- }
- }
-
- if (withdrawn.Count == 0)
- {
- _logger.LogDebug("WithdrawnEnv - No envelopes found");
- return;
- }
-
- _logger.LogInformation("WithdrawnEnv - Found {Count} envelopes", withdrawn.Count);
- var total = withdrawn.Count;
- var current = 1;
-
- foreach (var (envelopeId, reason) in withdrawn)
- {
- _logger.LogInformation("WithdrawnEnv - Processing Envelope {EnvelopeId} ({Current}/{Total})", envelopeId, current, total);
- try
- {
- // Log withdrawn mail trigger placeholder
- const string insertHistory = "INSERT INTO TBSIG_ENVELOPE_HISTORY (ENVELOPE_ID, STATUS, USER_REFERENCE, ADDED_WHEN, ACTION_DATE, COMMENT) VALUES (@EnvelopeId, @Status, @UserReference, GETDATE(), GETDATE(), @Comment)";
- await using var insertCommand = new SqlCommand(insertHistory, connection);
- insertCommand.Parameters.AddWithValue("@EnvelopeId", envelopeId);
- insertCommand.Parameters.AddWithValue("@Status", 3004);
- insertCommand.Parameters.AddWithValue("@UserReference", "API");
- insertCommand.Parameters.AddWithValue("@Comment", reason ?? string.Empty);
- await insertCommand.ExecuteNonQueryAsync(cancellationToken);
- }
- catch (System.Exception ex)
- {
- _logger.LogWarning(ex, "WithdrawnEnv - Unhandled exception while working envelope {EnvelopeId}", envelopeId);
- }
-
- current++;
- _logger.LogInformation("WithdrawnEnv - Envelope finalized");
- }
- }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs b/EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs
deleted file mode 100644
index 805f6f1f..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Data;
-
-namespace EnvelopeGenerator.Jobs;
-
-public static class DataRowExtensions
-{
- public static T? GetValueOrDefault(this DataRow row, string columnName, T? defaultValue = default)
- {
- if (!row.Table.Columns.Contains(columnName))
- {
- return defaultValue;
- }
-
- var value = row[columnName];
- if (value == DBNull.Value)
- {
- return defaultValue;
- }
-
- try
- {
- return (T)Convert.ChangeType(value, typeof(T));
- }
- catch
- {
- return defaultValue;
- }
- }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs
deleted file mode 100644
index 847ab06b..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public static class FinalizeDocumentExceptions
-{
- public class MergeDocumentException : ApplicationException
- {
- public MergeDocumentException(string message) : base(message) { }
- public MergeDocumentException(string message, Exception innerException) : base(message, innerException) { }
- }
-
- public class BurnAnnotationException : ApplicationException
- {
- public BurnAnnotationException(string message) : base(message) { }
- public BurnAnnotationException(string message, Exception innerException) : base(message, innerException) { }
- }
-
- public class CreateReportException : ApplicationException
- {
- public CreateReportException(string message) : base(message) { }
- public CreateReportException(string message, Exception innerException) : base(message, innerException) { }
- }
-
- public class ExportDocumentException : ApplicationException
- {
- public ExportDocumentException(string message) : base(message) { }
- public ExportDocumentException(string message, Exception innerException) : base(message, innerException) { }
- }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs
deleted file mode 100644
index 2ddb4e1d..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs
+++ /dev/null
@@ -1,229 +0,0 @@
-using System.Collections.Generic;
-using System.Data;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.Domain.Entities;
-using Microsoft.Data.SqlClient;
-using Microsoft.Extensions.Logging;
-using Quartz;
-using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class FinalizeDocumentJob : IJob
-{
- private readonly ILogger _logger;
- private readonly PDFBurner _pdfBurner;
- private readonly PDFMerger _pdfMerger;
- private readonly ReportCreator _reportCreator;
-
- private record ConfigSettings(string DocumentPath, string DocumentPathOrigin, string ExportPath);
-
- public FinalizeDocumentJob(
- ILogger logger,
- PDFBurner pdfBurner,
- PDFMerger pdfMerger,
- ReportCreator reportCreator)
- {
- _logger = logger;
- _pdfBurner = pdfBurner;
- _pdfMerger = pdfMerger;
- _reportCreator = reportCreator;
- }
-
- public async Task Execute(IJobExecutionContext context)
- {
- var jobId = context.JobDetail.Key.ToString();
- _logger.LogDebug("Starting job {JobId}", jobId);
-
- try
- {
- var connectionString = context.MergedJobDataMap.GetString(Value.DATABASE);
- if (string.IsNullOrWhiteSpace(connectionString))
- {
- _logger.LogWarning("FinalizeDocument - Connection string missing");
- return;
- }
-
- await using var connection = new SqlConnection(connectionString);
- await connection.OpenAsync(context.CancellationToken);
-
- var config = await LoadConfigurationAsync(connection, context.CancellationToken);
- var envelopes = await LoadCompletedEnvelopesAsync(connection, context.CancellationToken);
-
- if (envelopes.Count == 0)
- {
- _logger.LogInformation("No completed envelopes found");
- return;
- }
-
- var total = envelopes.Count;
- var current = 1;
-
- foreach (var envelopeId in envelopes)
- {
- _logger.LogInformation("Finalizing Envelope {EnvelopeId} ({Current}/{Total})", envelopeId, current, total);
- try
- {
- var envelopeData = await GetEnvelopeDataAsync(connection, envelopeId, context.CancellationToken);
- if (envelopeData is null)
- {
- _logger.LogWarning("Envelope data not found for {EnvelopeId}", envelopeId);
- continue;
- }
-
- var data = envelopeData.Value;
-
- var envelope = new Envelope
- {
- Id = envelopeId,
- Uuid = data.EnvelopeUuid ?? string.Empty,
- Title = data.Title ?? string.Empty,
- FinalEmailToCreator = (int)FinalEmailType.No,
- FinalEmailToReceivers = (int)FinalEmailType.No
- };
-
- var burned = _pdfBurner.BurnAnnotsToPDF(data.DocumentBytes, data.AnnotationData, envelopeId);
- var report = _reportCreator.CreateReport(connection, envelope);
- var merged = _pdfMerger.MergeDocuments(burned, report);
-
- var outputDirectory = Path.Combine(config.ExportPath, data.ParentFolderUid);
- Directory.CreateDirectory(outputDirectory);
- var outputPath = Path.Combine(outputDirectory, $"{envelope.Uuid}.pdf");
- await File.WriteAllBytesAsync(outputPath, merged, context.CancellationToken);
-
- await UpdateDocumentResultAsync(connection, envelopeId, merged, context.CancellationToken);
- await ArchiveEnvelopeAsync(connection, envelopeId, context.CancellationToken);
- }
- catch (MergeDocumentException ex)
- {
- _logger.LogWarning(ex, "Certificate Document job failed at merging documents");
- }
- catch (ExportDocumentException ex)
- {
- _logger.LogWarning(ex, "Certificate Document job failed at exporting document");
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Unhandled exception while working envelope {EnvelopeId}", envelopeId);
- }
-
- current++;
- _logger.LogInformation("Envelope {EnvelopeId} finalized", envelopeId);
- }
-
- _logger.LogDebug("Completed job {JobId} successfully", jobId);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Certificate Document job failed");
- }
- finally
- {
- _logger.LogDebug("Job execution for {JobId} ended", jobId);
- }
- }
-
- private async Task LoadConfigurationAsync(SqlConnection connection, CancellationToken cancellationToken)
- {
- const string sql = "SELECT TOP 1 DOCUMENT_PATH, EXPORT_PATH FROM TBSIG_CONFIG";
- await using var command = new SqlCommand(sql, connection);
- await using var reader = await command.ExecuteReaderAsync(cancellationToken);
- if (await reader.ReadAsync(cancellationToken))
- {
- var documentPath = reader.IsDBNull(0) ? string.Empty : reader.GetString(0);
- var exportPath = reader.IsDBNull(1) ? string.Empty : reader.GetString(1);
- return new ConfigSettings(documentPath, documentPath, exportPath);
- }
-
- return new ConfigSettings(string.Empty, string.Empty, Path.GetTempPath());
- }
-
- private async Task> LoadCompletedEnvelopesAsync(SqlConnection connection, CancellationToken cancellationToken)
- {
- const string sql = "SELECT GUID FROM TBSIG_ENVELOPE WHERE STATUS = @Status AND DATEDIFF(minute, CHANGED_WHEN, GETDATE()) >= 1 ORDER BY GUID";
- var ids = new List();
- await using var command = new SqlCommand(sql, connection);
- command.Parameters.AddWithValue("@Status", (int)EnvelopeStatus.EnvelopeCompletelySigned);
- await using var reader = await command.ExecuteReaderAsync(cancellationToken);
- while (await reader.ReadAsync(cancellationToken))
- {
- ids.Add(reader.GetInt32(0));
- }
-
- return ids;
- }
-
- private async Task<(int EnvelopeId, string? EnvelopeUuid, string? Title, byte[] DocumentBytes, List AnnotationData, string ParentFolderUid)?> GetEnvelopeDataAsync(SqlConnection connection, int envelopeId, CancellationToken cancellationToken)
- {
- const string sql = @"SELECT T.GUID, T.ENVELOPE_UUID, T.TITLE, T2.FILEPATH, T2.BYTE_DATA FROM [dbo].[TBSIG_ENVELOPE] T
- JOIN TBSIG_ENVELOPE_DOCUMENT T2 ON T.GUID = T2.ENVELOPE_ID
- WHERE T.GUID = @EnvelopeId";
-
- await using var command = new SqlCommand(sql, connection);
- command.Parameters.AddWithValue("@EnvelopeId", envelopeId);
- await using var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleRow, cancellationToken);
- if (!await reader.ReadAsync(cancellationToken))
- {
- return null;
- }
-
- var envelopeUuid = reader.IsDBNull(1) ? string.Empty : reader.GetString(1);
- var title = reader.IsDBNull(2) ? string.Empty : reader.GetString(2);
- var filePath = reader.IsDBNull(3) ? string.Empty : reader.GetString(3);
- var bytes = reader.IsDBNull(4) ? Array.Empty() : (byte[])reader[4];
- await reader.CloseAsync();
-
- if (bytes.Length == 0 && !string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath))
- {
- bytes = await File.ReadAllBytesAsync(filePath, cancellationToken);
- }
-
- var annotations = await GetAnnotationDataAsync(connection, envelopeId, cancellationToken);
-
- var parentFolderUid = !string.IsNullOrWhiteSpace(filePath)
- ? Path.GetFileName(Path.GetDirectoryName(filePath) ?? string.Empty)
- : envelopeUuid;
-
- return (envelopeId, envelopeUuid, title, bytes, annotations, parentFolderUid ?? envelopeUuid ?? envelopeId.ToString());
- }
-
- private async Task> GetAnnotationDataAsync(SqlConnection connection, int envelopeId, CancellationToken cancellationToken)
- {
- const string sql = "SELECT VALUE FROM TBSIG_DOCUMENT_STATUS WHERE ENVELOPE_ID = @EnvelopeId";
- var result = new List();
- await using var command = new SqlCommand(sql, connection);
- command.Parameters.AddWithValue("@EnvelopeId", envelopeId);
- await using var reader = await command.ExecuteReaderAsync(cancellationToken);
- while (await reader.ReadAsync(cancellationToken))
- {
- if (!reader.IsDBNull(0))
- {
- result.Add(reader.GetString(0));
- }
- }
-
- return result;
- }
-
- private static async Task UpdateDocumentResultAsync(SqlConnection connection, int envelopeId, byte[] bytes, CancellationToken cancellationToken)
- {
- const string sql = "UPDATE TBSIG_ENVELOPE SET DOC_RESULT = @ImageData WHERE GUID = @EnvelopeId";
- await using var command = new SqlCommand(sql, connection);
- command.Parameters.AddWithValue("@ImageData", bytes);
- command.Parameters.AddWithValue("@EnvelopeId", envelopeId);
- await command.ExecuteNonQueryAsync(cancellationToken);
- }
-
- private static async Task ArchiveEnvelopeAsync(SqlConnection connection, int envelopeId, CancellationToken cancellationToken)
- {
- const string sql = "UPDATE TBSIG_ENVELOPE SET STATUS = @Status, CHANGED_WHEN = GETDATE() WHERE GUID = @EnvelopeId";
- await using var command = new SqlCommand(sql, connection);
- command.Parameters.AddWithValue("@Status", (int)EnvelopeStatus.EnvelopeArchived);
- command.Parameters.AddWithValue("@EnvelopeId", envelopeId);
- await command.ExecuteNonQueryAsync(cancellationToken);
- }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs
deleted file mode 100644
index 0d04846c..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs
+++ /dev/null
@@ -1,277 +0,0 @@
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using iText.IO.Image;
-using iText.Kernel.Colors;
-using iText.Kernel.Pdf;
-using iText.Kernel.Pdf.Canvas;
-using iText.Layout;
-using iText.Layout.Element;
-using iText.Layout.Font;
-using iText.Layout.Properties;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Newtonsoft.Json;
-using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions;
-using LayoutImage = iText.Layout.Element.Image;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class PDFBurner
-{
- private static readonly FontProvider FontProvider = CreateFontProvider();
- private readonly ILogger _logger;
- private readonly PDFBurnerParams _pdfBurnerParams;
-
- public PDFBurner() : this(NullLogger.Instance, new PDFBurnerParams())
- {
- }
-
- public PDFBurner(ILogger logger, PDFBurnerParams? pdfBurnerParams = null)
- {
- _logger = logger;
- _pdfBurnerParams = pdfBurnerParams ?? new PDFBurnerParams();
- }
-
- public byte[] BurnAnnotsToPDF(byte[] sourceBuffer, IList instantJsonList, int envelopeId)
- {
- if (sourceBuffer is null || sourceBuffer.Length == 0)
- {
- throw new BurnAnnotationException("Source document is empty");
- }
-
- try
- {
- using var inputStream = new MemoryStream(sourceBuffer);
- using var outputStream = new MemoryStream();
- using var reader = new PdfReader(inputStream);
- using var writer = new PdfWriter(outputStream);
- using var pdf = new PdfDocument(reader, writer);
-
- foreach (var json in instantJsonList ?? Enumerable.Empty())
- {
- if (string.IsNullOrWhiteSpace(json))
- {
- continue;
- }
-
- var annotationData = JsonConvert.DeserializeObject(json);
- if (annotationData?.annotations is null)
- {
- continue;
- }
-
- annotationData.annotations.Reverse();
-
- foreach (var annotation in annotationData.annotations)
- {
- try
- {
- switch (annotation.type)
- {
- case AnnotationType.Image:
- AddImageAnnotation(pdf, annotation, annotationData.attachments);
- break;
- case AnnotationType.Ink:
- AddInkAnnotation(pdf, annotation);
- break;
- case AnnotationType.Widget:
- var formFieldValue = annotationData.formFieldValues?.FirstOrDefault(fv => fv.name == annotation.id);
- if (formFieldValue is not null && !_pdfBurnerParams.IgnoredLabels.Contains(formFieldValue.value))
- {
- AddFormFieldValue(pdf, annotation, formFieldValue.value);
- }
- break;
- }
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex, "Error applying annotation {AnnotationId} on envelope {EnvelopeId}", annotation.id, envelopeId);
- throw new BurnAnnotationException("Adding annotation failed", ex);
- }
- }
- }
-
- pdf.Close();
- return outputStream.ToArray();
- }
- catch (BurnAnnotationException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to burn annotations for envelope {EnvelopeId}", envelopeId);
- throw new BurnAnnotationException("Annotations could not be burned", ex);
- }
- }
-
- private void AddImageAnnotation(PdfDocument pdf, Annotation annotation, Dictionary? attachments)
- {
- if (attachments is null || string.IsNullOrWhiteSpace(annotation.imageAttachmentId) || !attachments.TryGetValue(annotation.imageAttachmentId, out var attachment))
- {
- return;
- }
-
- var page = pdf.GetPage(annotation.pageIndex + 1);
- var bounds = annotation.bbox.Select(ToInches).ToList();
- var x = (float)bounds[0];
- var y = (float)bounds[1];
- var width = (float)bounds[2];
- var height = (float)bounds[3];
-
- var imageBytes = Convert.FromBase64String(attachment.binary);
- var imageData = ImageDataFactory.Create(imageBytes);
- var image = new LayoutImage(imageData)
- .ScaleAbsolute(width, height)
- .SetFixedPosition(annotation.pageIndex + 1, x, y);
-
- using var canvas = new Canvas(new PdfCanvas(page), page.GetPageSize());
- canvas.Add(image);
- }
-
- private void AddInkAnnotation(PdfDocument pdf, Annotation annotation)
- {
- if (annotation.lines?.points is null)
- {
- return;
- }
-
- var page = pdf.GetPage(annotation.pageIndex + 1);
- var canvas = new PdfCanvas(page);
- var color = ParseColor(annotation.strokeColor);
- canvas.SetStrokeColor(color);
- canvas.SetLineWidth(1);
-
- foreach (var segment in annotation.lines.points)
- {
- var first = true;
- foreach (var point in segment)
- {
- var (px, py) = (ToInches(point[0]), ToInches(point[1]));
- if (first)
- {
- canvas.MoveTo(px, py);
- first = false;
- }
- else
- {
- canvas.LineTo(px, py);
- }
- }
- canvas.Stroke();
- }
- }
-
- private static FontProvider CreateFontProvider()
- {
- var provider = new FontProvider();
- provider.AddStandardPdfFonts();
- provider.AddSystemFonts();
- return provider;
- }
-
- private void AddFormFieldValue(PdfDocument pdf, Annotation annotation, string value)
- {
- var bounds = annotation.bbox.Select(ToInches).ToList();
- var x = (float)bounds[0];
- var y = (float)bounds[1];
- var width = (float)bounds[2];
- var height = (float)bounds[3];
-
- var page = pdf.GetPage(annotation.pageIndex + 1);
- var canvas = new Canvas(new PdfCanvas(page), page.GetPageSize());
- canvas.SetProperty(Property.FONT_PROVIDER, FontProvider);
- canvas.SetProperty(Property.FONT, FontProvider.GetFontSet());
-
- var paragraph = new Paragraph(value)
- .SetFontSize(_pdfBurnerParams.FontSize)
- .SetFontColor(ColorConstants.BLACK)
- .SetFontFamily(_pdfBurnerParams.FontName);
-
- if (_pdfBurnerParams.FontStyle.HasFlag(FontStyle.Italic))
- {
- paragraph.SetItalic();
- }
-
- if (_pdfBurnerParams.FontStyle.HasFlag(FontStyle.Bold))
- {
- paragraph.SetBold();
- }
-
- canvas.ShowTextAligned(
- paragraph,
- x + (float)_pdfBurnerParams.TopMargin,
- y + (float)_pdfBurnerParams.YOffset,
- annotation.pageIndex + 1,
- iText.Layout.Properties.TextAlignment.LEFT,
- iText.Layout.Properties.VerticalAlignment.TOP,
- 0);
- }
-
- private static DeviceRgb ParseColor(string? color)
- {
- if (string.IsNullOrWhiteSpace(color))
- {
- return new DeviceRgb(0, 0, 0);
- }
-
- try
- {
- var drawingColor = ColorTranslator.FromHtml(color);
- return new DeviceRgb(drawingColor.R, drawingColor.G, drawingColor.B);
- }
- catch
- {
- return new DeviceRgb(0, 0, 0);
- }
- }
-
- private static double ToInches(double value) => value / 72d;
- private static double ToInches(float value) => value / 72d;
-
- #region Model
- private static class AnnotationType
- {
- public const string Image = "pspdfkit/image";
- public const string Ink = "pspdfkit/ink";
- public const string Widget = "pspdfkit/widget";
- }
-
- private sealed class AnnotationData
- {
- public List? annotations { get; set; }
- public Dictionary? attachments { get; set; }
- public List? formFieldValues { get; set; }
- }
-
- private sealed class Annotation
- {
- public string id { get; set; } = string.Empty;
- public List bbox { get; set; } = new();
- public string type { get; set; } = string.Empty;
- public string imageAttachmentId { get; set; } = string.Empty;
- public Lines? lines { get; set; }
- public int pageIndex { get; set; }
- public string strokeColor { get; set; } = string.Empty;
- public string egName { get; set; } = string.Empty;
- }
-
- private sealed class Lines
- {
- public List>> points { get; set; } = new();
- }
-
- private sealed class Attachment
- {
- public string binary { get; set; } = string.Empty;
- public string contentType { get; set; } = string.Empty;
- }
-
- private sealed class FormFieldValue
- {
- public string name { get; set; } = string.Empty;
- public string value { get; set; } = string.Empty;
- }
- #endregion
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs
deleted file mode 100644
index 0b9536fa..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-using System.Drawing;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class PDFBurnerParams
-{
- public List IgnoredLabels { get; } = new() { "Date", "Datum", "ZIP", "PLZ", "Place", "Ort", "Position", "Stellung" };
-
- public double TopMargin { get; set; } = 0.1;
-
- public double YOffset { get; set; } = -0.3;
-
- public string FontName { get; set; } = "Arial";
-
- public int FontSize { get; set; } = 8;
-
- public FontStyle FontStyle { get; set; } = FontStyle.Italic;
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs
deleted file mode 100644
index 2306fac7..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.IO;
-using iText.Kernel.Pdf;
-using iText.Kernel.Utils;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class PDFMerger
-{
- private readonly ILogger _logger;
-
- public PDFMerger() : this(NullLogger.Instance)
- {
- }
-
- public PDFMerger(ILogger logger)
- {
- _logger = logger;
- }
-
- public byte[] MergeDocuments(byte[] document, byte[] report)
- {
- try
- {
- using var finalStream = new MemoryStream();
- using var documentReader = new PdfReader(new MemoryStream(document));
- using var reportReader = new PdfReader(new MemoryStream(report));
- using var writer = new PdfWriter(finalStream);
- using var targetDoc = new PdfDocument(documentReader, writer);
- using var reportDoc = new PdfDocument(reportReader);
-
- var merger = new PdfMerger(targetDoc);
- merger.Merge(reportDoc, 1, reportDoc.GetNumberOfPages());
-
- targetDoc.Close();
- return finalStream.ToArray();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to merge PDF documents");
- throw new MergeDocumentException("Documents could not be merged", ex);
- }
- }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs
deleted file mode 100644
index b0e4aa08..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System.Data;
-using System.IO;
-using EnvelopeGenerator.Domain.Entities;
-using iText.Kernel.Pdf;
-using iText.Layout.Element;
-using Microsoft.Data.SqlClient;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions;
-using LayoutDocument = iText.Layout.Document;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class ReportCreator
-{
- private readonly ILogger _logger;
-
- public ReportCreator() : this(NullLogger.Instance)
- {
- }
-
- public ReportCreator(ILogger logger)
- {
- _logger = logger;
- }
-
- public byte[] CreateReport(SqlConnection connection, Envelope envelope)
- {
- try
- {
- var reportItems = LoadReportItems(connection, envelope.Id);
- using var stream = new MemoryStream();
- using var writer = new PdfWriter(stream);
- using var pdf = new PdfDocument(writer);
- using var document = new LayoutDocument(pdf);
-
- document.Add(new Paragraph("Envelope Finalization Report").SetFontSize(16));
- document.Add(new Paragraph($"Envelope Id: {envelope.Id}"));
- document.Add(new Paragraph($"UUID: {envelope.Uuid}"));
- document.Add(new Paragraph($"Title: {envelope.Title}"));
- document.Add(new Paragraph($"Subject: {envelope.Comment}"));
- document.Add(new Paragraph($"Generated: {DateTime.UtcNow:O}"));
- document.Add(new Paragraph(" "));
-
- var table = new Table(4).UseAllAvailableWidth();
- table.AddHeaderCell("Date");
- table.AddHeaderCell("Status");
- table.AddHeaderCell("User");
- table.AddHeaderCell("EnvelopeId");
-
- foreach (var item in reportItems.OrderByDescending(r => r.ItemDate))
- {
- table.AddCell(item.ItemDate.ToString("u"));
- table.AddCell(item.ItemStatus.ToString());
- table.AddCell(item.ItemUserReference);
- table.AddCell(item.EnvelopeId.ToString());
- }
-
- document.Add(table);
- document.Close();
- return stream.ToArray();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Could not create report for envelope {EnvelopeId}", envelope.Id);
- throw new CreateReportException("Could not prepare report data", ex);
- }
- }
-
- private List LoadReportItems(SqlConnection connection, int envelopeId)
- {
- const string sql = "SELECT ENVELOPE_ID, POS_WHEN, POS_STATUS, POS_WHO FROM VWSIG_ENVELOPE_REPORT WHERE ENVELOPE_ID = @EnvelopeId";
- var result = new List();
-
- using var command = new SqlCommand(sql, connection);
- command.Parameters.AddWithValue("@EnvelopeId", envelopeId);
- using var reader = command.ExecuteReader();
- while (reader.Read())
- {
- result.Add(new ReportItem
- {
- EnvelopeId = reader.GetInt32(0),
- ItemDate = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1),
- ItemStatus = reader.IsDBNull(2) ? default : (EnvelopeGenerator.Domain.Constants.EnvelopeStatus)reader.GetInt32(2),
- ItemUserReference = reader.IsDBNull(3) ? string.Empty : reader.GetString(3)
- });
- }
-
- return result;
- }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs
deleted file mode 100644
index c8e0d52e..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.Domain.Entities;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class ReportItem
-{
- public Envelope? Envelope { get; set; }
- public int EnvelopeId { get; set; }
- public string EnvelopeTitle { get; set; } = string.Empty;
- public string EnvelopeSubject { get; set; } = string.Empty;
-
- public EnvelopeStatus ItemStatus { get; set; }
-
- public string ItemStatusTranslated => ItemStatus.ToString();
-
- public string ItemUserReference { get; set; } = string.Empty;
- public DateTime ItemDate { get; set; }
-}
diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs
deleted file mode 100644
index 47afd920..00000000
--- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System.Collections.Generic;
-
-namespace EnvelopeGenerator.Jobs.FinalizeDocument;
-
-public class ReportSource
-{
- public List Items { get; set; } = new();
-}
diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln
index fe942d58..f55cdd56 100644
--- a/EnvelopeGenerator.sln
+++ b/EnvelopeGenerator.sln
@@ -33,8 +33,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.PdfEditor
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Tests", "EnvelopeGenerator.Tests\EnvelopeGenerator.Tests.csproj", "{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Jobs", "EnvelopeGenerator.Jobs\EnvelopeGenerator.Jobs.csproj", "{3D0514EA-2681-4B13-AD71-35CC6363DBD7}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.API", "EnvelopeGenerator.API\EnvelopeGenerator.API.csproj", "{EC768913-6270-14F4-1DD3-69C87A659462}"
EndProject
Global
@@ -83,10 +81,6 @@ Global
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Release|Any CPU.Build.0 = Release|Any CPU
- {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Release|Any CPU.Build.0 = Release|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -109,7 +103,6 @@ Global
{6D56C01F-D6CB-4D8A-BD3D-4FD34326998C} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8} = {0CBC2432-A561-4440-89BC-671B66A24146}
- {3D0514EA-2681-4B13-AD71-35CC6363DBD7} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{EC768913-6270-14F4-1DD3-69C87A659462} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution