Explorar el Código

Added "Check For Updates" and "Open Support Session" to System Menu and Support Tickets
"Support Tickets" button is now colored if any "waiting Tickets for Current User are present

frankvandenbos hace 6 meses
padre
commit
89f75ee929

+ 28 - 5
prs.desktop/Forms/Issues/IssuesGrid.cs

@@ -1,19 +1,17 @@
 using Comal.Classes;
-using InABox.Clients;
-using InABox.Configuration;
 using InABox.Core;
 using InABox.DynamicGrid;
-using InABox.Wpf.Editors;
 using InABox.WPF;
 using System;
 using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using System.Windows.Controls;
 using System.Windows.Media;
+using InABox.Wpf;
 
 namespace PRSDesktop.Forms.Issues;
 
@@ -99,6 +97,30 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
 
     protected override void Init()
     {
+        AddButton("Check for Updates", PRSDesktop.Resources.autoupdate.AsBitmapImage(), CheckForUpdates);
+        AddButton("Open Support Session", PRSDesktop.Resources.appicon.AsBitmapImage(), OpenSupportSession);
+    }
+
+    private bool OpenSupportSession(Button button, CoreRow[] rows)
+    {
+        SupportUtils.OpenSupportSession();
+
+        return false;
+    }
+
+    
+
+    private bool CheckForUpdates(Button button, CoreRow[] rows)
+    {
+        if (!SupportUtils.CheckForUpdates())
+        {
+            if (MessageWindow.ShowYesNo(
+                    "You appear to be using the latest version already!\n\nRun the installer anyway?", "Update"))
+            {
+                SupportUtils.DownloadAndRunInstaller();
+            }
+        }
+        return false;
     }
 
     protected override void DoReconfigure(DynamicGridOptions options)
@@ -159,6 +181,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
         {
             text = string.Format("{0:yyyy-MM-dd HH:mm:ss}: {1}", DateTime.Now, text);
             kanban.Notes = kanban.Notes.Concatenate([text]);
+            kanban.Status = KanbanStatus.InProgress;
             SaveItem(kanban);
             Refresh(false, true);
         }

+ 64 - 26
prs.desktop/Forms/Issues/IssuesWindow.xaml.cs

@@ -37,31 +37,42 @@ public partial class IssuesWindow : Window
     {
         Grid.Refresh(true, true);
     }
+    
+    private static Guid? _customerID = null;
 
-    public static void Execute()
+    private static bool CheckCustomerID()
     {
+        if (_customerID is not null)
+            return true;
+        
         var license = Client.Query(new Filter<License>().All(), Columns.None<License>().Add(x => x.Data))
             .ToObjects<License>().FirstOrDefault();
 
-        var customerID = Guid.Empty;
-        if(license is not null && LicenseUtils.TryDecryptLicense(license.Data, out var result, out var error))
+        if (license is not null && LicenseUtils.TryDecryptLicense(license.Data, out var result, out var error))
         {
-            customerID = result.CustomerID;
-        }
-        if(customerID == Guid.Empty)
-        {
-            MessageWindow.ShowMessage("Could not load issues: no customer ID", "Error");
-            return;
+            _customerID = result.CustomerID;
+            return true;
         }
 
+        return false;
+
+    }
+    
+    private static RpcClientSocketTransport? _transport = null;
+
+    private static bool CheckTransport()
+    {
+        if (_transport is not null)
+            return true;
+        
         var transport = new RpcClientSocketTransport(["remote.prsdigital.com.au:8006"]);
         var client = new RpcClient<Kanban>(transport);
         if(client.Validate("SYSTEM", "DO!pt%Qi!R0_h@LW", Guid.Empty).Status != InABox.Clients.ValidationStatus.VALID)
-        {
-            MessageWindow.ShowMessage("Could not connect to PRS digital database.", "Connection error.");
-            return;
-        }
+            return false;
         
+        _transport = transport;
+        return true;
+
         // var transport = new RpcClientSocketTransport(["127.0.0.1:8000"]);
         // var client = new RpcClient<Kanban>(transport);
         // if(client.Validate("frank", "frank", Guid.Empty).Status != InABox.Clients.ValidationStatus.VALID)
@@ -69,25 +80,52 @@ public partial class IssuesWindow : Window
         //     MessageWindow.ShowMessage("Could not connect to PRS digital database.", "Connection error.");
         //     return;
         // }
+    }
 
