Bladeren bron

Updating so gut wie fertiggestellt!

Arne Diekmann 8 jaren geleden
bovenliggende
commit
190585bd53

+ 1 - 1
GreenTree.Nachtragsmanagement.Core/AppendixVersion.cs

@@ -15,7 +15,7 @@ namespace GreenTree.Nachtragsmanagement.Core
         {
             get
             {
-                return "0.9.0.1";
+                return "0.9.1.0";
             }
         }
     }

+ 16 - 0
GreenTree.Nachtragsmanagement.Core/Configuration/AppendixConfigurationSection.cs

@@ -42,6 +42,22 @@ namespace GreenTree.Nachtragsmanagement.Core.Configuration
             }
         }
 
+        /// <summary>
+        /// The path of the directory where update packages should be stored
+        /// </summary>
+        [ConfigurationProperty("updateStorePath", IsRequired = false)]
+        public string UpdateStorePath
+        {
+            get
+            {
+                return (string)this["updateStorePath"];
+            }
+            set
+            {
+                this["updateStorePath"] = value;
+            }
+        }
+
         /// <summary>
         /// Settings for mailserver handling
         /// </summary>

+ 121 - 29
GreenTree.Nachtragsmanagement.Web/Controllers/AdminController.cs

@@ -18,6 +18,8 @@ using System.Reflection;
 using System.Net;
 using System.IO;
 using GreenTree.Nachtragsmanagement.Services.Configuration;
