SEBWIN-220: Extracted user interface dependencies from all IOperations by introducing ActionRequired, ProgressChanged and StatusChanged events.
This commit is contained in:
parent
0b76770f0f
commit
6acd40eb74
54 changed files with 865 additions and 385 deletions
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using SafeExamBrowser.Contracts.Browser;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
|
@ -18,6 +17,7 @@ using SafeExamBrowser.Contracts.Configuration;
|
|||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
|
@ -97,7 +97,8 @@ namespace SafeExamBrowser.Client
|
|||
logger.Info("Initiating startup procedure...");
|
||||
|
||||
splashScreen = uiFactory.CreateSplashScreen();
|
||||
operations.ProgressIndicator = splashScreen;
|
||||
operations.ProgressChanged += Operations_ProgressChanged;
|
||||
operations.StatusChanged += Operations_StatusChanged;
|
||||
|
||||
var success = operations.TryPerform() == OperationResult.Success;
|
||||
|
||||
|
@ -276,6 +277,39 @@ namespace SafeExamBrowser.Client
|
|||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void Operations_ProgressChanged(ProgressChangedEventArgs args)
|
||||
{
|
||||
if (args.CurrentValue.HasValue)
|
||||
{
|
||||
splashScreen?.SetValue(args.CurrentValue.Value);
|
||||
}
|
||||
|
||||
if (args.IsIndeterminate == true)
|
||||
{
|
||||
splashScreen?.SetIndeterminate();
|
||||
}
|
||||
|
||||
if (args.MaxValue.HasValue)
|
||||
{
|
||||
splashScreen?.SetMaxValue(args.MaxValue.Value);
|
||||
}
|
||||
|
||||
if (args.Progress == true)
|
||||
{
|
||||
splashScreen?.Progress();
|
||||
}
|
||||
|
||||
if (args.Regress == true)
|
||||
{
|
||||
splashScreen?.Regress();
|
||||
}
|
||||
}
|
||||
|
||||
private void Operations_StatusChanged(TextKey status)
|
||||
{
|
||||
splashScreen?.UpdateText(status);
|
||||
}
|
||||
|
||||
private void Runtime_ConnectionLost()
|
||||
{
|
||||
logger.Error("Lost connection to the runtime!");
|
||||
|
@ -285,7 +319,7 @@ namespace SafeExamBrowser.Client
|
|||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void Taskbar_QuitButtonClicked(CancelEventArgs args)
|
||||
private void Taskbar_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
|
||||
{
|
||||
var result = messageBox.Show(TextKey.MessageBox_Quit, TextKey.MessageBox_QuitTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
@ -24,7 +25,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ITaskbar taskbar;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public BrowserOperation(
|
||||
IApplicationController browserController,
|
||||
|
@ -43,7 +45,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing browser...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeBrowser, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeBrowser);
|
||||
|
||||
var browserButton = uiFactory.CreateApplicationButton(browserInfo);
|
||||
|
||||
|
@ -63,7 +65,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Terminating browser...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_TerminateBrowser, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_TerminateBrowser);
|
||||
|
||||
browserController.Terminate();
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ using System.Threading;
|
|||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
|
@ -25,7 +25,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ILogger logger;
|
||||
private int timeout_ms;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged { add { } remove { } }
|
||||
|
||||
public ClientHostDisconnectionOperation(IClientHost clientHost, ILogger logger, int timeout_ms)
|
||||
{
|
||||
|
@ -50,6 +51,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
var disconnectedEvent = new AutoResetEvent(false);
|
||||
var disconnectedEventHandler = new CommunicationEventHandler(() => disconnectedEvent.Set());
|
||||
|
||||
// TODO: Update status!
|
||||
|
||||
clientHost.RuntimeDisconnected += disconnectedEventHandler;
|
||||
|
||||
if (clientHost.IsConnected)
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
|
@ -19,7 +19,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ILogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ClipboardOperation(ILogger logger, INativeMethods nativeMethods)
|
||||
{
|
||||
|
@ -47,7 +48,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private void EmptyClipboard()
|
||||
{
|
||||
logger.Info("Emptying clipboard...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_EmptyClipboard);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_EmptyClipboard);
|
||||
|
||||
nativeMethods.EmptyClipboard();
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
|
@ -22,7 +22,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ILogger logger;
|
||||
private IRuntimeProxy runtime;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ConfigurationOperation(ClientConfiguration configuration, ILogger logger, IRuntimeProxy runtime)
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing application configuration...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
|
@ -21,7 +21,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ILogger logger;
|
||||
private ITaskbar taskbar;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public DisplayMonitorOperation(IDisplayMonitor displayMonitor, ILogger logger, ITaskbar taskbar)
|
||||
{
|
||||
|
@ -33,7 +34,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing working area...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeWorkingArea);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeWorkingArea);
|
||||
|
||||
displayMonitor.PreventSleepMode();
|
||||
displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
|
||||
|
@ -50,7 +51,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Restoring working area...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RestoreWorkingArea);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_RestoreWorkingArea);
|
||||
|
||||
displayMonitor.StopMonitoringDisplayChanges();
|
||||
displayMonitor.ResetPrimaryDisplay();
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
|
@ -21,8 +21,9 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ILogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public KeyboardInterceptorOperation(
|
||||
IKeyboardInterceptor keyboardInterceptor,
|
||||
ILogger logger,
|
||||
|
@ -36,7 +37,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Starting keyboard interception...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartKeyboardInterception);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StartKeyboardInterception);
|
||||
|
||||
nativeMethods.RegisterKeyboardHook(keyboardInterceptor);
|
||||
|
||||
|
@ -51,7 +52,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping keyboard interception...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopKeyboardInterception);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopKeyboardInterception);
|
||||
|
||||
nativeMethods.DeregisterKeyboardHook(keyboardInterceptor);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
|
@ -21,7 +21,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private IMouseInterceptor mouseInterceptor;
|
||||
private INativeMethods nativeMethods;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public MouseInterceptorOperation(
|
||||
ILogger logger,
|
||||
|
@ -36,7 +37,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Starting mouse interception...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartMouseInterception);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StartMouseInterception);
|
||||
|
||||
nativeMethods.RegisterMouseHook(mouseInterceptor);
|
||||
|
||||
|
@ -51,7 +52,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping mouse interception...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopMouseInterception);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopMouseInterception);
|
||||
|
||||
nativeMethods.DeregisterMouseHook(mouseInterceptor);
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
|
@ -21,7 +21,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private IProcessMonitor processMonitor;
|
||||
private Settings settings;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor, Settings settings)
|
||||
{
|
||||
|
@ -33,7 +34,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing process monitoring...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeProcessMonitoring);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeProcessMonitoring);
|
||||
|
||||
if (settings.KioskMode == KioskMode.DisableExplorerShell)
|
||||
{
|
||||
|
@ -51,7 +52,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping process monitoring...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopProcessMonitoring);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopProcessMonitoring);
|
||||
|
||||
if (settings.KioskMode == KioskMode.DisableExplorerShell)
|
||||
{
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
|
@ -22,7 +22,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private IRuntimeProxy runtime;
|
||||
private Guid token;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public RuntimeConnectionOperation(ILogger logger, IRuntimeProxy runtime, Guid token)
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing runtime connection...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeRuntimeConnection);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeRuntimeConnection);
|
||||
|
||||
connected = runtime.Connect(token);
|
||||
|
||||
|
@ -58,7 +59,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Closing runtime connection...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_CloseRuntimeConnection);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_CloseRuntimeConnection);
|
||||
|
||||
if (connected)
|
||||
{
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.SystemComponents;
|
||||
|
@ -32,7 +33,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private IUserInterfaceFactory uiFactory;
|
||||
private IText text;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public TaskbarOperation(
|
||||
ILogger logger,
|
||||
|
@ -63,7 +65,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing taskbar...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeTaskbar);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeTaskbar);
|
||||
|
||||
if (settings.AllowApplicationLog)
|
||||
{
|
||||
|
@ -96,7 +98,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Terminating taskbar...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_TerminateTaskbar);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_TerminateTaskbar);
|
||||
|
||||
if (settings.AllowApplicationLog)
|
||||
{
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
|
@ -21,7 +21,8 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private ILogger logger;
|
||||
private IWindowMonitor windowMonitor;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public WindowMonitorOperation(KioskMode kioskMode, ILogger logger, IWindowMonitor windowMonitor)
|
||||
{
|
||||
|
@ -33,7 +34,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing window monitoring...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeWindowMonitoring);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeWindowMonitoring);
|
||||
|
||||
if (kioskMode == KioskMode.DisableExplorerShell)
|
||||
{
|
||||
|
@ -56,7 +57,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping window monitoring...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopWindowMonitoring);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopWindowMonitoring);
|
||||
|
||||
if (kioskMode != KioskMode.None)
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
CurrentSettings = new Settings();
|
||||
|
||||
CurrentSettings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
CurrentSettings.KioskMode = KioskMode.None;
|
||||
CurrentSettings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
CurrentSettings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all event arguments used for <see cref="IOperationSequence.ProgressChanged"/>.
|
||||
/// </summary>
|
||||
public class ActionRequiredEventArgs
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler used to indicate that an <see cref="IOperation"/> requires user interaction.
|
||||
/// </summary>
|
||||
public delegate void ActionRequiredEventHandler(ActionRequiredEventArgs args);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// The event arguments used for <see cref="IOperationSequence.ProgressChanged"/>.
|
||||
/// </summary>
|
||||
public class ProgressChangedEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the current progress value, if set.
|
||||
/// </summary>
|
||||
public int? CurrentValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the progress value is indeterminate, if set.
|
||||
/// </summary>
|
||||
public bool? IsIndeterminate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum progress value, if set.
|
||||
/// </summary>
|
||||
public int? MaxValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the current progress value has increased by 1, if set.
|
||||
/// </summary>
|
||||
public bool? Progress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the current progress value has decreased by 1, if set.
|
||||
/// </summary>
|
||||
public bool? Regress { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler used to indicate that the progress of an <see cref="IOperationSequence"/> has changed.
|
||||
/// </summary>
|
||||
public delegate void ProgressChangedEventHandler(ProgressChangedEventArgs args);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler used to indicate that the status of an <see cref="IOperation"/> has changed.
|
||||
/// </summary>
|
||||
public delegate void StatusChangedEventHandler(TextKey status);
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel
|
||||
{
|
||||
|
@ -16,9 +16,14 @@ namespace SafeExamBrowser.Contracts.Core.OperationModel
|
|||
public interface IOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// The progress indicator to be used to show status information to the user. Will be ignored if <c>null</c>.
|
||||
/// Event fired when the operation requires user interaction.
|
||||
/// </summary>
|
||||
IProgressIndicator ProgressIndicator { set; }
|
||||
event ActionRequiredEventHandler ActionRequired;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the status of the operation has changed.
|
||||
/// </summary>
|
||||
event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Performs the operation.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Core.OperationModel
|
||||
{
|
||||
|
@ -24,9 +24,19 @@ namespace SafeExamBrowser.Contracts.Core.OperationModel
|
|||
public interface IOperationSequence
|
||||
{
|
||||
/// <summary>
|
||||
/// The progress indicator to be used when executing an operation. Will be ignored if <c>null</c>.
|
||||
/// Event fired when an operation requires user interaction.
|
||||
/// </summary>
|
||||
IProgressIndicator ProgressIndicator { set; }
|
||||
event ActionRequiredEventHandler ActionRequired;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the progress of the sequence has changed.
|
||||
/// </summary>
|
||||
event ProgressChangedEventHandler ProgressChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the status of an operation has changed.
|
||||
/// </summary>
|
||||
event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to perform the operations of this sequence according to their initialized order. If any operation fails, the already
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
PasswordDialog_Confirm,
|
||||
PasswordDialog_SettingsPasswordRequired,
|
||||
PasswordDialog_SettingsPasswordRequiredTitle,
|
||||
// TODO: Rename these...
|
||||
ProgressIndicator_CloseRuntimeConnection,
|
||||
ProgressIndicator_EmptyClipboard,
|
||||
ProgressIndicator_FinalizeServiceSession,
|
||||
|
|
|
@ -57,6 +57,11 @@
|
|||
<Compile Include="Core\IApplicationController.cs" />
|
||||
<Compile Include="Core\InstanceIdentifier.cs" />
|
||||
<Compile Include="Core\IRuntimeController.cs" />
|
||||
<Compile Include="Core\OperationModel\Events\ActionRequiredEventArgs.cs" />
|
||||
<Compile Include="Core\OperationModel\Events\ActionRequiredEventHandler.cs" />
|
||||
<Compile Include="Core\OperationModel\Events\ProgressChangedEventArgs.cs" />
|
||||
<Compile Include="Core\OperationModel\Events\ProgressChangedEventHandler.cs" />
|
||||
<Compile Include="Core\OperationModel\Events\StatusChangedEventHandler.cs" />
|
||||
<Compile Include="Core\OperationModel\IOperationSequence.cs" />
|
||||
<Compile Include="Core\OperationModel\OperationResult.cs" />
|
||||
<Compile Include="Browser\DownloadEventArgs.cs" />
|
||||
|
|
|
@ -16,14 +16,14 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
public interface IProgressIndicator
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the progress value according to the specified amount.
|
||||
/// Increases the current progress value by 1.
|
||||
/// </summary>
|
||||
void Progress(int amount = 1);
|
||||
void Progress();
|
||||
|
||||
/// <summary>
|
||||
/// Regresses the progress value according to the specified amount.
|
||||
/// Decreases the current progress value by 1.
|
||||
/// </summary>
|
||||
void Regress(int amount = 1);
|
||||
void Regress();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the style of the progress indicator to indeterminate (<c>Progress</c> and <c>Regress</c> won't have any effect when called).
|
||||
|
@ -42,6 +42,7 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
|
||||
/// <summary>
|
||||
/// Updates the status text. If the busy flag is set, an animation will be shown to indicate a long-running operation.
|
||||
/// TODO: Automatically show busy indication in implementations after e.g. 2 seconds!
|
||||
/// </summary>
|
||||
void UpdateText(TextKey key, bool showBusyIndication = false);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.UserInterface.MessageBox
|
||||
{
|
||||
|
@ -18,11 +19,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.MessageBox
|
|||
/// <summary>
|
||||
/// Shows a message box according to the specified parameters and returns the result chosen by the user.
|
||||
/// </summary>
|
||||
MessageBoxResult Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information);
|
||||
MessageBoxResult Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information, IWindow parent = null);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a message box according to the specified parameters and returns the result chosen by the user.
|
||||
/// </summary>
|
||||
MessageBoxResult Show(TextKey message, TextKey title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information);
|
||||
MessageBoxResult Show(TextKey message, TextKey title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information, IWindow parent = null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Core.OperationModel;
|
||||
|
||||
namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||
|
@ -251,10 +250,8 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
|||
public void MustNotFailInCaseOfUnexpectedError()
|
||||
{
|
||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||
var indicatorMock = new Mock<IProgressIndicator>();
|
||||
|
||||
indicatorMock.Setup(i => i.SetMaxValue(It.IsAny<int>())).Throws<Exception>();
|
||||
sut.ProgressIndicator = indicatorMock.Object;
|
||||
sut.ProgressChanged += (args) => throw new Exception();
|
||||
|
||||
var result = sut.TryPerform();
|
||||
|
||||
|
@ -406,10 +403,8 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
|||
public void MustNotFailInCaseOfUnexpectedErrorWhenRepeating()
|
||||
{
|
||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||
var indicatorMock = new Mock<IProgressIndicator>();
|
||||
|
||||
indicatorMock.Setup(i => i.SetMaxValue(It.IsAny<int>())).Throws<Exception>();
|
||||
sut.ProgressIndicator = indicatorMock.Object;
|
||||
sut.ProgressChanged += (args) => throw new Exception();
|
||||
|
||||
var result = sut.TryRepeat();
|
||||
|
||||
|
@ -570,10 +565,8 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
|||
public void MustNotFailInCaseOfUnexpectedErrorWhenReverting()
|
||||
{
|
||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||
var indicatorMock = new Mock<IProgressIndicator>();
|
||||
|
||||
indicatorMock.Setup(i => i.SetIndeterminate()).Throws<Exception>();
|
||||
sut.ProgressIndicator = indicatorMock.Object;
|
||||
sut.ProgressChanged += (args) => throw new Exception();
|
||||
|
||||
var success = sut.TryRevert();
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SafeExamBrowser.Core.OperationModel;
|
||||
|
||||
namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||
{
|
||||
[TestClass]
|
||||
public class QueueExtensionTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void MustCorrectlyIterateThroughQueue()
|
||||
{
|
||||
var order = 0;
|
||||
var queue = new Queue<int>(Enumerable.Range(1, 25));
|
||||
var action = new Action<int>(i =>
|
||||
{
|
||||
Assert.AreEqual(i, ++order);
|
||||
Assert.AreEqual(queue.ElementAt(i - 1), i);
|
||||
});
|
||||
|
||||
queue.ForEach(action);
|
||||
|
||||
Assert.AreEqual(queue.Count, order);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,8 @@ using System;
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Core.Operations;
|
||||
|
||||
namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||
|
@ -94,23 +95,47 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustUpdateProgressIndicator()
|
||||
public void MustCorrectlyHandleEventSubscription()
|
||||
{
|
||||
IOperation initialize()
|
||||
{
|
||||
return operationMock.Object;
|
||||
};
|
||||
|
||||
var sut = new LazyInitializationOperation(initialize)
|
||||
{
|
||||
ProgressIndicator = new Mock<IProgressIndicator>().Object
|
||||
};
|
||||
var actionRequired = 0;
|
||||
var actionRequiredHandler = new ActionRequiredEventHandler(args => actionRequired++);
|
||||
var statusChanged = 0;
|
||||
var statusChangedHandler = new StatusChangedEventHandler(t => statusChanged++);
|
||||
var sut = new LazyInitializationOperation(initialize);
|
||||
|
||||
sut.ActionRequired += actionRequiredHandler;
|
||||
sut.StatusChanged += statusChangedHandler;
|
||||
|
||||
sut.Perform();
|
||||
sut.Repeat();
|
||||
sut.Revert();
|
||||
|
||||
operationMock.VerifySet(o => o.ProgressIndicator = It.IsAny<IProgressIndicator>(), Times.Exactly(3));
|
||||
operationMock.Raise(o => o.ActionRequired += null, new ActionRequiredEventArgs());
|
||||
operationMock.Raise(o => o.StatusChanged += null, default(TextKey));
|
||||
|
||||
Assert.AreEqual(1, actionRequired);
|
||||
Assert.AreEqual(1, statusChanged);
|
||||
|
||||
sut.ActionRequired -= actionRequiredHandler;
|
||||
sut.StatusChanged -= statusChangedHandler;
|
||||
|
||||
operationMock.Raise(o => o.ActionRequired += null, new ActionRequiredEventArgs());
|
||||
operationMock.Raise(o => o.StatusChanged += null, default(TextKey));
|
||||
|
||||
Assert.AreEqual(1, actionRequired);
|
||||
Assert.AreEqual(1, statusChanged);
|
||||
|
||||
sut.ActionRequired += actionRequiredHandler;
|
||||
sut.StatusChanged += statusChangedHandler;
|
||||
|
||||
operationMock.Raise(o => o.ActionRequired += null, new ActionRequiredEventArgs());
|
||||
operationMock.Raise(o => o.StatusChanged += null, default(TextKey));
|
||||
|
||||
Assert.AreEqual(2, actionRequired);
|
||||
Assert.AreEqual(2, statusChanged);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="OperationModel\QueueExtensionTests.cs" />
|
||||
<Compile Include="Operations\CommunicationHostOperationTests.cs" />
|
||||
<Compile Include="Operations\LazyInitializationOperationTests.cs" />
|
||||
<Compile Include="Operations\I18nOperationTests.cs" />
|
||||
|
|
|
@ -10,8 +10,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.OperationModel
|
||||
{
|
||||
|
@ -24,7 +24,19 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
private Queue<IOperation> operations = new Queue<IOperation>();
|
||||
private Stack<IOperation> stack = new Stack<IOperation>();
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired
|
||||
{
|
||||
add { operations.ForEach(o => o.ActionRequired += value); }
|
||||
remove { operations.ForEach(o => o.ActionRequired -= value); }
|
||||
}
|
||||
|
||||
public event ProgressChangedEventHandler ProgressChanged;
|
||||
|
||||
public event StatusChangedEventHandler StatusChanged
|
||||
{
|
||||
add { operations.ForEach(o => o.StatusChanged += value); }
|
||||
remove { operations.ForEach(o => o.StatusChanged -= value); }
|
||||
}
|
||||
|
||||
public OperationSequence(ILogger logger, Queue<IOperation> operations)
|
||||
{
|
||||
|
@ -92,12 +104,11 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
{
|
||||
if (indeterminate)
|
||||
{
|
||||
ProgressIndicator?.SetIndeterminate();
|
||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { IsIndeterminate = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgressIndicator?.SetValue(0);
|
||||
ProgressIndicator?.SetMaxValue(operations.Count);
|
||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { CurrentValue = 0, MaxValue = operations.Count });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +122,6 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
|
||||
try
|
||||
{
|
||||
operation.ProgressIndicator = ProgressIndicator;
|
||||
result = operation.Perform();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -124,7 +134,7 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
return result;
|
||||
}
|
||||
|
||||
ProgressIndicator?.Progress();
|
||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { Progress = true });
|
||||
}
|
||||
|
||||
return OperationResult.Success;
|
||||
|
@ -138,7 +148,6 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
|
||||
try
|
||||
{
|
||||
operation.ProgressIndicator = ProgressIndicator;
|
||||
result = operation.Repeat();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -151,7 +160,7 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
return result;
|
||||
}
|
||||
|
||||
ProgressIndicator?.Progress();
|
||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { Progress = true });
|
||||
}
|
||||
|
||||
return OperationResult.Success;
|
||||
|
@ -167,7 +176,6 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
|
||||
try
|
||||
{
|
||||
operation.ProgressIndicator = ProgressIndicator;
|
||||
operation.Revert();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -178,7 +186,7 @@ namespace SafeExamBrowser.Core.OperationModel
|
|||
|
||||
if (regress)
|
||||
{
|
||||
ProgressIndicator?.Regress();
|
||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { Regress = true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
SafeExamBrowser.Core/OperationModel/QueueExtensions.cs
Normal file
24
SafeExamBrowser.Core/OperationModel/QueueExtensions.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SafeExamBrowser.Core.OperationModel
|
||||
{
|
||||
internal static class QueueExtensions
|
||||
{
|
||||
internal static void ForEach<T>(this Queue<T> queue, Action<T> action)
|
||||
{
|
||||
foreach (var element in queue)
|
||||
{
|
||||
action(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Operations
|
||||
{
|
||||
|
@ -23,7 +23,8 @@ namespace SafeExamBrowser.Core.Operations
|
|||
private ICommunicationHost host;
|
||||
private ILogger logger;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public CommunicationHostOperation(ICommunicationHost host, ILogger logger)
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace SafeExamBrowser.Core.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Starting communication host...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartCommunicationHost);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StartCommunicationHost);
|
||||
|
||||
host.Start();
|
||||
|
||||
|
@ -46,7 +47,7 @@ namespace SafeExamBrowser.Core.Operations
|
|||
if (!host.IsRunning)
|
||||
{
|
||||
logger.Info("Restarting communication host...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RestartCommunicationHost);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_RestartCommunicationHost);
|
||||
|
||||
host.Stop();
|
||||
host.Start();
|
||||
|
@ -58,7 +59,7 @@ namespace SafeExamBrowser.Core.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping communication host...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopCommunicationHost);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopCommunicationHost);
|
||||
|
||||
host.Stop();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Core.Operations
|
||||
{
|
||||
|
@ -22,7 +22,8 @@ namespace SafeExamBrowser.Core.Operations
|
|||
private Action repeat;
|
||||
private Action revert;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged { add { } remove { } }
|
||||
|
||||
public DelegateOperation(Action perform, Action repeat = null, Action revert = null)
|
||||
{
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
using System.Globalization;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Operations
|
||||
{
|
||||
|
@ -23,7 +23,8 @@ namespace SafeExamBrowser.Core.Operations
|
|||
private IText text;
|
||||
private ITextResource textResource;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged { add { } remove { } }
|
||||
|
||||
public I18nOperation(ILogger logger, IText text, ITextResource textResource)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Core.Operations
|
||||
{
|
||||
|
@ -22,7 +22,52 @@ namespace SafeExamBrowser.Core.Operations
|
|||
private Func<IOperation> initialize;
|
||||
private IOperation operation;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { get; set; }
|
||||
private event ActionRequiredEventHandler ActionRequiredImpl;
|
||||
private event StatusChangedEventHandler StatusChangedImpl;
|
||||
|
||||
public event ActionRequiredEventHandler ActionRequired
|
||||
{
|
||||
add
|
||||
{
|
||||
ActionRequiredImpl += value;
|
||||
|
||||
if (operation != null)
|
||||
{
|
||||
operation.ActionRequired += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
ActionRequiredImpl -= value;
|
||||
|
||||
if (operation != null)
|
||||
{
|
||||
operation.ActionRequired -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event StatusChangedEventHandler StatusChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
StatusChangedImpl += value;
|
||||
|
||||
if (operation != null)
|
||||
{
|
||||
operation.StatusChanged += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
StatusChangedImpl -= value;
|
||||
|
||||
if (operation != null)
|
||||
{
|
||||
operation.StatusChanged -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LazyInitializationOperation(Func<IOperation> initialize)
|
||||
{
|
||||
|
@ -32,21 +77,19 @@ namespace SafeExamBrowser.Core.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
operation = initialize.Invoke();
|
||||
operation.ProgressIndicator = ProgressIndicator;
|
||||
operation.ActionRequired += ActionRequiredImpl;
|
||||
operation.StatusChanged += StatusChangedImpl;
|
||||
|
||||
return operation.Perform();
|
||||
}
|
||||
|
||||
public OperationResult Repeat()
|
||||
{
|
||||
operation.ProgressIndicator = ProgressIndicator;
|
||||
|
||||
return operation.Repeat();
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
operation.ProgressIndicator = ProgressIndicator;
|
||||
operation.Revert();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
|
@ -14,6 +15,7 @@ using System.Runtime.InteropServices;
|
|||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: InternalsVisibleTo("SafeExamBrowser.Core.UnitTests")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("3d6fdbb6-a4af-4626-bb2b-bf329d44f9cc")]
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="OperationModel\QueueExtensions.cs" />
|
||||
<Compile Include="Operations\CommunicationHostOperation.cs" />
|
||||
<Compile Include="Operations\LazyInitializationOperation.cs" />
|
||||
<Compile Include="Operations\I18nOperation.cs" />
|
||||
|
|
|
@ -11,18 +11,13 @@ using System.IO;
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
using SafeExamBrowser.Runtime.Operations;
|
||||
using SafeExamBrowser.Runtime.Operations.Events;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||
{
|
||||
|
@ -31,14 +26,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
{
|
||||
private AppConfig appConfig;
|
||||
private Mock<ILogger> logger;
|
||||
private Mock<IMessageBox> messageBox;
|
||||
private Mock<IPasswordDialog> passwordDialog;
|
||||
private Mock<IConfigurationRepository> repository;
|
||||
private Mock<IResourceLoader> resourceLoader;
|
||||
private Mock<IRuntimeHost> runtimeHost;
|
||||
private Settings settings;
|
||||
private Mock<IText> text;
|
||||
private Mock<IUserInterfaceFactory> uiFactory;
|
||||
private ConfigurationOperation sut;
|
||||
|
||||
[TestInitialize]
|
||||
|
@ -46,22 +36,15 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
{
|
||||
appConfig = new AppConfig();
|
||||
logger = new Mock<ILogger>();
|
||||
messageBox = new Mock<IMessageBox>();
|
||||
passwordDialog = new Mock<IPasswordDialog>();
|
||||
repository = new Mock<IConfigurationRepository>();
|
||||
resourceLoader = new Mock<IResourceLoader>();
|
||||
runtimeHost = new Mock<IRuntimeHost>();
|
||||
settings = new Settings();
|
||||
text = new Mock<IText>();
|
||||
uiFactory = new Mock<IUserInterfaceFactory>();
|
||||
|
||||
appConfig.AppDataFolder = @"C:\Not\Really\AppData";
|
||||
appConfig.DefaultSettingsFileName = "SettingsDummy.txt";
|
||||
appConfig.ProgramDataFolder = @"C:\Not\Really\ProgramData";
|
||||
|
||||
repository.SetupGet(r => r.CurrentSettings).Returns(settings);
|
||||
|
||||
uiFactory.Setup(f => f.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(passwordDialog.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -75,7 +58,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
var resource = new Uri(url);
|
||||
|
@ -93,7 +76,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
var resource = new Uri(Path.Combine(location, "SettingsDummy.txt"));
|
||||
|
@ -110,7 +93,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
var resource = new Uri(Path.Combine(location, "SettingsDummy.txt"));
|
||||
|
@ -121,7 +104,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void MustFallbackToDefaultsAsLastPrio()
|
||||
{
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Once);
|
||||
|
@ -131,10 +114,16 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
public void MustAbortIfWishedByUser()
|
||||
{
|
||||
appConfig.ProgramDataFolder = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations));
|
||||
messageBox.Setup(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is ConfigurationCompletedEventArgs c)
|
||||
{
|
||||
c.AbortStartup = true;
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -144,10 +133,16 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void MustNotAbortIfNotWishedByUser()
|
||||
{
|
||||
messageBox.Setup(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is ConfigurationCompletedEventArgs c)
|
||||
{
|
||||
c.AbortStartup = false;
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -160,10 +155,16 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
settings.ConfigurationMode = ConfigurationMode.Exam;
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut.Perform();
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is ConfigurationCompletedEventArgs c)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
};
|
||||
|
||||
messageBox.Verify(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>()), Times.Never);
|
||||
sut.Perform();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -171,10 +172,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
{
|
||||
repository.Setup(r => r.LoadDefaultSettings());
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
sut.Perform();
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new string[] { });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new string[] { });
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Exactly(2));
|
||||
|
@ -185,20 +186,26 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
{
|
||||
var uri = @"an/invalid\uri.'*%yolo/()你好";
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", uri });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", uri });
|
||||
sut.Perform();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustOnlyAllowToEnterAdminPasswordFiveTimes()
|
||||
{
|
||||
var result = new PasswordDialogResultStub { Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.AdminPasswordNeeded);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Success = true;
|
||||
}
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Exactly(5));
|
||||
|
@ -207,13 +214,19 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void MustOnlyAllowToEnterSettingsPasswordFiveTimes()
|
||||
{
|
||||
var result = new PasswordDialogResultStub { Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Success = true;
|
||||
}
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Exactly(5));
|
||||
|
@ -223,14 +236,21 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
public void MustSucceedIfAdminPasswordCorrect()
|
||||
{
|
||||
var password = "test";
|
||||
var result = new PasswordDialogResultStub { Password = password, Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.AdminPasswordNeeded);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), password, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Password = password;
|
||||
p.Success = true;
|
||||
}
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Once);
|
||||
|
@ -241,14 +261,21 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
public void MustSucceedIfSettingsPasswordCorrect()
|
||||
{
|
||||
var password = "test";
|
||||
var result = new PasswordDialogResultStub { Password = password, Success = true };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(result);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, password)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Password = password;
|
||||
p.Success = true;
|
||||
}
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Once);
|
||||
|
@ -258,13 +285,18 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void MustAbortAskingForAdminPasswordIfDecidedByUser()
|
||||
{
|
||||
var dialogResult = new PasswordDialogResultStub { Success = false };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(dialogResult);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.AdminPasswordNeeded);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Success = false;
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -274,13 +306,18 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void MustAbortAskingForSettingsPasswordIfDecidedByUser()
|
||||
{
|
||||
var dialogResult = new PasswordDialogResultStub { Success = false };
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(dialogResult);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Success = false;
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -291,18 +328,23 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
public void MustAllowEnteringBothPasswords()
|
||||
{
|
||||
var adminPassword = "xyz";
|
||||
var adminResult = new PasswordDialogResultStub { Password = adminPassword, Success = true };
|
||||
var adminCallback = new Action(() => passwordDialog.Setup(d => d.Show(null)).Returns(adminResult));
|
||||
var settingsPassword = "abc";
|
||||
var settingsResult = new PasswordDialogResultStub { Password = settingsPassword, Success = true };
|
||||
var settingsCallback = new Action(() => passwordDialog.Setup(d => d.Show(null)).Returns(settingsResult));
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded).Callback(settingsCallback);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, settingsPassword)).Returns(LoadStatus.AdminPasswordNeeded).Callback(adminCallback);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, settingsPassword)).Returns(LoadStatus.AdminPasswordNeeded);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), adminPassword, settingsPassword)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
sut.ActionRequired += args =>
|
||||
{
|
||||
if (args is PasswordRequiredEventArgs p)
|
||||
{
|
||||
p.Password = p.Purpose == PasswordRequestPurpose.Administrator ? adminPassword : settingsPassword;
|
||||
p.Success = true;
|
||||
}
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), null, null), Times.Once);
|
||||
|
@ -310,79 +352,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
repository.Verify(r => r.LoadSettings(It.IsAny<Uri>(), adminPassword, settingsPassword), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustRequestPasswordViaDialogOnDefaultDesktop()
|
||||
{
|
||||
var clientProxy = new Mock<IClientProxy>();
|
||||
var session = new Mock<ISessionData>();
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true });
|
||||
repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
settings.KioskMode = KioskMode.DisableExplorerShell;
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
clientProxy.Verify(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>()), Times.Never);
|
||||
passwordDialog.Verify(p => p.Show(null), Times.AtLeastOnce);
|
||||
session.VerifyGet(s => s.ClientProxy, Times.Never);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustRequestPasswordViaClientDuringReconfigurationOnNewDesktop()
|
||||
{
|
||||
var clientProxy = new Mock<IClientProxy>();
|
||||
var communication = new CommunicationResult(true);
|
||||
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||
{
|
||||
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = true });
|
||||
});
|
||||
var session = new Mock<ISessionData>();
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication).Callback(passwordReceived);
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true });
|
||||
repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut.Perform();
|
||||
|
||||
clientProxy.Verify(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>()), Times.AtLeastOnce);
|
||||
passwordDialog.Verify(p => p.Show(null), Times.Never);
|
||||
session.VerifyGet(s => s.ClientProxy, Times.AtLeastOnce);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustAbortAskingForPasswordViaClientIfDecidedByUser()
|
||||
{
|
||||
var clientProxy = new Mock<IClientProxy>();
|
||||
var communication = new CommunicationResult(true);
|
||||
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||
{
|
||||
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = false });
|
||||
});
|
||||
var session = new Mock<ISessionData>();
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication).Callback(passwordReceived);
|
||||
repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
Assert.AreEqual(OperationResult.Aborted, result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotWaitForPasswordViaClientIfCommunicationHasFailed()
|
||||
{
|
||||
|
@ -397,7 +366,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -412,7 +381,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
resourceLoader.Setup(r => r.IsHtmlResource(It.IsAny<Uri>())).Returns(false);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.InvalidData);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -427,7 +396,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
resourceLoader.Setup(r => r.IsHtmlResource(It.IsAny<Uri>())).Returns(true);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.InvalidData);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
|
@ -444,7 +413,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
repository.SetupGet(r => r.ReconfigurationFilePath).Returns(resource.AbsolutePath);
|
||||
repository.Setup(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(resource)), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
|
||||
var result = sut.Repeat();
|
||||
|
||||
|
@ -461,7 +430,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|||
repository.SetupGet(r => r.ReconfigurationFilePath).Returns(null as string);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.Success);
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, null);
|
||||
|
||||
var result = sut.Repeat();
|
||||
|
||||
|
|
|
@ -18,5 +18,78 @@ namespace SafeExamBrowser.Runtime.UnitTests
|
|||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
//[TestMethod]
|
||||
//public void MustRequestPasswordViaDialogOnDefaultDesktop()
|
||||
//{
|
||||
// var clientProxy = new Mock<IClientProxy>();
|
||||
// var session = new Mock<ISessionData>();
|
||||
// var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
// passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true });
|
||||
// repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
// repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
// session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
// settings.KioskMode = KioskMode.DisableExplorerShell;
|
||||
|
||||
// sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
// sut.Perform();
|
||||
|
||||
// clientProxy.Verify(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>()), Times.Never);
|
||||
// passwordDialog.Verify(p => p.Show(null), Times.AtLeastOnce);
|
||||
// session.VerifyGet(s => s.ClientProxy, Times.Never);
|
||||
//}
|
||||
|
||||
//[TestMethod]
|
||||
//public void MustRequestPasswordViaClientDuringReconfigurationOnNewDesktop()
|
||||
//{
|
||||
// var clientProxy = new Mock<IClientProxy>();
|
||||
// var communication = new CommunicationResult(true);
|
||||
// var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||
// {
|
||||
// runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = true });
|
||||
// });
|
||||
// var session = new Mock<ISessionData>();
|
||||
// var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
// clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication).Callback(passwordReceived);
|
||||
// passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true });
|
||||
// repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
// repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
// session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
// settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
|
||||
// sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
// sut.Perform();
|
||||
|
||||
// clientProxy.Verify(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>()), Times.AtLeastOnce);
|
||||
// passwordDialog.Verify(p => p.Show(null), Times.Never);
|
||||
// session.VerifyGet(s => s.ClientProxy, Times.AtLeastOnce);
|
||||
//}
|
||||
|
||||
//[TestMethod]
|
||||
//public void MustAbortAskingForPasswordViaClientIfDecidedByUser()
|
||||
//{
|
||||
// var clientProxy = new Mock<IClientProxy>();
|
||||
// var communication = new CommunicationResult(true);
|
||||
// var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||
// {
|
||||
// runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = false });
|
||||
// });
|
||||
// var session = new Mock<ISessionData>();
|
||||
// var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
// clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication).Callback(passwordReceived);
|
||||
// repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
// repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
// session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
// settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
|
||||
// sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, resourceLoader.Object, new[] { "blubb.exe", url });
|
||||
|
||||
// var result = sut.Perform();
|
||||
|
||||
// Assert.AreEqual(OperationResult.Aborted, result);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,6 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Operations\ConfigurationOperationTests.cs" />
|
||||
<Compile Include="Operations\KioskModeOperationTests.cs" />
|
||||
<Compile Include="Operations\PasswordDialogResultStub.cs" />
|
||||
<Compile Include="Operations\ServiceOperationTests.cs" />
|
||||
<Compile Include="Operations\ClientOperationTests.cs" />
|
||||
<Compile Include="Operations\ClientTerminationOperationTests.cs" />
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace SafeExamBrowser.Runtime
|
|||
bootstrapOperations.Enqueue(new I18nOperation(logger, text, textResource));
|
||||
bootstrapOperations.Enqueue(new CommunicationHostOperation(runtimeHost, logger));
|
||||
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, messageBox, resourceLoader, runtimeHost, text, uiFactory, args));
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, resourceLoader, args));
|
||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy));
|
||||
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||
|
@ -81,7 +81,7 @@ namespace SafeExamBrowser.Runtime
|
|||
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||
|
||||
RuntimeController = new RuntimeController(appConfig, configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, shutdown, uiFactory);
|
||||
RuntimeController = new RuntimeController(appConfig, configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, shutdown, text, uiFactory);
|
||||
}
|
||||
|
||||
internal void LogStartupInformation()
|
||||
|
|
|
@ -12,9 +12,9 @@ using SafeExamBrowser.Contracts.Communication.Hosts;
|
|||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
using SafeExamBrowser.Contracts.WindowsApi.Events;
|
||||
|
||||
|
@ -30,7 +30,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
protected IProxyFactory proxyFactory;
|
||||
protected IRuntimeHost runtimeHost;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { protected get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
protected IProcess ClientProcess
|
||||
{
|
||||
|
@ -62,7 +63,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
public virtual OperationResult Perform()
|
||||
{
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartClient, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StartClient);
|
||||
|
||||
var success = TryStartClient();
|
||||
|
||||
|
@ -87,7 +88,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
if (ClientProcess != null && !ClientProcess.HasTerminated)
|
||||
{
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopClient, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopClient);
|
||||
TryStopClient();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
@ -18,6 +19,9 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
internal class ClientTerminationOperation : ClientOperation
|
||||
{
|
||||
public new event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public new event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ClientTerminationOperation(
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
|
@ -39,7 +43,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
if (ClientProcess != null && !ClientProcess.HasTerminated)
|
||||
{
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopClient, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_StopClient);
|
||||
success = TryStopClient();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,17 +8,14 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||
using SafeExamBrowser.Runtime.Operations.Events;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
|
@ -26,42 +23,31 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private IResourceLoader resourceLoader;
|
||||
private IRuntimeHost runtimeHost;
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private string[] commandLineArgs;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired;
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ConfigurationOperation(
|
||||
AppConfig appConfig,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
IResourceLoader resourceLoader,
|
||||
IRuntimeHost runtimeHost,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
string[] commandLineArgs)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.configuration = configuration;
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.runtimeHost = runtimeHost;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.commandLineArgs = commandLineArgs;
|
||||
}
|
||||
|
||||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info("Initializing application configuration...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
|
||||
var isValidUri = TryInitializeSettingsUri(out Uri uri);
|
||||
|
||||
|
@ -86,7 +72,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
public OperationResult Repeat()
|
||||
{
|
||||
logger.Info("Initializing new application configuration...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeConfiguration);
|
||||
|
||||
var isValidUri = TryValidateSettingsUri(configuration.ReconfigurationFilePath, out Uri uri);
|
||||
|
||||
|
@ -123,18 +109,17 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
if (status == LoadStatus.AdminPasswordNeeded || status == LoadStatus.SettingsPasswordNeeded)
|
||||
{
|
||||
var purpose = status == LoadStatus.AdminPasswordNeeded ? PasswordRequestPurpose.Administrator : PasswordRequestPurpose.Settings;
|
||||
var aborted = !TryGetPassword(purpose, out string password);
|
||||
var result = TryGetPassword(status);
|
||||
|
||||
adminAttempts += purpose == PasswordRequestPurpose.Administrator ? 1 : 0;
|
||||
adminPassword = purpose == PasswordRequestPurpose.Administrator ? password : adminPassword;
|
||||
settingsAttempts += purpose == PasswordRequestPurpose.Settings ? 1 : 0;
|
||||
settingsPassword = purpose == PasswordRequestPurpose.Settings ? password : settingsPassword;
|
||||
|
||||
if (aborted)
|
||||
if (!result.Success)
|
||||
{
|
||||
return OperationResult.Aborted;
|
||||
}
|
||||
|
||||
adminAttempts += status == LoadStatus.AdminPasswordNeeded ? 1 : 0;
|
||||
adminPassword = status == LoadStatus.AdminPasswordNeeded ? result.Password : adminPassword;
|
||||
settingsAttempts += status == LoadStatus.SettingsPasswordNeeded ? 1 : 0;
|
||||
settingsPassword = status == LoadStatus.SettingsPasswordNeeded ? result.Password : settingsPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -150,64 +135,14 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
return status == LoadStatus.Success ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
private bool TryGetPassword(PasswordRequestPurpose purpose, out string password)
|
||||
private PasswordRequiredEventArgs TryGetPassword(LoadStatus status)
|
||||
{
|
||||
var isStartup = configuration.CurrentSession == null;
|
||||
var isRunningOnDefaultDesktop = configuration.CurrentSettings?.KioskMode == KioskMode.DisableExplorerShell;
|
||||
var purpose = status == LoadStatus.AdminPasswordNeeded ? PasswordRequestPurpose.Administrator : PasswordRequestPurpose.Settings;
|
||||
var args = new PasswordRequiredEventArgs { Purpose = purpose };
|
||||
|
||||
if (isStartup || isRunningOnDefaultDesktop)
|
||||
{
|
||||
return TryGetPasswordViaDialog(purpose, out password);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TryGetPasswordViaClient(purpose, out password);
|
||||
}
|
||||
}
|
||||
ActionRequired?.Invoke(args);
|
||||
|
||||
private bool TryGetPasswordViaDialog(PasswordRequestPurpose purpose, out string password)
|
||||
{
|
||||
var isAdmin = purpose == PasswordRequestPurpose.Administrator;
|
||||
var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired;
|
||||
var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle;
|
||||
var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title));
|
||||
var result = dialog.Show();
|
||||
var success = result.Success;
|
||||
|
||||
password = success ? result.Password : default(string);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryGetPasswordViaClient(PasswordRequestPurpose purpose, out string password)
|
||||
{
|
||||
var requestId = Guid.NewGuid();
|
||||
var response = default(PasswordReplyEventArgs);
|
||||
var responseEvent = new AutoResetEvent(false);
|
||||
var responseEventHandler = new CommunicationEventHandler<PasswordReplyEventArgs>((args) =>
|
||||
{
|
||||
if (args.RequestId == requestId)
|
||||
{
|
||||
response = args;
|
||||
responseEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
runtimeHost.PasswordReceived += responseEventHandler;
|
||||
|
||||
var communication = configuration.CurrentSession.ClientProxy.RequestPassword(purpose, requestId);
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
responseEvent.WaitOne();
|
||||
}
|
||||
|
||||
var success = response?.Success == true;
|
||||
|
||||
runtimeHost.PasswordReceived -= responseEventHandler;
|
||||
password = success ? response.Password : default(string);
|
||||
|
||||
return success;
|
||||
return args;
|
||||
}
|
||||
|
||||
private void HandleInvalidData(ref LoadStatus status, Uri uri)
|
||||
|
@ -273,26 +208,19 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
{
|
||||
if (result == OperationResult.Success && configuration.CurrentSettings.ConfigurationMode == ConfigurationMode.ConfigureClient)
|
||||
{
|
||||
var abort = IsConfigurationSufficient();
|
||||
var args = new ConfigurationCompletedEventArgs();
|
||||
|
||||
logger.Info($"The user chose to {(abort ? "abort" : "continue")} after successful client configuration.");
|
||||
ActionRequired?.Invoke(args);
|
||||
|
||||
if (abort)
|
||||
logger.Info($"The user chose to {(args.AbortStartup ? "abort" : "continue")} after successful client configuration.");
|
||||
|
||||
if (args.AbortStartup)
|
||||
{
|
||||
result = OperationResult.Aborted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConfigurationSufficient()
|
||||
{
|
||||
var message = text.Get(TextKey.MessageBox_ClientConfigurationQuestion);
|
||||
var title = text.Get(TextKey.MessageBox_ClientConfigurationQuestionTitle);
|
||||
var abort = messageBox.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
return abort == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
private void LogOperationResult(OperationResult result)
|
||||
{
|
||||
switch (result)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations.Events
|
||||
{
|
||||
internal class ConfigurationCompletedEventArgs : ActionRequiredEventArgs
|
||||
{
|
||||
public bool AbortStartup { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,13 +6,15 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||
namespace SafeExamBrowser.Runtime.Operations.Events
|
||||
{
|
||||
internal class PasswordDialogResultStub : IPasswordDialogResult
|
||||
internal class PasswordRequiredEventArgs : ActionRequiredEventArgs
|
||||
{
|
||||
public string Password { get; set; }
|
||||
public PasswordRequestPurpose Purpose { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
|
@ -27,7 +27,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
private IDesktop newDesktop;
|
||||
private IDesktop originalDesktop;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public KioskModeOperation(
|
||||
IConfigurationRepository configuration,
|
||||
|
@ -48,7 +49,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
kioskMode = configuration.CurrentSettings.KioskMode;
|
||||
|
||||
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeKioskMode);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeKioskMode);
|
||||
|
||||
switch (kioskMode)
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RevertKioskMode);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_RevertKioskMode);
|
||||
|
||||
switch (kioskMode)
|
||||
{
|
||||
|
@ -142,13 +143,13 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
|
||||
private void TerminateExplorerShell()
|
||||
{
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_WaitExplorerTermination, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_WaitExplorerTermination);
|
||||
explorerShell.Terminate();
|
||||
}
|
||||
|
||||
private void RestartExplorerShell()
|
||||
{
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_WaitExplorerStartup, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_WaitExplorerStartup);
|
||||
explorerShell.Start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ using SafeExamBrowser.Contracts.Communication.Proxies;
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
|
@ -23,7 +23,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
private ILogger logger;
|
||||
private IServiceProxy service;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public ServiceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service)
|
||||
{
|
||||
|
@ -35,7 +36,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
public OperationResult Perform()
|
||||
{
|
||||
logger.Info($"Initializing service session...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeServiceSession);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeServiceSession);
|
||||
|
||||
mandatory = configuration.CurrentSettings.ServicePolicy == ServicePolicy.Mandatory;
|
||||
connected = service.Connect();
|
||||
|
@ -73,7 +74,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
public void Revert()
|
||||
{
|
||||
logger.Info("Finalizing service session...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_FinalizeServiceSession);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_FinalizeServiceSession);
|
||||
|
||||
if (connected)
|
||||
{
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Operations
|
||||
{
|
||||
|
@ -21,7 +21,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
private ILogger logger;
|
||||
private IRuntimeHost runtimeHost;
|
||||
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public event StatusChangedEventHandler StatusChanged;
|
||||
|
||||
public SessionInitializationOperation(IConfigurationRepository configuration, ILogger logger, IRuntimeHost runtimeHost)
|
||||
{
|
||||
|
@ -52,7 +53,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
|||
private void InitializeSessionConfiguration()
|
||||
{
|
||||
logger.Info("Initializing new session configuration...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeSession, true);
|
||||
StatusChanged?.Invoke(TextKey.ProgressIndicator_InitializeSession);
|
||||
|
||||
configuration.InitializeSessionConfiguration();
|
||||
runtimeHost.StartupToken = configuration.CurrentSession.StartupToken;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Events;
|
||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
|
@ -14,11 +16,13 @@ using SafeExamBrowser.Contracts.Configuration;
|
|||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Core;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
using SafeExamBrowser.Runtime.Operations.Events;
|
||||
|
||||
namespace SafeExamBrowser.Runtime
|
||||
{
|
||||
|
@ -37,6 +41,7 @@ namespace SafeExamBrowser.Runtime
|
|||
private IServiceProxy service;
|
||||
private ISplashScreen splashScreen;
|
||||
private Action shutdown;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
public RuntimeController(
|
||||
|
@ -49,6 +54,7 @@ namespace SafeExamBrowser.Runtime
|
|||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service,
|
||||
Action shutdown,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
|
@ -60,6 +66,7 @@ namespace SafeExamBrowser.Runtime
|
|||
this.sessionSequence = sessionSequence;
|
||||
this.service = service;
|
||||
this.shutdown = shutdown;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
||||
|
@ -70,8 +77,11 @@ namespace SafeExamBrowser.Runtime
|
|||
runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig);
|
||||
splashScreen = uiFactory.CreateSplashScreen(appConfig);
|
||||
|
||||
bootstrapSequence.ProgressIndicator = splashScreen;
|
||||
sessionSequence.ProgressIndicator = runtimeWindow;
|
||||
bootstrapSequence.ProgressChanged += BootstrapSequence_ProgressChanged;
|
||||
bootstrapSequence.StatusChanged += BootstrapSequence_StatusChanged;
|
||||
sessionSequence.ActionRequired += SessionSequence_ActionRequired;
|
||||
sessionSequence.ProgressChanged += SessionSequence_ProgressChanged;
|
||||
sessionSequence.StatusChanged += SessionSequence_StatusChanged;
|
||||
|
||||
splashScreen.Show();
|
||||
|
||||
|
@ -93,7 +103,7 @@ namespace SafeExamBrowser.Runtime
|
|||
logger.Info("Application startup aborted!");
|
||||
logger.Log(string.Empty);
|
||||
|
||||
messageBox.Show(TextKey.MessageBox_StartupError, TextKey.MessageBox_StartupErrorTitle, icon: MessageBoxIcon.Error);
|
||||
messageBox.Show(TextKey.MessageBox_StartupError, TextKey.MessageBox_StartupErrorTitle, icon: MessageBoxIcon.Error, parent: splashScreen);
|
||||
}
|
||||
|
||||
return initialized && sessionRunning;
|
||||
|
@ -128,7 +138,7 @@ namespace SafeExamBrowser.Runtime
|
|||
logger.Info("Shutdown procedure failed!");
|
||||
logger.Log(string.Empty);
|
||||
|
||||
messageBox.Show(TextKey.MessageBox_ShutdownError, TextKey.MessageBox_ShutdownErrorTitle, icon: MessageBoxIcon.Error);
|
||||
messageBox.Show(TextKey.MessageBox_ShutdownError, TextKey.MessageBox_ShutdownErrorTitle, icon: MessageBoxIcon.Error, parent: splashScreen);
|
||||
}
|
||||
|
||||
splashScreen?.Close();
|
||||
|
@ -171,7 +181,7 @@ namespace SafeExamBrowser.Runtime
|
|||
if (result == OperationResult.Failed)
|
||||
{
|
||||
// TODO: Check if message box is rendered on new desktop as well! -> E.g. if settings for reconfiguration are invalid
|
||||
messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
|
||||
messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error, parent: runtimeWindow);
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
|
@ -201,7 +211,7 @@ namespace SafeExamBrowser.Runtime
|
|||
else
|
||||
{
|
||||
logger.Info("### --- Session Stop Failed --- ###");
|
||||
messageBox.Show(TextKey.MessageBox_SessionStopError, TextKey.MessageBox_SessionStopErrorTitle, icon: MessageBoxIcon.Error);
|
||||
messageBox.Show(TextKey.MessageBox_SessionStopError, TextKey.MessageBox_SessionStopErrorTitle, icon: MessageBoxIcon.Error, parent: runtimeWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,10 +239,44 @@ namespace SafeExamBrowser.Runtime
|
|||
configuration.CurrentSession.ClientProxy.ConnectionLost -= Client_ConnectionLost;
|
||||
}
|
||||
|
||||
private void BootstrapSequence_ProgressChanged(ProgressChangedEventArgs args)
|
||||
{
|
||||
// TODO: Duplicated code (for splashScreen as well as runtimeWindow)!
|
||||
if (args.CurrentValue.HasValue)
|
||||
{
|
||||
splashScreen?.SetValue(args.CurrentValue.Value);
|
||||
}
|
||||
|
||||
if (args.IsIndeterminate == true)
|
||||
{
|
||||
splashScreen?.SetIndeterminate();
|
||||
}
|
||||
|
||||
if (args.MaxValue.HasValue)
|
||||
{
|
||||
splashScreen?.SetMaxValue(args.MaxValue.Value);
|
||||
}
|
||||
|
||||
if (args.Progress == true)
|
||||
{
|
||||
splashScreen?.Progress();
|
||||
}
|
||||
|
||||
if (args.Regress == true)
|
||||
{
|
||||
splashScreen?.Regress();
|
||||
}
|
||||
}
|
||||
|
||||
private void BootstrapSequence_StatusChanged(TextKey status)
|
||||
{
|
||||
splashScreen?.UpdateText(status);
|
||||
}
|
||||
|
||||
private void ClientProcess_Terminated(int exitCode)
|
||||
{
|
||||
logger.Error($"Client application has unexpectedly terminated with exit code {exitCode}!");
|
||||
// TODO: Check if message box is rendered on new desktop as well -> otherwise shutdown is blocked!
|
||||
// TODO: Check if message box is rendered on new desktop as well -> otherwise shutdown is blocked! Check if parent needed!
|
||||
messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error);
|
||||
|
||||
shutdown.Invoke();
|
||||
|
@ -241,7 +285,7 @@ namespace SafeExamBrowser.Runtime
|
|||
private void Client_ConnectionLost()
|
||||
{
|
||||
logger.Error("Lost connection to the client application!");
|
||||
// TODO: Check if message box is rendered on new desktop as well -> otherwise shutdown is blocked!
|
||||
// TODO: Check if message box is rendered on new desktop as well -> otherwise shutdown is blocked! Check if parent needed!
|
||||
messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error);
|
||||
|
||||
shutdown.Invoke();
|
||||
|
@ -270,5 +314,120 @@ namespace SafeExamBrowser.Runtime
|
|||
logger.Info("Received shutdown request from the client application.");
|
||||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void SessionSequence_ActionRequired(ActionRequiredEventArgs args)
|
||||
{
|
||||
switch (args)
|
||||
{
|
||||
case ConfigurationCompletedEventArgs a:
|
||||
AskIfConfigurationSufficient(a);
|
||||
break;
|
||||
case PasswordRequiredEventArgs p:
|
||||
AskForPassword(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void AskIfConfigurationSufficient(ConfigurationCompletedEventArgs args)
|
||||
{
|
||||
var message = TextKey.MessageBox_ClientConfigurationQuestion;
|
||||
var title = TextKey.MessageBox_ClientConfigurationQuestionTitle;
|
||||
var result = messageBox.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question, runtimeWindow);
|
||||
|
||||
args.AbortStartup = result == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
private void AskForPassword(PasswordRequiredEventArgs args)
|
||||
{
|
||||
var isStartup = configuration.CurrentSession == null;
|
||||
var isRunningOnDefaultDesktop = configuration.CurrentSettings?.KioskMode == KioskMode.DisableExplorerShell;
|
||||
|
||||
if (isStartup || isRunningOnDefaultDesktop)
|
||||
{
|
||||
TryGetPasswordViaDialog(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
TryGetPasswordViaClient(args);
|
||||
}
|
||||
}
|
||||
|
||||
private void TryGetPasswordViaDialog(PasswordRequiredEventArgs args)
|
||||
{
|
||||
var isAdmin = args.Purpose == PasswordRequestPurpose.Administrator;
|
||||
var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired;
|
||||
var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle;
|
||||
var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title));
|
||||
var result = dialog.Show(runtimeWindow);
|
||||
|
||||
args.Password = result.Password;
|
||||
args.Success = result.Success;
|
||||
}
|
||||
|
||||
private void TryGetPasswordViaClient(PasswordRequiredEventArgs args)
|
||||
{
|
||||
var requestId = Guid.NewGuid();
|
||||
var response = default(PasswordReplyEventArgs);
|
||||
var responseEvent = new AutoResetEvent(false);
|
||||
var responseEventHandler = new CommunicationEventHandler<PasswordReplyEventArgs>((a) =>
|
||||
{
|
||||
if (a.RequestId == requestId)
|
||||
{
|
||||
response = a;
|
||||
responseEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
runtimeHost.PasswordReceived += responseEventHandler;
|
||||
|
||||
var communication = configuration.CurrentSession.ClientProxy.RequestPassword(args.Purpose, requestId);
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
responseEvent.WaitOne();
|
||||
args.Password = response.Password;
|
||||
args.Success = response.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Password = default(string);
|
||||
args.Success = false;
|
||||
}
|
||||
|
||||
runtimeHost.PasswordReceived -= responseEventHandler;
|
||||
}
|
||||
|
||||
private void SessionSequence_ProgressChanged(ProgressChangedEventArgs args)
|
||||
{
|
||||
if (args.CurrentValue.HasValue)
|
||||
{
|
||||
runtimeWindow?.SetValue(args.CurrentValue.Value);
|
||||
}
|
||||
|
||||
if (args.IsIndeterminate == true)
|
||||
{
|
||||
runtimeWindow?.SetIndeterminate();
|
||||
}
|
||||
|
||||
if (args.MaxValue.HasValue)
|
||||
{
|
||||
runtimeWindow?.SetMaxValue(args.MaxValue.Value);
|
||||
}
|
||||
|
||||
if (args.Progress == true)
|
||||
{
|
||||
runtimeWindow?.Progress();
|
||||
}
|
||||
|
||||
if (args.Regress == true)
|
||||
{
|
||||
runtimeWindow?.Regress();
|
||||
}
|
||||
}
|
||||
|
||||
private void SessionSequence_StatusChanged(TextKey status)
|
||||
{
|
||||
runtimeWindow?.UpdateText(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
<Compile Include="Operations\ClientOperation.cs" />
|
||||
<Compile Include="Operations\ClientTerminationOperation.cs" />
|
||||
<Compile Include="Operations\ConfigurationOperation.cs" />
|
||||
<Compile Include="Operations\Events\ConfigurationCompletedEventArgs.cs" />
|
||||
<Compile Include="Operations\Events\PasswordRequiredEventArgs.cs" />
|
||||
<Compile Include="Operations\KioskModeOperation.cs" />
|
||||
<Compile Include="Operations\ServiceOperation.cs" />
|
||||
<Compile Include="Operations\SessionInitializationOperation.cs" />
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using System.Windows;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
using MessageBoxResult = SafeExamBrowser.Contracts.UserInterface.MessageBox.MessageBoxResult;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Classic
|
||||
|
@ -22,16 +23,25 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
this.text = text;
|
||||
}
|
||||
|
||||
public MessageBoxResult Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information)
|
||||
public MessageBoxResult Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information, IWindow parent = null)
|
||||
{
|
||||
var result = System.Windows.MessageBox.Show(message, title, ToButton(action), ToImage(icon));
|
||||
var result = default(System.Windows.MessageBoxResult);
|
||||
|
||||
if (parent is Window window)
|
||||
{
|
||||
result = window.Dispatcher.Invoke(() => System.Windows.MessageBox.Show(window, message, title, ToButton(action), ToImage(icon)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = System.Windows.MessageBox.Show(message, title, ToButton(action), ToImage(icon));
|
||||
}
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
public MessageBoxResult Show(TextKey message, TextKey title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information)
|
||||
public MessageBoxResult Show(TextKey message, TextKey title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information, IWindow parent = null)
|
||||
{
|
||||
return Show(text.Get(message), text.Get(title), action, icon);
|
||||
return Show(text.Get(message), text.Get(title), action, icon, parent);
|
||||
}
|
||||
|
||||
private MessageBoxButton ToButton(MessageBoxAction action)
|
||||
|
|
|
@ -81,14 +81,14 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
});
|
||||
}
|
||||
|
||||
public void Progress(int amount = 1)
|
||||
public void Progress()
|
||||
{
|
||||
model.CurrentProgress += amount;
|
||||
model.CurrentProgress += 1;
|
||||
}
|
||||
|
||||
public void Regress(int amount = 1)
|
||||
public void Regress()
|
||||
{
|
||||
model.CurrentProgress -= amount;
|
||||
model.CurrentProgress -= 1;
|
||||
}
|
||||
|
||||
public void SetIndeterminate()
|
||||
|
|
|
@ -77,14 +77,14 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
Dispatcher.Invoke(base.Show);
|
||||
}
|
||||
|
||||
public void Progress(int amount = 1)
|
||||
public void Progress()
|
||||
{
|
||||
model.CurrentProgress += amount;
|
||||
model.CurrentProgress += 1;
|
||||
}
|
||||
|
||||
public void Regress(int amount = 1)
|
||||
public void Regress()
|
||||
{
|
||||
model.CurrentProgress -= amount;
|
||||
model.CurrentProgress -= 1;
|
||||
}
|
||||
|
||||
public void SetIndeterminate()
|
||||
|
|
|
@ -75,14 +75,14 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
|||
Dispatcher.Invoke(base.Show);
|
||||
}
|
||||
|
||||
public void Progress(int amount = 1)
|
||||
public void Progress()
|
||||
{
|
||||
model.CurrentProgress += amount;
|
||||
model.CurrentProgress += 1;
|
||||
}
|
||||
|
||||
public void Regress(int amount = 1)
|
||||
public void Regress()
|
||||
{
|
||||
model.CurrentProgress -= amount;
|
||||
model.CurrentProgress -= 1;
|
||||
}
|
||||
|
||||
public void SetIndeterminate()
|
||||
|
|
Loading…
Reference in a new issue