-        var issues = new IssuesWindow();
 
-        // Save the old property if it exists.
-        //var prop = DatabaseSchema.Property(typeof(Kanban), IssuesGrid.CustomerProperty.Name) as CustomProperty;
+    public static bool Check()
+    {
+        if (!CheckCustomerID())
+            return false;
 
-        // Load the new property.
-        //DatabaseSchema.Load([IssuesGrid.CustomerProperty]);
+        if (!CheckTransport())
+            return false;
 
-        issues.Grid.CustomerID = customerID;
-        issues.ClientFactory = new _Factory(transport);
+        var client = new RpcClient<Kanban>(_transport!);
+        var waiting = client.Query(
+            new Filter<Kanban>(x => x.Closed).IsEqualTo(Guid.Empty)
+                .And(x => x.Status).IsEqualTo(KanbanStatus.Waiting)
+                .And(x=>x.JobLink.Customer.ID).IsEqualTo(_customerID!.Value)
+                .And(x=>x.CreatedBy).IsEqualTo(App.EmployeeName),
+            Columns.None<Kanban>().Add(x => x.LastUpdate),
+            new SortOrder<Kanban>(x => x.LastUpdate, SortDirection.Descending),
+            CoreRange.Database(1)
+        ).Rows.Any();
+        
+        return waiting;
+
+    }
+
+    public static void Execute()
+    {
+        if (!CheckCustomerID())
+        {
+            MessageWindow.ShowMessage("Could not load issues: no customer ID", "Error");
+            return;
+        }
+
+        if (!CheckTransport())
+        {
+            MessageWindow.ShowMessage("Could not connect to PRS digital database.", "Connection error.");
+            return;
+        }
+        
+        var issues = new IssuesWindow();
+
+        issues.Grid.CustomerID = _customerID!.Value;
+        issues.ClientFactory = new _Factory(_transport!);
         issues.ShowDialog();
 
-        // Return DB schema to what it was.
-        // DatabaseSchema.Unload([IssuesGrid.CustomerProperty]);
-        // if(prop is not null)
-        // {
-        //     DatabaseSchema.Load([prop]);
-        // }
     }
 
     private class _Factory(IRpcClientTransport transport) : IQueryProviderFactory

+ 21 - 2
prs.desktop/MainWindow.xaml

@@ -133,7 +133,25 @@
                             Size="Middle"
                             HorizontalAlignment="Stretch"
                             Foreground="{Binding Path=(themes:ThemeManager.BackstageForegroundBrush)}" />
-
+                        
+                        <fluent:Button
+                            x:Name="OpenSupportSessionButton"
+                            Header="Open Support Session"
+                            Click="OpenSupportSession_OnClick"
+                            Size="Middle"
+                            HorizontalAlignment="Stretch"
+                            Foreground="{Binding Path=(themes:ThemeManager.BackstageForegroundBrush)}" />
+                        
+                        <fluent:SeparatorTabItem x:Name="BackstageSeparator2a" Height="20" />
+                        
+                        <fluent:Button
+                            x:Name="CheckForUpdatesButton"
+                            Header="Check For Updates"
+                            Click="CheckForUpdates_OnClick"
+                            Size="Middle"
+                            HorizontalAlignment="Stretch"
+                            Foreground="{Binding Path=(themes:ThemeManager.BackstageForegroundBrush)}" />
+                        
                         <fluent:SeparatorTabItem x:Name="BackstageSeparator2" Height="20" />
 
                         <fluent:Button
@@ -731,8 +749,9 @@
                            Margin="0,0,5,20"/>
             
             <fluent:Button Grid.Row="1" Grid.Column="2"
+                           x:Name="IssuesButton"
                            Header="Support Tickets"
-                           LargeIcon="Resources/appicon.png"
+                           LargeIcon="pack://application:,,,/Resources/appicon.png"
                            Click="Issues_Click"
                            ToolTip="Raise an issue with the PRS team"
                            Margin="0,0,5,20"/>

+ 98 - 60
prs.desktop/MainWindow.xaml.cs

@@ -61,6 +61,7 @@ using Comal.Classes.SecurityDescriptors;
 using System.Threading;
 using H.Formatters;
 using PRSDesktop.Forms.Issues;
+using Brushes = System.Windows.Media.Brushes;
 
 namespace PRSDesktop;
 