+using GreenTree.Nachtragsmanagement.Web.Extensions;
+using System.IO.Compression;
 
 namespace GreenTree.Nachtragsmanagement.Web.Controllers
 {
@@ -493,27 +495,30 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         /// </summary>
         public ActionResult ViewAppInfo()
         {
-            var assemblies = AppDomain.CurrentDomain.GetAssemblies()
-                .Select(a => new AssemblyDataModel
-                {
-                    Name = a.GetName().Name,
-                    Version = a.GetName().Version.ToString(),
-                    Manufacturer =
-                        a.GetCustomAttributes<AssemblyCompanyAttribute>().Any()
-                            ? a.GetCustomAttributes<AssemblyCompanyAttribute>()
-                                .FirstOrDefault().Company
-                            : "Unbekannt"
-                })
-                .OrderBy(a => a.Manufacturer)
-                .ThenBy(a => a.Name)
-                .ToArray();
+            var model = new AppInfoDataModel
+            {
+                BaseDirectory = AppDomain.CurrentDomain.BaseDirectory,
+                IsUpdate = false
+            };
+
+            model.GetAssemblies();
 
+            return View("~/Views/Admin/AppInfo/View.cshtml", model);
+        }
+
+        /// <summary>
+        /// Basic appInfo view function
+        /// </summary>
+        public ActionResult ViewUpdateSuccess()
+        {
             var model = new AppInfoDataModel
             {
-                Assemblies = assemblies,
-                BaseDirectory = AppDomain.CurrentDomain.BaseDirectory
+                BaseDirectory = AppDomain.CurrentDomain.BaseDirectory,
+                IsUpdate = true
             };
 
+            model.GetAssemblies();
+
             return View("~/Views/Admin/AppInfo/View.cshtml", model);
         }
 
@@ -523,25 +528,112 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         [HttpPost]
         public ActionResult CheckUpdate()
         {
-            var model = new AppUpdateDataModel
+            _logger.Information("Updateüberprüfung gestartet.");
+
+            try
             {
-                Package = "GreenTree.Nachtragsmanagement",
-                CurrentVersion = AppendixVersion.CurrentVersion
-            };
+                var model = new AppUpdateDataModel
+                {
+                    Package = "GreenTree.Nachtragsmanagement",
+                    CurrentVersion = AppendixVersion.CurrentVersion
+                };
 
-            var wc = new WebClient();
+                var webResult = String.Empty;
 
-            wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
-            var webData = String.Format("Package={0}&CurrentVersion={1}", model.Package, model.CurrentVersion);
-            var webResult = wc.UploadString(_configurationService.GetCurrentConfiguration().CheckUpdateUrl, webData);
+                using (var wc = new WebClient())
+                {
+                    wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
+                    var webData = String.Format("Package={0}&CurrentVersion={1}", model.Package, model.CurrentVersion);
+                    webResult = wc.UploadString(_configurationService.GetCurrentConfiguration().CheckUpdateUrl, webData);
+                }
 
-            var jsonResult = JsonConvert.DeserializeObject<JsonResult>(webResult);
-            var result = JsonConvert.DeserializeObject<AppUpdateDataModel>(jsonResult.Data.ToString());
+                var jsonResult = JsonConvert.DeserializeObject<JsonResult>(webResult);
+                var result = JsonConvert.DeserializeObject<AppUpdateDataModel>(jsonResult.Data.ToString());
 
-            return new JsonResult
+                if (result.IsUpdateAvailable)
+                    _logger.Information(
+                        String.Format(
+                            "Es ist ein Update verfügbar (Aktuell: {0} - Neu: {1})!", AppendixVersion.CurrentVersion, result.UpdateVersion));
+                else
+                    _logger.Information("Es kein Update verfügbar!");
+
+                return new JsonResult
+                {
+                    Data = result
+                };
+            }
+            catch (Exception ex)
             {
-                Data = result
-            };
+                _logger.Error("Fehler bei der Überprüfung eines Updates", ex);
+
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Update check
+        /// </summary>
+        [HttpPost]
+        public ActionResult Update()
+        {
+            _logger.Information("Update gestartet.");
+
+            try
+            {
+                var model = new AppUpdateDataModel
+                {
+                    Package = "GreenTree.Nachtragsmanagement",
+                    CurrentVersion = AppendixVersion.CurrentVersion
+                };
+
+                var currentConfig = _configurationService.GetCurrentConfiguration();
+
+                AppUpdateDataModel result;
+                string storePath;
+
+                using (var wc = new WebClient())
+                {
+                    wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
+                    var webData = String.Format("Package={0}&CurrentVersion={1}", model.Package, model.CurrentVersion);
+                    var webResult = wc.UploadString(currentConfig.CheckUpdateUrl, webData);
+
+                    var jsonResult = JsonConvert.DeserializeObject<JsonResult>(webResult);
+
+                    result = JsonConvert.DeserializeObject<AppUpdateDataModel>(jsonResult.Data.ToString());
+
+                    storePath = Path.Combine(Server.MapPath(currentConfig.UpdateStorePath), result.PackageFilename);
+
+                    if (System.IO.File.Exists(storePath))
+                        System.IO.File.Delete(storePath);
+
+                    wc.DownloadFile(result.PackagePath, storePath);
+                }
+
+                var hash = HashHelper.GetFileMd5(storePath);
+
+                if (hash != result.PackageMd5Hash)
+                    return null;
+
+                var archive = ZipFile.Open(storePath, ZipArchiveMode.Read);
+                var applicationPath = Server.MapPath("/");
+
+                archive.ExtractToDirectory(applicationPath, true);
+
+                _logger.Information("Update erfolgreich durchgeführt - Anwendung wird neu gestartet!");
+
+                _webHelper.RestartAppDomain(true, "~/admin/viewupdatesuccess");
+
+                return new JsonResult
+                {
+                    Data = "success"
+                };
+            }
+            catch (Exception ex)
+            {
+                _logger.Error("Fehler bei der Durchführung eines Updates", ex);
+
+                throw;
+            }
         }
 
         #endregion

+ 32 - 0
GreenTree.Nachtragsmanagement.Web/Extensions/HashHelper.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Extensions
+{
+    public static class HashHelper
+    {
+        /// <summary>
+        /// Calculates a MD5-Hash value for a specific file
+        /// </summary>
+        /// <param name="filePath">Full path of the file.</param>
+        public static string GetFileMd5(string filePath)
+        {
+            if (!File.Exists(filePath))
+                throw new FileNotFoundException("The specified file does not exist.");
+
+            using (var md5 = MD5.Create())
+            {
+                using (var stream = File.OpenRead(filePath))
+                {
+                    var hash = md5.ComputeHash(stream);
+
+                    return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
+                }
+            }
+        }
+    }
+}

+ 40 - 0
GreenTree.Nachtragsmanagement.Web/Extensions/ZipArchiveExtension.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Extensions
+{
+    public static class ZipArchiveExtension
+    {
+        /// <summary>
+        /// Extracts all entries in a zip file to a target directory on the destination file system
+        /// </summary>
+        /// <param name="archive">The archive.</param>
+        /// <param name="destinationDirectoryName">The target directory path.</param>
+        /// <param name="overwrite">Overwrite existing files.</param>
+        public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
+        {
+            if (!overwrite)
+            {
+                archive.ExtractToDirectory(destinationDirectoryName);
+
+                return;
+            }
+
+            foreach (var file in archive.Entries)
+            {
+                var completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
+                var directory = Path.GetDirectoryName(completeFileName);
+
+                if (!Directory.Exists(directory))
+                    Directory.CreateDirectory(directory);
+
+                if (file.Name != "")
+                    file.ExtractToFile(completeFileName, true);
+            }
+        }
+    }
+}

+ 3 - 0
GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj

@@ -91,6 +91,7 @@
     <Reference Include="System.Data" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.IO.Compression" />
+    <Reference Include="System.IO.Compression.FileSystem" />
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
       <HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
@@ -377,8 +378,10 @@
     <Compile Include="App_Start\WebApiConfig.cs" />
     <Compile Include="Controllers\MiscController.cs" />
     <Compile Include="Extensions\ControlHelper.cs" />
+    <Compile Include="Extensions\HashHelper.cs" />
     <Compile Include="Extensions\MVCxGridViewGeneratorHelper.cs" />
     <Compile Include="Extensions\MVCxGridViewState.cs" />
+    <Compile Include="Extensions\ZipArchiveExtension.cs" />
     <Compile Include="Models\Admin\AppInfo\AppInfoDataModel.cs" />
     <Compile Include="Models\Admin\AppInfo\AppUpdateDataModel.cs" />
     <Compile Include="Models\Admin\AppInfo\AssemblyDataModel.cs" />

+ 24 - 0
GreenTree.Nachtragsmanagement.Web/Models/Admin/AppInfo/AppInfoDataModel.cs

@@ -10,5 +10,29 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.AppInfo
     {
         public AssemblyDataModel[] Assemblies { get; set; }
         public string BaseDirectory { get; set; }
+        public bool IsUpdate { get; set; }
+
+        /// <summary>
+        /// Gets information about every used assembly in local AppDomain
+        /// </summary>
+        public void GetAssemblies()
+        {
+            var assemblies = AppDomain.CurrentDomain.GetAssemblies()
+                .Select(a => new AssemblyDataModel
+                {
+                    Name = a.GetName().Name,
+                    Version = a.GetName().Version.ToString(),
+                    Manufacturer =
+                        a.GetCustomAttributes<AssemblyCompanyAttribute>().Any()
+                            ? a.GetCustomAttributes<AssemblyCompanyAttribute>()
+                                .FirstOrDefault().Company
+                            : "Unbekannt"
+                })
+                .OrderBy(a => a.Manufacturer)
+                .ThenBy(a => a.Name)
+                .ToArray();
+
+            Assemblies = assemblies;
+        }
     }
 }

