From 9bb8c869e25bc89fcf63862416d5a3f26680b55f Mon Sep 17 00:00:00 2001
From: Niko Ehrenfeuchter <nikolaus.ehrenfeuchter@unibas.ch>
Date: Thu, 2 Nov 2017 18:51:33 +0100
Subject: [PATCH] Add CheckGraceLocation() and GracePeriod property.

The method checks folders in the grace location for their age (parsing
the folder name timestamp) and generates a report for those older than
the given GracePeriod.

This is related to issue #1
---
 AutoTx/AutoTx.cs                           | 53 ++++++++++++++++++++++
 AutoTx/Resources/configuration-example.xml |  3 ++
 AutoTx/XmlWrapper/ServiceConfig.cs         |  6 +++
 3 files changed, 62 insertions(+)

diff --git a/AutoTx/AutoTx.cs b/AutoTx/AutoTx.cs
index 0b028f8..7663811 100644
--- a/AutoTx/AutoTx.cs
+++ b/AutoTx/AutoTx.cs
@@ -6,6 +6,7 @@ using System.ServiceProcess;
 using System.IO;
 using System.Timers;
 using System.DirectoryServices.AccountManagement;
+using System.Globalization;
 using System.Management;
 using AutoTx.XmlWrapper;
 using RoboSharp;
@@ -268,6 +269,7 @@ namespace AutoTx
             writeLogDebug("IncomingDirectory: " + _config.IncomingDirectory);
             writeLogDebug("MarkerFile: " + _config.MarkerFile);
             writeLogDebug("ManagedDirectory: " + _config.ManagedDirectory);
+            writeLogDebug("GracePeriod: " + _config.GracePeriod);
             writeLogDebug("DestinationDirectory: " + _config.DestinationDirectory);
             writeLogDebug("TmpTransferDir: " + _config.TmpTransferDir);
             writeLogDebug("ServiceTimer: " + _config.ServiceTimer);
@@ -299,6 +301,14 @@ namespace AutoTx
                               GetFreeDriveSpace(driveToCheck.DriveName));
             }
             writeLogDebug("");
+
+            writeLogDebug("------ Grace location status ------");
+            try {
+                CheckGraceLocation();
+            }
+            catch (Exception ex) {
+                writeLog("CheckGraceLocation() failed: " + ex.Message, true);
+            }
         }
 
         #endregion
@@ -807,6 +817,9 @@ namespace AutoTx
                     sourceDirectory.Delete();
                     if (sourceDirectory.Parent != null)
                         sourceDirectory.Parent.Delete();
+                    // check age and size of existing folders in the grace location after
+                    // a transfer has completed, trigger a notification if necessary:
+                    CheckGraceLocation();
                     return;
                 }
                 errMsg = "unable to move " + sourceDirectory.FullName;
@@ -953,6 +966,46 @@ namespace AutoTx
                 .Sum(file => file.Length);
         }
 
+        /// <summary>
+        /// Generate a report on expired folders in the grace location.
+        /// 
+        /// Check all user-directories in the grace location for subdirectories whose
+        /// name-timestamp exceeds the configured grace period and generate a summary
+        /// containing the age and size of those directories.
+        /// </summary>
+        public void CheckGraceLocation() {
+            var graceDir = new DirectoryInfo(Path.Combine(_managedPath, "DONE"));
+            var report = "";
+            foreach (var userdir in graceDir.GetDirectories()) {
+                var expired = "";
+                foreach (var subdir in userdir.GetDirectories()) {
+                    DateTime timestamp;
+                    try {
+                        timestamp = DateTime.ParseExact(subdir.Name,
+                            "yyyy-MM-dd__HH-mm-ss", CultureInfo.InvariantCulture);
+                    }
+                    catch (Exception ex) {
+                        writeLogDebug("ERROR parsing timestamp from directory name '" +
+                            subdir.Name + "', skipping: " + ex.Message);
+                        continue;
+                    }
+                    var delta = DateTime.UtcNow - timestamp;
+                    if (delta.Days < _config.GracePeriod)
+                        continue;
+                    var size = GetDirectorySize(subdir.FullName) / MegaBytes;
+                    expired += "   - " + subdir + ": " + size + " MB (age: "
+                        + delta.Days + " days)\n";
+                }
+                if (string.IsNullOrWhiteSpace(expired))
+                    continue;
+                report += "\n - user '" + userdir + "':\n" + expired;
+            }
+            if (string.IsNullOrWhiteSpace(report))
+                return;
+            writeLogDebug("Expired folders in grace location (" + graceDir.FullName + "):\n"
+                + report);
+        }
+
         #endregion
 
     }
diff --git a/AutoTx/Resources/configuration-example.xml b/AutoTx/Resources/configuration-example.xml
index 4f0a545..75d579c 100644
--- a/AutoTx/Resources/configuration-example.xml
+++ b/AutoTx/Resources/configuration-example.xml
@@ -23,6 +23,9 @@
          and to store them for deferred delection after a grace period after
          the transfer (sub-directory "DONE"). -->
 	<ManagedDirectory>ProgramData\AUTOTRANSFER</ManagedDirectory>
+	<!-- GracePeriod: number of days after data in the "DONE" location expires,
+         which will trigger a summary email to the admin address. -->
+	<GracePeriod>5</GracePeriod>
 	<!-- DestinationDirectory: where files should be transferred to -->
 	<DestinationDirectory>\\fileserver.mydomain.xy\share\</DestinationDirectory>
 	<!-- TmpTransferDir: temporary directory relative to DestinationDirectory
diff --git a/AutoTx/XmlWrapper/ServiceConfig.cs b/AutoTx/XmlWrapper/ServiceConfig.cs
index 6586c3e..d840a89 100644
--- a/AutoTx/XmlWrapper/ServiceConfig.cs
+++ b/AutoTx/XmlWrapper/ServiceConfig.cs
@@ -69,6 +69,12 @@ namespace AutoTx.XmlWrapper
         public int AdminNotificationDelta { get; set; }
         public int StorageNotificationDelta { get; set; }
 
+        /// <summary>
+        /// GracePeriod: number of days after data in the "DONE" location expires,
+        /// which will trigger a summary email to the admin address.
+        /// </summary>
+        public int GracePeriod { get; set; }
+
         public bool SendAdminNotification { get; set; }
         public bool SendTransferNotification { get; set; }
         public bool Debug { get; set; }
-- 
GitLab