@@ -273,7 +274,7 @@ public partial class MainWindow : IPanelHostControl
         Title = $"{(String.Equals(App.Profile?.ToUpper(), "DEFAULT") ? "PRS Desktop" : App.Profile)} (Release {CoreUtils.GetVersion()})";
         
         Logger.Send(LogType.Information, "", "Checking for updates");
-        CheckForUpdates();
+        SupportUtils.CheckForUpdates();
 
         Exception? startupException = null;
         ValidationStatus? loginStatus = null;
@@ -1641,6 +1642,9 @@ public partial class MainWindow : IPanelHostControl
     /// <param name="progress">If not <see langword="null"/>, then rather than opening a new progress window, just uses that.</param>
     private void AfterLogin(IProgress<string>? progress)
     {
+        Logger.Send(LogType.Information, "", "Checking Support Ticket Status");
+        CheckSupportTicketStatus();
+        
         Logger.Send(LogType.Information, "", "Loading employee");
         LoadCurrentEmployee();
         if (CheckTimesheetBypass(true))
@@ -2391,6 +2395,9 @@ public partial class MainWindow : IPanelHostControl
         //{
         try
         {
+
+            CheckSupportTicketStatus();
+            
             bool IsClockedOn = this.IsClockedOn();
 
             if (IsClockedOn)
@@ -2429,6 +2436,17 @@ public partial class MainWindow : IPanelHostControl
         //});
     }
 
+    private void CheckSupportTicketStatus()
+    {
+        Dispatcher.BeginInvoke(() =>
+        {
+            IssuesButton.Background = IssuesWindow.Check()
+                ? new SolidColorBrush(Colors.Red) { Opacity = 0.5 }
+                : Brushes.Transparent;
+
+        });
+    }
+
     private void Notifications_Changed(object sender)
     {
         if (Notifications.IsActive)
@@ -2887,64 +2905,64 @@ public partial class MainWindow : IPanelHostControl
     [DllImport("user32.dll")]
     private static extern IntPtr GetActiveWindow();
 
-    #region Check For Updates
-
-    private string GetUpdateLocation()
-    {
-        if (App.DatabaseSettings.DatabaseType == DatabaseType.Networked)
-        {
-            if(ClientFactory.ClientType == typeof(RestClient<>))
-            {
-                string url = "";
-                //var domain = App.DatabaseSettings.URL.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries).Last();
-                //var port = App.DatabaseSettings.Port;
-                var domain = ClientFactory.Parameters?.FirstOrDefault()?.ToString() ?? "";
-                domain = domain.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? "";
-                if (!String.IsNullOrWhiteSpace(domain))
-                {
-                    
-                    try
-                    {
-                        var client = new HttpClient { BaseAddress = new Uri($"https://{domain}") };
-                        client.GetAsync("operations").Wait();
-                        url = $"https://{domain}";
-                    }
-                    catch (Exception)
-                    {
-                        url = $"http://{domain}";
-                    }
-                }
-                return url;
-            }
-            else
-            {
-                return "";
-            }
-        }
-        else
-            return Path.Combine(CoreUtils.GetCommonAppData("PRSServer"), "update");
-    }
-
-    private string GetLatestVersion(string location)
-    {
-        return Client.Version();
-    }
-    private string GetReleaseNotes(string location)
-    {
-        return Client.ReleaseNotes();
-    }
-    private byte[]? GetInstaller(string location)
-    {
-        return Client.Installer();
-    }
-
-    private void CheckForUpdates()
-    {
-        Update.CheckForUpdates(
-            GetUpdateLocation, GetLatestVersion, GetReleaseNotes, GetInstaller, null, App.AutoUpdateSettings.Elevated, "PRSDesktopSetup.exe");
-    }
-
-    #endregion
+    // #region Check For Updates
+    //
+    // private string GetUpdateLocation()
+    // {
+    //     if (App.DatabaseSettings.DatabaseType == DatabaseType.Networked)
+    //     {
+    //         if(ClientFactory.ClientType == typeof(RestClient<>))
+    //         {
+    //             string url = "";
+    //             //var domain = App.DatabaseSettings.URL.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries).Last();
+    //             //var port = App.DatabaseSettings.Port;
+    //             var domain = ClientFactory.Parameters?.FirstOrDefault()?.ToString() ?? "";
+    //             domain = domain.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? "";
+    //             if (!String.IsNullOrWhiteSpace(domain))
+    //             {
+    //                 
+    //                 try
+    //                 {
+    //                     var client = new HttpClient { BaseAddress = new Uri($"https://{domain}") };
+    //                     client.GetAsync("operations").Wait();
+    //                     url = $"https://{domain}";
+    //                 }
+    //                 catch (Exception)
+    //                 {
+    //                     url = $"http://{domain}";
+    //                 }
+    //             }
+    //             return url;
+    //         }
+    //         else
+    //         {
+    //             return "";
+    //         }
+    //     }
+    //     else
+    //         return Path.Combine(CoreUtils.GetCommonAppData("PRSServer"), "update");
+    // }
+    //
+    // private string GetLatestVersion(string location)
+    // {
+    //     return Client.Version();
+    // }
+    // private string GetReleaseNotes(string location)
+    // {
+    //     return Client.ReleaseNotes();
+    // }
+    // private byte[]? GetInstaller(string location)
+    // {
+    //     return Client.Installer();
+    // }
+    //
+    // private void CheckForUpdates()
+    // {
+    //     Update.CheckForUpdates(
+    //         GetUpdateLocation, GetLatestVersion, GetReleaseNotes, GetInstaller, null, App.AutoUpdateSettings.Elevated, "PRSDesktopSetup.exe");
+    // }
+    //
+    // #endregion
 
     #region Modules + Reports
 
@@ -3304,6 +3322,23 @@ public partial class MainWindow : IPanelHostControl
             MessageBox.Show(logfile + " does not exist!");
         }
     }