+ 4 - 0
GreenTree.Nachtragsmanagement.Web/Models/Admin/AppInfo/AppUpdateDataModel.cs

@@ -11,5 +11,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.AppInfo
         public string CurrentVersion { get; set; }
         public string UpdateVersion { get; set; }
         public string UpdateDescription { get; set; }
+        public string PackageFilename { get; set; }
+        public string PackagePath { get; set; }
+        public string PackageMd5Hash { get; set; }
+        public bool IsUpdateAvailable { get; set; }
     }
 }

+ 40 - 2
GreenTree.Nachtragsmanagement.Web/Views/Admin/AppInfo/View.cshtml

@@ -18,10 +18,32 @@
 			method: "POST",
 			url: '@Url.Action("CheckUpdate", "Admin")',
 			success: function (response) {
+				if (!response) return;
 				devLoadingPanelUpdate.Hide();
+				if (response.IsUpdateAvailable == true) {
+					devPopupControlDoUpdate.Show();
+				}
 			},
 			error: function () {
-				 alert("error occured");
+				devLoadingPanelUpdate.Hide();
+				alert("error occured");
+			}
+		});
+	}
+
+	function update() {
+		devPopupControlDoUpdate.Hide();
+		devLoadingPanelUpdate.SetText("Update wird durchgeführt und die Anwendung anschließend neu gestartet... bitte warten!");
+		devLoadingPanelUpdate.Show();
+		$.ajax({
+			method: "POST",
+			url: '@Url.Action("Update", "Admin")',
+			success: function (response) {
+				window.location = '@Url.Action("ViewUpdateSuccess", "Admin")'
+			},
+			error: function () {
+				devLoadingPanelUpdate.Hide();
+				alert("error occured");
 			}
 		});
 	}
@@ -69,6 +91,12 @@
 							t.ClientSideEvents.Click = "function (s, e) { checkUpdate(); }";
 						}).GetHtml();
 					}
+					@if (Model.IsUpdate)
+					{
+						<div style="margin-top: 12px; color: green; font-size: 28px">
+							Update erfolgreich!
+						</div>
+					}
 				</div>
 			</td>
 		</tr>
@@ -81,4 +109,14 @@
 	t.Text = "Es wird nach Updates geprüft... bitte warten!";
 	t.Modal = true;
 	t.Styles.LoadingDiv.Opacity = 0;
-}).GetHtml()
+}).GetHtml()
+
+@Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
+{
+	PopupName = "devPopupControlDoUpdate",
+	Content = "<div class='dialogText' style='padding: 12px'>" +
+		"Es ist ein Update verfügbar. Sind Sie sicher, dass Sie das Update durchführen möchten? " +
+		"Der Vorgang kann einige Zeit in Anspruch nehmen.</div>",
+	HeaderText = "Update durchführen",
+	YesFunction = "function (s, e) { update(); }"
+})

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Web.config

@@ -28,7 +28,7 @@
     <add key="vs:EnableBrowserLink" value="false" />
   </appSettings>
   <appendixSectionGroup>
-    <appendixConfigSection iisAnonymousUser="IUSR" checkUpdateUrl="http://localhost:53759/api/Update/CheckUpdate">
+    <appendixConfigSection iisAnonymousUser="IUSR" checkUpdateUrl="https://greentreestudios.de/AppUpdate/api/Update/CheckUpdate" updateStorePath="~/App_Data/UpdatePackages">
       <mailServer smtpServer="greentreestudios.de" port="25" username="a.diekmann@greentreestudios.de" domain="" password="14595809ad." useSsl="false">
       </mailServer>
       <ldapServer ldapServer="" administriveUser="" password="">