diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs
index 173de3a4..00f7e45a 100644
--- a/SafeExamBrowser.I18n.Contracts/TextKey.cs
+++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs
@@ -165,6 +165,11 @@ namespace SafeExamBrowser.I18n.Contracts
PasswordDialog_SettingsPasswordRequired,
PasswordDialog_SettingsPasswordRequiredTitle,
RuntimeWindow_ApplicationRunning,
+ ServerFailureDialog_Abort,
+ ServerFailureDialog_Fallback,
+ ServerFailureDialog_Message,
+ ServerFailureDialog_Retry,
+ ServerFailureDialog_Title,
Shell_QuitButton,
SystemControl_AudioDeviceInfo,
SystemControl_AudioDeviceInfoMuted,
diff --git a/SafeExamBrowser.I18n/Data/de.xml b/SafeExamBrowser.I18n/Data/de.xml
index 4c55906d..eb56b7bb 100644
--- a/SafeExamBrowser.I18n/Data/de.xml
+++ b/SafeExamBrowser.I18n/Data/de.xml
@@ -453,6 +453,21 @@
SEB wird ausgeführt.
+
+ Abbrechen
+
+
+ Fallback
+
+
+ Bei der Kommunikation mit dem SEB-Server ist ein Fehler aufgetreten.
+
+
+ Wiederholen
+
+
+ SEB-Server-Fehler
+
Sitzung beenden
diff --git a/SafeExamBrowser.I18n/Data/en.xml b/SafeExamBrowser.I18n/Data/en.xml
index 348b38fc..36cdb0a3 100644
--- a/SafeExamBrowser.I18n/Data/en.xml
+++ b/SafeExamBrowser.I18n/Data/en.xml
@@ -453,6 +453,21 @@
SEB is running.
+
+ Abort
+
+
+ Fallback
+
+
+ An error occurred while trying to communicate with the SEB server.
+
+
+ Retry
+
+
+ SEB-Server Error
+
Terminate Session
diff --git a/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs b/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs
index 3d0178d3..7febce61 100644
--- a/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs
+++ b/SafeExamBrowser.Runtime/Operations/Events/ServerFailureEventArgs.cs
@@ -16,10 +16,12 @@ namespace SafeExamBrowser.Runtime.Operations.Events
public bool Fallback { get; set; }
public string Message { get; set; }
public bool Retry { get; set; }
+ public bool ShowFallback { get; }
- public ServerFailureEventArgs(string message)
+ public ServerFailureEventArgs(string message, bool showFallback)
{
Message = message;
+ ShowFallback = showFallback;
}
}
}
diff --git a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs
index 21f20382..4e3de3cd 100644
--- a/SafeExamBrowser.Runtime/Operations/ServerOperation.cs
+++ b/SafeExamBrowser.Runtime/Operations/ServerOperation.cs
@@ -70,6 +70,7 @@ namespace SafeExamBrowser.Runtime.Operations
if (status == LoadStatus.Success)
{
Context.Next.Settings = settings;
+ Context.Next.Settings.Browser.StartUrl = exam.Url;
result = OperationResult.Success;
}
else
@@ -116,7 +117,7 @@ namespace SafeExamBrowser.Runtime.Operations
{
var result = OperationResult.Failed;
- if (Context.Current.Settings.SessionMode == SessionMode.Server)
+ if (Context.Current?.Settings.SessionMode == SessionMode.Server)
{
logger.Info("Finalizing server...");
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
@@ -192,7 +193,7 @@ namespace SafeExamBrowser.Runtime.Operations
private bool Retry(string message, out bool abort, out bool fallback)
{
- var args = new ServerFailureEventArgs(message);
+ var args = new ServerFailureEventArgs(message, Context.Next.Settings.Server.PerformFallback);
ActionRequired?.Invoke(args);
diff --git a/SafeExamBrowser.Runtime/RuntimeController.cs b/SafeExamBrowser.Runtime/RuntimeController.cs
index 88a2d823..0b1a5592 100644
--- a/SafeExamBrowser.Runtime/RuntimeController.cs
+++ b/SafeExamBrowser.Runtime/RuntimeController.cs
@@ -417,7 +417,18 @@ namespace SafeExamBrowser.Runtime
private void AskForServerFailureAction(ServerFailureEventArgs args)
{
- // TODO: Also implement mechanism to retrieve selection via client!!
+ var isStartup = !SessionIsRunning;
+ var isRunningOnDefaultDesktop = SessionIsRunning && Session.Settings.Security.KioskMode == KioskMode.DisableExplorerShell;
+
+ if (isStartup || isRunningOnDefaultDesktop)
+ {
+ TryAskForServerFailureActionViaDialog(args);
+ }
+ else
+ {
+ // TODO: Also implement mechanism to retrieve selection via client!!
+ // TryAskForServerFailureActionViaClient(args);
+ }
}
private void AskIfConfigurationSufficient(ConfigurationCompletedEventArgs args)
@@ -503,15 +514,23 @@ namespace SafeExamBrowser.Runtime
private void TryAskForExamSelectionViaDialog(ExamSelectionEventArgs args)
{
- var message = TextKey.ExamSelectionDialog_Message;
- var title = TextKey.ExamSelectionDialog_Title;
- var dialog = uiFactory.CreateExamSelectionDialog(text.Get(message), text.Get(title), args.Exams);
+ var dialog = uiFactory.CreateExamSelectionDialog(args.Exams);
var result = dialog.Show(runtimeWindow);
args.SelectedExam = result.SelectedExam;
args.Success = result.Success;
}
+ private void TryAskForServerFailureActionViaDialog(ServerFailureEventArgs args)
+ {
+ var dialog = uiFactory.CreateServerFailureDialog(args.Message, args.ShowFallback);
+ var result = dialog.Show(runtimeWindow);
+
+ args.Abort = result.Abort;
+ args.Fallback = result.Fallback;
+ args.Retry = result.Retry;
+ }
+
private void TryGetPasswordViaDialog(PasswordRequiredEventArgs args)
{
var message = default(TextKey);
diff --git a/SafeExamBrowser.Server.Contracts/Exam.cs b/SafeExamBrowser.Server.Contracts/Exam.cs
index 96a4d09c..de303948 100644
--- a/SafeExamBrowser.Server.Contracts/Exam.cs
+++ b/SafeExamBrowser.Server.Contracts/Exam.cs
@@ -18,6 +18,11 @@ namespace SafeExamBrowser.Server.Contracts
///
public string Id { get; set; }
+ ///
+ /// The name of the learning management system (LMS) on which the exam is running.
+ ///
+ public string LmsName { get; set; }
+
///
/// The name of the exam.
///
diff --git a/SafeExamBrowser.Server/ServerProxy.cs b/SafeExamBrowser.Server/ServerProxy.cs
index 63340d50..e5909291 100644
--- a/SafeExamBrowser.Server/ServerProxy.cs
+++ b/SafeExamBrowser.Server/ServerProxy.cs
@@ -223,6 +223,7 @@ namespace SafeExamBrowser.Server
exams.Add(new Exam
{
Id = exam["examId"].Value(),
+ LmsName = exam["lmsType"].Value(),
Name = exam["name"].Value(),
Url = exam["url"].Value()
});
@@ -314,7 +315,7 @@ namespace SafeExamBrowser.Server
private string ToString(HttpResponseMessage response)
{
- return $"{(int) response.StatusCode} {response.StatusCode} {response.ReasonPhrase}";
+ return $"{(int?) response?.StatusCode} {response?.StatusCode} {response?.ReasonPhrase}";
}
}
}
diff --git a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs
index 16a98687..70418550 100644
--- a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs
+++ b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs
@@ -58,7 +58,7 @@ namespace SafeExamBrowser.UserInterface.Contracts
///
/// Creates an exam selection dialog for the given exams.
///
- IExamSelectionDialog CreateExamSelectionDialog(string message, string title, IEnumerable exams);
+ IExamSelectionDialog CreateExamSelectionDialog(IEnumerable exams);
///
/// Creates a system control which allows to change the keyboard layout of the computer.
@@ -98,9 +98,13 @@ namespace SafeExamBrowser.UserInterface.Contracts
///
/// Creates a new runtime window which runs on its own thread.
///
- ///
IRuntimeWindow CreateRuntimeWindow(AppConfig appConfig);
+ ///
+ /// Creates a new server failure dialog with the given parameters.
+ ///
+ IServerFailureDialog CreateServerFailureDialog(string info, bool showFallback);
+
///
/// Creates a new splash screen which runs on its own thread.
///
diff --git a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj
index 84b0b350..737c7268 100644
--- a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj
+++ b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj
@@ -89,12 +89,14 @@
+
+
diff --git a/SafeExamBrowser.UserInterface.Contracts/Windows/Data/ServerFailureDialogResult.cs b/SafeExamBrowser.UserInterface.Contracts/Windows/Data/ServerFailureDialogResult.cs
new file mode 100644
index 00000000..fff576d0
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Contracts/Windows/Data/ServerFailureDialogResult.cs
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 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.UserInterface.Contracts.Windows.Data
+{
+ ///
+ /// Defines the user interaction result of an .
+ ///
+ public class ServerFailureDialogResult
+ {
+ ///
+ /// Indicates whether the user wants to abort the operation.
+ ///
+ public bool Abort { get; set; }
+
+ ///
+ /// Indicates whether the user wants to performa a fallback.
+ ///
+ public bool Fallback { get; set; }
+
+ ///
+ /// Indicates whether the user wants to retry the operation.
+ ///
+ public bool Retry { get; set; }
+
+ ///
+ /// Indicates whether the user confirmed the dialog or not.
+ ///
+ public bool Success { get; set; }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Contracts/Windows/IExamSelectionDialog.cs b/SafeExamBrowser.UserInterface.Contracts/Windows/IExamSelectionDialog.cs
index 9d4d524d..ed414fa0 100644
--- a/SafeExamBrowser.UserInterface.Contracts/Windows/IExamSelectionDialog.cs
+++ b/SafeExamBrowser.UserInterface.Contracts/Windows/IExamSelectionDialog.cs
@@ -11,7 +11,7 @@ using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
namespace SafeExamBrowser.UserInterface.Contracts.Windows
{
///
- /// Defines the functionality of an exam selection dialog.
+ /// The dialog shown to let the user select which server exam to start.
///
public interface IExamSelectionDialog
{
diff --git a/SafeExamBrowser.UserInterface.Contracts/Windows/IServerFailureDialog.cs b/SafeExamBrowser.UserInterface.Contracts/Windows/IServerFailureDialog.cs
new file mode 100644
index 00000000..880697b8
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Contracts/Windows/IServerFailureDialog.cs
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020 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.UserInterface.Contracts.Windows.Data;
+
+namespace SafeExamBrowser.UserInterface.Contracts.Windows
+{
+ ///
+ /// The dialog shown in case a communication failure with a server occurs.
+ ///
+ public interface IServerFailureDialog
+ {
+ ///
+ /// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
+ ///
+ ServerFailureDialogResult Show(IWindow parent = null);
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj
index 4a249a14..668ecd69 100644
--- a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj
+++ b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj
@@ -168,6 +168,9 @@
RuntimeWindow.xaml
+
+ ServerFailureDialog.xaml
+
SplashScreen.xaml
@@ -347,6 +350,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs
index 6c834894..41fde627 100644
--- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs
+++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs
@@ -82,9 +82,9 @@ namespace SafeExamBrowser.UserInterface.Desktop
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text));
}
- public IExamSelectionDialog CreateExamSelectionDialog(string message, string title, IEnumerable exams)
+ public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable exams)
{
- return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(message, title, text, exams));
+ return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
}
public ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location)
@@ -167,6 +167,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
return Application.Current.Dispatcher.Invoke(() => new RuntimeWindow(appConfig, text));
}
+ public IServerFailureDialog CreateServerFailureDialog(string info, bool showFallback)
+ {
+ return Application.Current.Dispatcher.Invoke(() => new ServerFailureDialog(info, showFallback, text));
+ }
+
public ISplashScreen CreateSplashScreen(AppConfig appConfig = null)
{
var window = default(SplashScreen);
diff --git a/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml b/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml
index 9d869466..f2025823 100644
--- a/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml
+++ b/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml
@@ -39,7 +39,7 @@
-
+
diff --git a/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml.cs
index 0fb386f8..5e31bb55 100644
--- a/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml.cs
+++ b/SafeExamBrowser.UserInterface.Desktop/Windows/ExamSelectionDialog.xaml.cs
@@ -20,12 +20,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
private readonly IText text;
- public ExamSelectionDialog(string message, string title, IText text, IEnumerable exams)
+ public ExamSelectionDialog(IEnumerable exams, IText text)
{
this.text = text;
InitializeComponent();
- InitializeExamSelectionDialog(message, title, exams);
+ InitializeExamSelectionDialog(exams);
}
public ExamSelectionDialogResult Show(IWindow parent = null)
@@ -50,10 +50,10 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
});
}
- private void InitializeExamSelectionDialog(string message, string title, IEnumerable exams)
+ private void InitializeExamSelectionDialog(IEnumerable exams)
{
- Message.Text = message;
- Title = title;
+ Message.Text = text.Get(TextKey.ExamSelectionDialog_Message);
+ Title = text.Get(TextKey.ExamSelectionDialog_Title);
WindowStartupLocation = WindowStartupLocation.CenterScreen;
CancelButton.Content = text.Get(TextKey.ExamSelectionDialog_Cancel);
diff --git a/SafeExamBrowser.UserInterface.Desktop/Windows/ServerFailureDialog.xaml b/SafeExamBrowser.UserInterface.Desktop/Windows/ServerFailureDialog.xaml
new file mode 100644
index 00000000..f5b13700
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Desktop/Windows/ServerFailureDialog.xaml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Desktop/Windows/ServerFailureDialog.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Windows/ServerFailureDialog.xaml.cs
new file mode 100644
index 00000000..09192642
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Desktop/Windows/ServerFailureDialog.xaml.cs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020 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.Windows;
+using SafeExamBrowser.I18n.Contracts;
+using SafeExamBrowser.UserInterface.Contracts.Windows;
+using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
+
+namespace SafeExamBrowser.UserInterface.Desktop.Windows
+{
+ public partial class ServerFailureDialog : Window, IServerFailureDialog
+ {
+ private readonly IText text;
+
+ public ServerFailureDialog(string info, bool showFallback, IText text)
+ {
+ this.text = text;
+
+ InitializeComponent();
+ InitializeDialog(info, showFallback);
+ }
+
+ public ServerFailureDialogResult Show(IWindow parent = null)
+ {
+ return Dispatcher.Invoke(() =>
+ {
+ var result = new ServerFailureDialogResult { Success = false };
+
+ if (parent is Window)
+ {
+ Owner = parent as Window;
+ WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ }
+
+ if (ShowDialog() is true)
+ {
+ result.Abort = Tag as string == nameof(AbortButton);
+ result.Fallback = Tag as string == nameof(FallbackButton);
+ result.Retry = Tag as string == nameof(RetryButton);
+ result.Success = true;
+ }
+ else
+ {
+ result.Abort = true;
+ }
+
+ return result;
+ });
+ }
+
+ private void InitializeDialog(string info, bool showFallback)
+ {
+ Info.Text = info;
+ Message.Text = text.Get(TextKey.ServerFailureDialog_Message);
+ Title = text.Get(TextKey.ServerFailureDialog_Title);
+
+ AbortButton.Click += AbortButton_Click;
+ AbortButton.Content = text.Get(TextKey.ServerFailureDialog_Abort);
+
+ FallbackButton.Click += FallbackButton_Click;
+ FallbackButton.Content = text.Get(TextKey.ServerFailureDialog_Fallback);
+ FallbackButton.Visibility = showFallback ? Visibility.Visible : Visibility.Collapsed;
+
+ Loaded += (o, args) => Activate();
+
+ RetryButton.Click += RetryButton_Click;
+ RetryButton.Content = text.Get(TextKey.ServerFailureDialog_Retry);
+ }
+
+ private void AbortButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Tag = nameof(AbortButton);
+ Close();
+ }
+
+ private void FallbackButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Tag = nameof(FallbackButton);
+ Close();
+ }
+
+ private void RetryButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Tag = nameof(RetryButton);
+ Close();
+ }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs
index ba5d2060..58e05475 100644
--- a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs
+++ b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs
@@ -82,7 +82,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text));
}
- public IExamSelectionDialog CreateExamSelectionDialog(string message, string title, IEnumerable exams)
+ public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable exams)
{
// TODO
throw new System.NotImplementedException();
@@ -168,6 +168,12 @@ namespace SafeExamBrowser.UserInterface.Mobile
return Application.Current.Dispatcher.Invoke(() => new RuntimeWindow(appConfig, text));
}
+ public IServerFailureDialog CreateServerFailureDialog(string info, bool showFallback)
+ {
+ // TODO
+ throw new System.NotImplementedException();
+ }
+
public ISplashScreen CreateSplashScreen(AppConfig appConfig = null)
{
var window = default(SplashScreen);