+    
+    private void CheckForUpdates_OnClick(object sender, RoutedEventArgs e)
+    {
+        if (!SupportUtils.CheckForUpdates())
+        {
+            if (MessageWindow.ShowYesNo(
+                    "You appear to be using the latest version already!\n\nRun the installer anyway?", "Update"))
+            {
+                SupportUtils.DownloadAndRunInstaller();
+            }
+        }
+    }
+    
+    private void OpenSupportSession_OnClick(object sender, RoutedEventArgs e)
+    {
+        SupportUtils.OpenSupportSession();
+    }
 
     private void DocumentTypeList_OnClick(object sender, RoutedEventArgs e)
     {
@@ -3386,11 +3421,14 @@ public partial class MainWindow : IPanelHostControl
         try
         {
             IssuesWindow.Execute();
+            CheckSupportTicketStatus();
         }
         catch(Exception err)
         {
             MessageWindow.ShowError("Could not load issues.", err);
         }
     }
-    
+
+
+
 }

+ 5 - 0
prs.desktop/PRSDesktop.csproj

@@ -1060,6 +1060,11 @@
         <XamlRuntime>Wpf</XamlRuntime>
         <SubType>Designer</SubType>
       </Page>
+      <Page Update="Utils\DownloadSupportAppWindow.xaml">
+        <Generator>MSBuild:Compile</Generator>
+        <XamlRuntime>Wpf</XamlRuntime>
+        <SubType>Designer</SubType>
+      </Page>
     </ItemGroup>
 
     <Import Project="..\PRS.Scheduler\Comal.TaskScheduler.Shared.projitems" Label="Shared" />

+ 4 - 1
prs.desktop/Panels/Tasks/TaskGrid.cs

@@ -216,7 +216,10 @@ public class TaskGrid : DynamicDataGrid<Kanban>, ITaskControl, IDefaultGrid
 
     public DataModel DataModel(Selection selection)
     {
-        return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).IsEqualTo(Guid.Empty));
+        var ids = ExtractValues<Guid>(x => x.ID, selection);
+        if (!ids.Any())
+            ids = [Guid.Empty];
+        return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).InList(ids.ToArray()));
     }
 
     public void Refresh()

+ 48 - 0
prs.desktop/Utils/DownloadSupportAppWindow.xaml

