diff --git a/Common/PendingEmails/App.config b/Common/PendingEmails/App.config
index f0c21a8d..ec39cb3b 100644
--- a/Common/PendingEmails/App.config
+++ b/Common/PendingEmails/App.config
@@ -1,10 +1,12 @@
-
-
+
+
+
+
+
+
+
-
-
-
\ No newline at end of file
diff --git a/Common/PendingEmails/AppSettings.cs b/Common/PendingEmails/AppSettings.cs
new file mode 100644
index 00000000..715ac93a
--- /dev/null
+++ b/Common/PendingEmails/AppSettings.cs
@@ -0,0 +1,138 @@
+namespace PendingEmails
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Configuration;
+ using System.IO;
+ using System.Linq;
+
+ public static partial class Program
+ {
+ public class AppSettings
+ {
+ public static string LogFolder { get; private set; }
+
+ public static string MSSQLConnectionString { get; private set; }
+
+ public static string Sender { get; private set; }
+
+ public static string ExcludeRecipients { get; private set; }
+
+ public static string SMTPHost { get; private set; }
+
+ public static int SMTPPort { get; private set; }
+
+ public static int Interval { get; private set; }
+
+ public static bool TryLoadExeConfiguration(out ICollection errors)
+ {
+ errors = new HashSet();
+
+ var exeFileInfo = new FileInfo(typeof(Program).Assembly.Location);
+ var settings = ConfigurationManager
+ .OpenExeConfiguration(exeFileInfo.FullName)
+ ?.AppSettings
+ ?.Settings;
+ var loaded = true;
+
+ if (settings is null)
+ {
+ errors.Add($"{exeFileInfo.Name} nicht gefunden.");
+
+ loaded = false;
+ }
+ else
+ {
+ var keys = settings.AllKeys;
+
+ LogFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
+
+ if (!keys.Any(x => x == nameof(LogFolder)))
+ {
+ errors.Add($"{nameof(LogFolder)} nicht definiert in die {exeFileInfo.Name}.");
+ }
+ else
+ {
+ LogFolder = settings[nameof(LogFolder)]?.Value;
+ }
+
+ if (!keys.Any(x => x == nameof(MSSQLConnectionString)))
+ {
+ errors.Add($"{nameof(MSSQLConnectionString)} nicht definiert in die {exeFileInfo.Name}.");
+
+ loaded = false;
+ }
+ else
+ {
+ MSSQLConnectionString = settings[nameof(MSSQLConnectionString)]?.Value;
+ }
+
+ if (!keys.Any(x => x == nameof(Sender)))
+ {
+ errors.Add($"{nameof(Sender)} nicht definiert in die {exeFileInfo.Name}.");
+
+ loaded = false;
+ }
+ else
+ {
+ Sender = settings[nameof(Sender)]?.Value;
+ }
+
+ if (!keys.Any(x => x == nameof(ExcludeRecipients)))
+ {
+ errors.Add($"{nameof(ExcludeRecipients)} nicht definiert in die {exeFileInfo.Name}.");
+ }
+ else
+ {
+ ExcludeRecipients = settings[nameof(ExcludeRecipients)]?.Value;
+ }
+
+ if (!keys.Any(x => x == nameof(SMTPHost)))
+ {
+ errors.Add($"{nameof(SMTPHost)} nicht definiert in die {exeFileInfo.Name}.");
+
+ loaded = false;
+ }
+ else
+ {
+ SMTPHost = settings[nameof(SMTPHost)]?.Value;
+ }
+
+ if (!keys.Any(x => x == nameof(SMTPPort)))
+ {
+ errors.Add($"{nameof(SMTPPort)} nicht definiert in die {exeFileInfo.Name}.");
+
+ loaded = false;
+ }
+ else if (!int.TryParse($"{settings[nameof(SMTPPort)]?.Value}", out var smtpPort))
+ {
+ errors.Add($"{nameof(SMTPPort)} ist ungültig.");
+
+ loaded = false;
+ }
+ else
+ {
+ SMTPPort = smtpPort;
+ }
+
+ Interval = 600_000;
+
+ if (!keys.Any(x => x == nameof(Interval)))
+ {
+ errors.Add($"{nameof(Interval)} nicht definiert in die {exeFileInfo.Name}.");
+ }
+ else if (!int.TryParse($"{settings[nameof(Interval)]?.Value}", out var interval))
+ {
+ errors.Add($"{nameof(Interval)} ist ungültig.");
+ }
+ else
+ {
+ Interval = interval;
+ }
+ }
+
+ return loaded;
+ }
+ }
+ }
+}
diff --git a/Common/PendingEmails/Message.cs b/Common/PendingEmails/Message.cs
new file mode 100644
index 00000000..023fc9b5
--- /dev/null
+++ b/Common/PendingEmails/Message.cs
@@ -0,0 +1,32 @@
+namespace PendingEmails
+{
+ public static partial class Program
+ {
+ public class Message
+ {
+ public Message(int messageId, string sender, string subject, string body, string recipients, string recipientsCC)
+ {
+ this.Id = messageId;
+ this.Sender = sender;
+ this.Subject = subject;
+ this.Body = body;
+ this.Recipients = recipients;
+ this.RecipientsCC = recipientsCC;
+ }
+
+ public int Id { get; set; }
+
+ public string Sender { get; set; }
+
+ public string Subject { get; set; }
+
+ public string Body { get; set; }
+
+ public string Recipients { get; set; }
+
+ public string RecipientsCC { get; set; }
+
+ public bool IsValid => !string.IsNullOrWhiteSpace(this.Recipients);
+ }
+ }
+}
diff --git a/Common/PendingEmails/PendingEmails.csproj b/Common/PendingEmails/PendingEmails.csproj
index 9813bb46..776612d3 100644
--- a/Common/PendingEmails/PendingEmails.csproj
+++ b/Common/PendingEmails/PendingEmails.csproj
@@ -37,6 +37,7 @@
DEBUG;TRACE
prompt
4
+ IDE0003;IDE0049;
AnyCPU
@@ -69,10 +70,18 @@
true
+
+
+
+
+ sensus.ico
+
+
+
@@ -80,6 +89,8 @@
+
+
@@ -93,5 +104,8 @@
false
+
+
+
\ No newline at end of file
diff --git a/Common/PendingEmails/Program.cs b/Common/PendingEmails/Program.cs
index f935bd2c..3ec08b23 100644
--- a/Common/PendingEmails/Program.cs
+++ b/Common/PendingEmails/Program.cs
@@ -1,273 +1,269 @@
-namespace PendingEmails
-{
- using System;
- using System.Collections.Generic;
- using System.Configuration;
- using System.Data;
- using System.Data.SqlClient;
- using System.IO;
- using System.Linq;
- using System.Net.Mail;
- using System.Threading;
- using System.Timers;
-
- using SystemTimersTimer = System.Timers.Timer;
-
- public static class Program
- {
- private static readonly SystemTimersTimer timer = new SystemTimersTimer();
-
- private static void Main()
- {
- Console.WriteLine("Pending emails ....");
- try
- {
- timer.AutoReset = true;
- timer.Interval = 600_000;
- timer.Elapsed += Timer_Elapsed;
-
- while (true)
- {
- Timer_Elapsed(null, null);
- timer.Start();
- var awaiter = new ManualResetEventSlim();
- awaiter.Wait();
- timer.Stop();
- }
- }
- catch (Exception e)
- {
- LogToFile(e.Message);
- }
-
- }
-
- public class Ready
- {
- public string Source { get; set; }
-
- public string Subject { get; set; }
-
- public string Body { get; set; }
- }
-
- private static void Timer_Elapsed(Object _, ElapsedEventArgs _1)
- {
- LogToFile($"loading pending emails");
-
- var connectionString = ConfigurationManager.ConnectionStrings["Auftrag"].ConnectionString;
-
- using (var connection = new SqlConnection(connectionString))
- {
- connection.FireInfoMessageEventOnUserErrors = true;
- connection.InfoMessage += (_2, args) => LogToFile(args.Message);
- connection.Open();
-
- var ready = new List();
-
- using (var command = connection.CreateCommand())
- {
- command.CommandTimeout = 60000;
- command.CommandText = @"
- INSERT INTO Messages
- ( Source
- , InDate
- , StationNr
- , PCName
- , IPAddress
- , Trace
- , Sender
- , Subject
- , Body
- , Recipients
- , CC
- , State)
- SELECT ag.Fertigungsauftrag
- , CURRENT_TIMESTAMP
- , ag.Pruefstation
- , @@SERVERNAME
- , @@SERVICENAME
- , 'Xylem.Common.Service.PendingMails'
- , 'noreplay@xylem.com'
- , ISNULL(ag.Kundenort, 'Kundenort') + ' - ' + CAST(ag.Auftrag AS VARCHAR(15)) + '/' + CAST(ag.Position AS VARCHAR(10))
- + ' erfolgreich geprüft - bitte Garantiescheine drucken und bereitlegen!'
- , 'Auftrag: ' + CAST(ag.Auftrag AS VARCHAR(15)) + '/' + CAST(ag.Position AS VARCHAR(10)) + CHAR(10)
+ 'FertigungsauftragNr: ' + CAST(ISNULL(ag.Fertigungsauftrag, 0) AS VARCHAR(15)) + CHAR(10)
- + CHAR(10)
+ CAST(ISNULL(ag.Menge, 0) AS VARCHAR(10)) + ' Stück ' + ag.Bezeichnung + CHAR(10)
+ 'wurde an der Prüfstation: ' + CAST(ISNULL(ag.Pruefstation, 0) AS VARCHAR(5)) + CHAR(10)
+ 'am ' + CONVERT(VARCHAR(10), ag.Pruefdatum, 105) + ' um ' + CONVERT(VARCHAR(5), ag.Pruefdatum, 108) + ' Uhr' + CHAR(10)
+ 'von ' + ag.Mitarbaiter + ' vollständig geprüft.' + CHAR(10)
- + CHAR(10)
+ 'Seriennummern: ' + CAST(ag.SerienNrVon AS VARCHAR(15)) + ' - ' + CAST(ag.SerienNrBis AS VARCHAR(15)) + '' + CHAR(10)
- + CHAR(10)
- + ag.Merkmal + CHAR(10)
- , 'uwe.kubon@xylem.com'
- , 'stoyan.zlatev@xylem.com'
- , 'Automatische fertigmeldung für garantiescheine.'
- FROM AlleGepruefteAuftraegeMitGarantieAusLetzte24Hours AS ag
- LEFT JOIN Messages AS msg
- ON ag.Fertigungsauftrag LIKE msg.Source
- WHERE msg.Id IS NULL";
-
- LogToFile($"Inserted: {command.ExecuteNonQuery()}");
- }
-
- var updated = new Dictionary();
- var countAll = 0;
-
- using (var command = connection.CreateCommand())
- {
- command.CommandText = @"
- SELECT [Sender]
- , [Subject]
- , [Body]
- , [Recipients]
- , [CC]
- , [Id]
- FROM [Messages]
- WHERE [OutDate] IS NULL
- ORDER BY [InDate] DESC";
-
- using (var reader = command.ExecuteReader())
- {
- while (reader.Read())
- {
- var messageId = reader.GetValue(5);
-
- try
- {
- var email = new MailMessage();
- var from = ConfigurationManager.AppSettings["DefaultSender"];
- email.From = new MailAddress(from);
- email.Subject = $"{reader.GetValue(1)}";
- email.Body = $"{reader.GetValue(2)}";
-
- $"{reader.GetValue(3)}"
- .Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => new MailAddress(x))
- .ToList()
- .ForEach(email.To.Add);
-
- $"{reader.GetValue(4)}"
- .Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => new MailAddress(x))
- .ToList()
- .ForEach(email.CC.Add);
-
- if (SendEmail(email))
- {
- updated[messageId] = "Sent";
- }
- }
- catch (Exception e)
- {
- LogToFile(e);
-
- updated[messageId] = e.ToString();
- }
-
- countAll++;
- }
- }
- }
-
- var updatedCount = updated.Count;
-
- if (updatedCount > 0)
- {
- try
- {
- LogToFile($"updating: {string.Join(", ", updated)}");
-
- foreach (var kvp in updated)
- {
- using (var command = connection.CreateCommand())
- {
- command.CommandText = $@"
- UPDATE [Messages]
- SET [OutDate] = GETDATE()
- , [State] = ISNULL([State], '') + ISNULL(@{nameof(kvp.Value)}, '')
- WHERE [Id] = @{nameof(kvp.Key)}";
- command.Parameters.Add(new SqlParameter(nameof(kvp.Key), kvp.Key));
- command.Parameters.Add(new SqlParameter(nameof(kvp.Value), kvp.Value));
- command.ExecuteNonQuery();
- command.Parameters.Clear();
- }
-
- updatedCount++;
- }
-
- Console.WriteLine($"{updatedCount}/{countAll} email{(updatedCount == 1 ? null : "s")} sent.");
- LogToFile($"{updatedCount}/{countAll} emails sent.");
- }
- catch (Exception e)
- {
- LogToFile(e);
- }
- }
- else
- {
- LogToFile($"there are no pending emails to send");
- }
- }
- }
-
- private static Boolean SendEmail(MailMessage email)
- {
- try
- {
- using (var smtpClient = new SmtpClient("smtp.xylem.com", 587))
- {
- smtpClient.UseDefaultCredentials = true;
- smtpClient.Send(email);
- }
-
- return true;
- }
- catch (Exception e)
- {
- LogToFile(e);
- }
-
- return false;
- }
-
- private static void LogToFile(Object e)
- => File.AppendAllText(GetOrCreateFile(), $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {e}{Environment.NewLine}");
-
- private static String GetOrCreateFile()
- {
- var logFolder = ConfigurationManager.AppSettings["LogFolder"];
- var logPath = Directory.CreateDirectory(logFolder).FullName;
-
- return Path.Combine(logPath, $"{DateTime.Now:yyyy-MM-dd}.txt");
- }
-
- private static T GetValue(this SqlDataReader sqlDataReader, Int32 index, T defaultValue = default(T))
- {
- var value = defaultValue;
-
- if (0 <= index && index < sqlDataReader.FieldCount && !sqlDataReader.IsDBNull(index))
- {
- var sqlValue = sqlDataReader.GetValue(index);
- var type = Nullable.GetUnderlyingType(typeof(T));
-
- if (type is null)
- {
- type = typeof(T);
- }
-
- try
- {
- sqlValue = Convert.ChangeType(sqlValue, type);
-
- if (sqlValue is T expectedValue)
- {
- value = expectedValue;
- }
- }
- catch (Exception e)
- {
- LogToFile(e);
- }
- }
-
- return value;
- }
- }
-}
+namespace PendingEmails
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Data;
+ using System.Data.SqlClient;
+ using System.IO;
+ using System.Linq;
+ using System.Net.Mail;
+ using System.Threading;
+
+ public static partial class Program
+ {
+ private static void Main()
+ {
+ try
+ {
+ var awaiter = new ManualResetEventSlim();
+
+ while (true)
+ {
+ if (!AppSettings.TryLoadExeConfiguration(out var errors))
+ {
+ WriteLine(new string('=', 50));
+
+ foreach (var error in errors)
+ {
+ WriteLine(error);
+ }
+ }
+ else
+ {
+ WriteLine(new string('=', 50));
+
+ using (var connection = new SqlConnection(AppSettings.MSSQLConnectionString))
+ {
+ OpenConnection(connection);
+
+ FindWarantyEmails(connection);
+ var messages = FindPendingEmails(connection);
+
+ if (messages.Count <= 0)
+ {
+ WriteLine($"Keine neue nachrichten gefunden.");
+ }
+
+ var invalidMessages = messages.Where(x => !x.IsValid).ToList();
+
+ if (invalidMessages.Count > 0)
+ {
+ WriteLine($"{invalidMessages.Count} von {messages.Count} ungültige nachrichten gefunden.");
+ var rowsAffected = SetOutDate(connection, invalidMessages.Select(x => x.Id));
+ WriteLine($"{rowsAffected} von {invalidMessages.Count} wurden als gesended markiert.");
+ }
+ else
+ {
+ WriteLine($"Keine neue ungültige nachrichten gefunden.");
+ }
+
+ var validMessages = messages
+ .Where(x => x.IsValid)
+ .ToList();
+
+ if (validMessages.Count > 0)
+ {
+ WriteLine($"{validMessages.Count} von {messages.Count} gültige nachrichten gefunden.");
+ SendEmails(connection, validMessages);
+ }
+ }
+ }
+
+ awaiter.Wait(AppSettings.Interval);
+ awaiter.Reset();
+ }
+ }
+ catch (Exception e)
+ {
+ WriteLine(e.ToString());
+ }
+ }
+
+ private static void OpenConnection(SqlConnection connection)
+ {
+ connection.FireInfoMessageEventOnUserErrors = true;
+ connection.InfoMessage += (_, args) => WriteLine(args.Message);
+ connection.Open();
+ }
+
+ private static void SendEmails(SqlConnection connection, List messages)
+ {
+ var sentEmails = new List();
+ var excludedRecipients = AppSettings
+ .ExcludeRecipients
+ .ToEmailList();
+
+ foreach (var message in messages)
+ {
+ try
+ {
+ var recipients = message
+ .Recipients
+ .ToEmailList()
+ .Except(excludedRecipients)
+ .ToList();
+
+ if (recipients.Count <= 0)
+ {
+ break;
+ }
+
+ var recipientsCC = message
+ .RecipientsCC
+ .ToEmailList()
+ .Except(excludedRecipients)
+ .ToList();
+
+ var emailMessage = new MailMessage
+ {
+ From = new MailAddress(AppSettings.Sender),
+ Subject = message.Subject,
+ Body = message.Body
+ };
+
+ recipients.ForEach(emailMessage.To.Add);
+ recipientsCC.ForEach(emailMessage.CC.Add);
+
+ using (var smtpClient = new SmtpClient(AppSettings.SMTPHost, AppSettings.SMTPPort))
+ {
+ smtpClient.UseDefaultCredentials = true;
+ smtpClient.Send(emailMessage);
+ }
+
+ sentEmails.Add(message.Id);
+ WriteLine($"Nachricht: {message.Id} wurde gesendet.");
+ }
+ catch (Exception e)
+ {
+ WriteLine(e.ToString());
+ }
+ }
+
+ if (sentEmails.Count > 0)
+ {
+ WriteLine($"Gesendet {sentEmails.Count} von {messages.Count}");
+ var rowsAffected = SetOutDate(connection, sentEmails);
+ WriteLine($"{rowsAffected} von {messages.Count} wurden als gesended markiert.");
+ }
+ else
+ {
+ WriteLine($"Keine nachrichten gesendet.");
+ }
+ }
+
+ private static int SetOutDate(SqlConnection connection, IEnumerable messageIds)
+ {
+ var rowsAffected = default(int);
+
+ using (var command = connection.CreateCommand())
+ {
+ command.CommandText = $@"
+ UPDATE Messages
+ SET OutDate = GETDATE()
+ WHERE Id IN ({string.Join(", ", messageIds)})";
+ rowsAffected = command.ExecuteNonQuery();
+ }
+
+ return rowsAffected;
+ }
+
+ private static List FindPendingEmails(SqlConnection connection)
+ {
+ var messages = new List();
+
+ using (var command = connection.CreateCommand())
+ {
+ command.CommandText = @"
+ SELECT Id
+ , Sender
+ , Subject
+ , Body
+ , Recipients
+ , CC
+ FROM Messages
+ WHERE OutDate IS NULL
+ ORDER BY InDate DESC";
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ var messageId = reader.GetValue(0);
+ var sender = reader.GetValue(1);
+ var subject = reader.GetValue(2);
+ var body = reader.GetValue(3);
+ var recipients = reader.GetValue(4);
+ var recipientsCC = reader.GetValue(5);
+
+ messages.Add(new Message(messageId, sender, subject, body, recipients, recipientsCC));
+ }
+ }
+ }
+
+ return messages;
+ }
+
+ private static void FindWarantyEmails(SqlConnection connection)
+ {
+ using (var command = connection.CreateCommand())
+ {
+ command.CommandTimeout = 60000;
+ command.CommandType = CommandType.StoredProcedure;
+ command.CommandText = @"SP_EMAILS_FUER_GARANTIESCHEINE_LADEN";
+
+ WriteLine($"E-Mails für Garantiescheine gefunden: {command.ExecuteNonQuery()}");
+ }
+ }
+
+ private static void WriteLine(object e)
+ {
+ var logFolder = AppSettings.LogFolder;
+ var logPath = Directory.CreateDirectory(logFolder).FullName;
+ var logFile = Path.Combine(logPath, $"{DateTime.Now:yyyy-MM-dd}.txt");
+ var message = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {e}";
+
+ File.AppendAllText(logFile, message);
+ Console.WriteLine(message.Trim());
+ }
+
+ private static T GetValue(this SqlDataReader sqlDataReader, int index, T defaultValue = default(T))
+ {
+ var value = defaultValue;
+
+ if (0 <= index && index < sqlDataReader.FieldCount && !sqlDataReader.IsDBNull(index))
+ {
+ var sqlValue = sqlDataReader.GetValue(index);
+ var type = Nullable.GetUnderlyingType(typeof(T));
+
+ if (type is null)
+ {
+ type = typeof(T);
+ }
+
+ try
+ {
+ sqlValue = Convert.ChangeType(sqlValue, type);
+
+ if (sqlValue is T expectedValue)
+ {
+ value = expectedValue;
+ }
+ }
+ catch (Exception e)
+ {
+ WriteLine(e);
+ }
+ }
+
+ return value;
+ }
+
+ private static List ToEmailList(this string value)
+ => value
+ ?.ToLower()
+ ?.Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries)
+ ?.Where(x => !string.IsNullOrWhiteSpace(x))
+ ?.ToList()
+ ?? new List();
+ }
+}
diff --git a/Common/PendingEmails/sensus.ico b/Common/PendingEmails/sensus.ico
new file mode 100644
index 00000000..c35853e5
Binary files /dev/null and b/Common/PendingEmails/sensus.ico differ