@@ -0,0 +1,48 @@
+<Window x:Class="PRSDesktop.DownloadSupportAppWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:local="clr-namespace:PRSDesktop"
+        xmlns:wpf="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
+        mc:Ignorable="d"
+        Title="DownloadSupportAppWindow" Height="450" Width="800">
+    <Grid 
+        Margin="5">
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="Auto"/>
+            <ColumnDefinition Width="*" />
+            <ColumnDefinition Width="Auto"/>
+        </Grid.ColumnDefinitions>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+        </Grid.RowDefinitions>
+        <Label
+            Content="Paste URL:"
+            Grid.Row="0"
+            Grid.Column="0"
+            Margin="0,0,5,0"
+            HorizontalContentAlignment="Center"
+            VerticalContentAlignment="Center"/>
+        <TextBox
+            x:Name="URL"
+            Grid.Row="0"
+            Grid.Column="1"
+            VerticalContentAlignment="Center"/>
+        <Button
+            Content=".."
+            Grid.Row="0"
+            Grid.Column="2"
+            Padding="10,0"
+            Margin="5,0,0,0"
+            Click="Download_Click"/>
+        <wpf:WebView2
+            x:Name="Browser"
+            Grid.Row="1"
+            Grid.Column="0"
+            Grid.ColumnSpan="3"
+            Margin="0,5,0,0"
+            NavigationStarting="Browser_OnNavigationStarting" />
+    </Grid> 
+</Window>

+ 38 - 0
prs.desktop/Utils/DownloadSupportAppWindow.xaml.cs

@@ -0,0 +1,38 @@
+using System;
+using System.IO;
+using System.Windows;
+using InABox.Core;
+using Microsoft.Web.WebView2.Core;
+
+namespace PRSDesktop;
+
+public partial class DownloadSupportAppWindow : Window
+{
+    public DownloadSupportAppWindow()
+    {
+        InitializeComponent();
+    }
+
+    private void Download_Click(object sender, RoutedEventArgs e)
+    {
+        Browser.Source = new Uri(URL.Text);
+    }
+
+    private void Browser_OnNavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs e)
+    {
+        Browser.CoreWebView2.DownloadStarting += (o, args) =>
+        {
+            args.ResultFilePath = System.IO.Path.Combine(CoreUtils.GetPath(), "helpwire.exe");
+            args.DownloadOperation.StateChanged += (o, e) =>
+            {
+                if (args.DownloadOperation.State == CoreWebView2DownloadState.Interrupted)
+                {
+                    if (File.Exists(args.ResultFilePath))
+                        File.Delete(args.ResultFilePath);
+                }
+                if (args.DownloadOperation.State == CoreWebView2DownloadState.Completed)
+                    Close();
+            };
+        };
+    }
+}

+ 119 - 0
prs.desktop/Utils/SupportUtils.cs

@@ -0,0 +1,119 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using InABox.Wpf;
+using PRS.Shared;
+
+namespace PRSDesktop;
+
+public static class SupportUtils
+{
+    
+    public static void OpenSupportSession()
+    {
+        var helpwire = Path.Combine(CoreUtils.GetPath(), "helpwire.exe");
+        if (!File.Exists(helpwire))
+        {
+            DownloadSupportAppWindow dl = new DownloadSupportAppWindow();
+            dl.ShowDialog();
+        }
+        if (File.Exists(helpwire))
+        {
+            var startInfo = new ProcessStartInfo(helpwire);
+            startInfo.Verb = "open";
+            startInfo.UseShellExecute = true;
+            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
+            try
+            {
+                Process.Start(startInfo);
+            }
+            catch (System.Exception e)
+            {
+                Logger.Send(LogType.Information,"",$"{e.Message}\n{e.StackTrace}");
+                MessageWindow.ShowError("Unable to launch Support App", e, "Error");
+                try
+                {
+                    if (File.Exists(helpwire))
+                        File.Delete(helpwire);
+                }
+                catch (System.Exception e2)
+                {
+                    Logger.Send(LogType.Information,"",$"{e2.Message}\n{e2.StackTrace}");
+                }
+            }
+        }
+    }
+    
+    public static string GetUpdateLocation()
+    {
+        if (App.DatabaseSettings.DatabaseType == DatabaseType.Networked)
+        {
+            if(ClientFactory.ClientType == typeof(RestClient<>))
+            {
+                string url = "";
+                //var domain = App.DatabaseSettings.URL.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries).Last();
+                //var port = App.DatabaseSettings.Port;
+                var domain = ClientFactory.Parameters?.FirstOrDefault()?.ToString() ?? "";
+                domain = domain.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? "";
+                if (!String.IsNullOrWhiteSpace(domain))
+                {
+                    
+                    try
+                    {
+                        var client = new HttpClient { BaseAddress = new Uri($"https://{domain}") };
+                        client.GetAsync("operations").Wait();
+                        url = $"https://{domain}";
+                    }
+                    catch (Exception)
+                    {
+                        url = $"http://{domain}";
+                    }
+                }
+                return url;
+            }
+            else
+            {
+                return "";
+            }
+        }
+        else
+            return Path.Combine(CoreUtils.GetCommonAppData("PRSServer"), "update");
+    }
+    
+    public static string GetLatestVersion(string location)
+    {
+        return Client.Version();
+    }
+    
+    public static string GetReleaseNotes(string location)
+    {
+        return Client.ReleaseNotes();
+    }
+    
+    public static byte[]? GetInstaller(string location)
+    {
+        return Client.Installer();
+    }
+    
+    public static bool CheckForUpdates()
+    {
+        return Update.CheckForUpdates(
+            GetUpdateLocation, GetLatestVersion, GetReleaseNotes, GetInstaller, null, App.AutoUpdateSettings.Elevated, "PRSDesktopSetup.exe");
+    }
+
+    public static void DownloadAndRunInstaller()
+    {
+        InABox.WPF.Progress.ShowModal("Retrieving Update", progress =>
+        {
+            Update.DownloadAndRunInstaller(GetInstaller, null, App.AutoUpdateSettings.Elevated, GetUpdateLocation(),
+                "PRSDesktopSetup.exe", progress);
+        });
+
+    }
+
+}

+ 39 - 30
prs.shared/Update.cs

@@ -121,38 +121,9 @@ namespace PRS.Shared
                     return true;
                 
                 var bOK = false;
-                var tempinstall = Path.Combine(CoreUtils.GetPath(), tempName);
                 Progress.ShowModal("Retrieving Update", progress =>
                 {
-                    try
-                    {
-                        var installer = getInstaller(location);
-                        if (installer?.Any() == true)
-                        {
-                            File.WriteAllBytes(tempinstall, installer);
-
-                            var scriptFile = Path.Combine(CoreUtils.GetPath(), "install.bat");
-                            File.WriteAllText(scriptFile, GenerateInstallerScript(tempinstall));
-
-                            bOK = true;
-
-                            beforeUpdate?.Invoke();
-                            progress.Report("Launching Installer");
-                            /*var startInfo = new ProcessStartInfo(tempinstall,
-                                " /SILENT /SUPPRESSMSGBOXES /FORCECLOSEAPPLICATIONS /RESTARTAPPLICATIONS");*/
-                            var startInfo = new ProcessStartInfo(scriptFile);
-                            startInfo.Verb = elevated ? "runas" : "open";
-                            startInfo.UseShellExecute = true;
-                            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
-                            var p = Process.Start(startInfo);
-                            p.WaitForExit();
-                        }
-                    }
-                    catch (Exception e)
-                    {
-                        Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
-                        MessageBox.Show("Error during installation!");
-                    }
+                    bOK = DownloadAndRunInstaller(getInstaller, beforeUpdate, elevated, location, tempName, progress);
                 });
                 if (bOK)
                     return true;
@@ -162,5 +133,43 @@ namespace PRS.Shared
             }
             return false;
         }
+
+        public static bool DownloadAndRunInstaller(Func<string, byte[]?>? getInstaller, Action? beforeUpdate, bool elevated, string location,
+            string tempName, IProgress<string> progress)
+        {
+            bool bOK = false;
+            var tempinstall = Path.Combine(CoreUtils.GetPath(), tempName);
+            try
+            {
+                var installer = getInstaller(location);
+                if (installer?.Any() == true)
+                {
+                    File.WriteAllBytes(tempinstall, installer);
+
+                    var scriptFile = Path.Combine(CoreUtils.GetPath(), "install.bat");
+                    File.WriteAllText(scriptFile, GenerateInstallerScript(tempinstall));
+
+                    bOK = true;
+
+                    beforeUpdate?.Invoke();
+                    progress.Report("Launching Installer");
+                    /*var startInfo = new ProcessStartInfo(tempinstall,
+                                " /SILENT /SUPPRESSMSGBOXES /FORCECLOSEAPPLICATIONS /RESTARTAPPLICATIONS");*/
+                    var startInfo = new ProcessStartInfo(scriptFile);
+                    startInfo.Verb = elevated ? "runas" : "open";
+                    startInfo.UseShellExecute = true;
+                    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
+                    var p = Process.Start(startInfo);
+                    p.WaitForExit();
+                }
+            }
+            catch (Exception e)
+            {
+                Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
+                MessageBox.Show("Error during installation!");
+            }
+
+            return bOK;
+        }
     }
 }