SEBWIN-475: Implemented basic proctoring with Zoom and SEB server.
This commit is contained in:
parent
cad8f21ff3
commit
7ad1d6ae5d
12 changed files with 234 additions and 58 deletions
|
@ -77,9 +77,24 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
|
||||||
case Keys.Proctoring.WindowVisibility:
|
case Keys.Proctoring.WindowVisibility:
|
||||||
MapWindowVisibility(settings, value);
|
MapWindowVisibility(settings, value);
|
||||||
break;
|
break;
|
||||||
|
case Keys.Proctoring.Zoom.ApiKey:
|
||||||
|
MapZoomApiKey(settings, value);
|
||||||
|
break;
|
||||||
|
case Keys.Proctoring.Zoom.ApiSecret:
|
||||||
|
MapZoomApiSecret(settings, value);
|
||||||
|
break;
|
||||||
case Keys.Proctoring.Zoom.Enabled:
|
case Keys.Proctoring.Zoom.Enabled:
|
||||||
MapZoomEnabled(settings, value);
|
MapZoomEnabled(settings, value);
|
||||||
break;
|
break;
|
||||||
|
case Keys.Proctoring.Zoom.MeetingNumber:
|
||||||
|
MapZoomMeetingNumber(settings, value);
|
||||||
|
break;
|
||||||
|
case Keys.Proctoring.Zoom.Signature:
|
||||||
|
MapZoomSignature(settings, value);
|
||||||
|
break;
|
||||||
|
case Keys.Proctoring.Zoom.UserName:
|
||||||
|
MapZoomUserName(settings, value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +277,22 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MapZoomApiKey(AppSettings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is string key)
|
||||||
|
{
|
||||||
|
settings.Proctoring.Zoom.ApiKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapZoomApiSecret(AppSettings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is string secret)
|
||||||
|
{
|
||||||
|
settings.Proctoring.Zoom.ApiSecret = secret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void MapZoomEnabled(AppSettings settings, object value)
|
private void MapZoomEnabled(AppSettings settings, object value)
|
||||||
{
|
{
|
||||||
if (value is bool enabled)
|
if (value is bool enabled)
|
||||||
|
@ -269,5 +300,29 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
|
||||||
settings.Proctoring.Zoom.Enabled = enabled;
|
settings.Proctoring.Zoom.Enabled = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MapZoomMeetingNumber(AppSettings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is string number)
|
||||||
|
{
|
||||||
|
settings.Proctoring.Zoom.MeetingNumber = number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapZoomSignature(AppSettings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is string signature)
|
||||||
|
{
|
||||||
|
settings.Proctoring.Zoom.Signature = signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapZoomUserName(AppSettings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is string name)
|
||||||
|
{
|
||||||
|
settings.Proctoring.Zoom.UserName = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,7 +250,12 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
|
|
||||||
internal static class Zoom
|
internal static class Zoom
|
||||||
{
|
{
|
||||||
|
internal const string ApiKey = "zoomApiKey";
|
||||||
|
internal const string ApiSecret = "zoomApiSecret";
|
||||||
internal const string Enabled = "zoomEnable";
|
internal const string Enabled = "zoomEnable";
|
||||||
|
internal const string MeetingNumber = "zoomRoom";
|
||||||
|
internal const string Signature = "zoomToken";
|
||||||
|
internal const string UserName = "zoomUserInfoDisplayName";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,12 @@ namespace SafeExamBrowser.Proctoring.Contracts
|
||||||
public interface IProctoringController
|
public interface IProctoringController
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Initializes the given settings and starts the proctoring if the settings are valid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Initialize(ProctoringSettings settings);
|
void Initialize(ProctoringSettings settings);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Stops the proctoring functionality.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Terminate();
|
void Terminate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.Proctoring.Contracts;
|
using SafeExamBrowser.Proctoring.Contracts;
|
||||||
using SafeExamBrowser.Server.Contracts;
|
using SafeExamBrowser.Server.Contracts;
|
||||||
|
using SafeExamBrowser.Server.Contracts.Events;
|
||||||
using SafeExamBrowser.Settings.Proctoring;
|
using SafeExamBrowser.Settings.Proctoring;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts;
|
using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
|
@ -97,7 +98,7 @@ namespace SafeExamBrowser.Proctoring
|
||||||
else if (settings.Zoom.Enabled)
|
else if (settings.Zoom.Enabled)
|
||||||
{
|
{
|
||||||
start = !string.IsNullOrWhiteSpace(settings.Zoom.ApiKey);
|
start = !string.IsNullOrWhiteSpace(settings.Zoom.ApiKey);
|
||||||
start &= !string.IsNullOrWhiteSpace(settings.Zoom.ApiSecret);
|
start &= !string.IsNullOrWhiteSpace(settings.Zoom.ApiSecret) || !string.IsNullOrWhiteSpace(settings.Zoom.Signature);
|
||||||
start &= !string.IsNullOrWhiteSpace(settings.Zoom.MeetingNumber);
|
start &= !string.IsNullOrWhiteSpace(settings.Zoom.MeetingNumber);
|
||||||
start &= !string.IsNullOrWhiteSpace(settings.Zoom.UserName);
|
start &= !string.IsNullOrWhiteSpace(settings.Zoom.UserName);
|
||||||
}
|
}
|
||||||
|
@ -113,13 +114,19 @@ namespace SafeExamBrowser.Proctoring
|
||||||
StopProctoring();
|
StopProctoring();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Server_ProctoringInstructionReceived(string roomName, string serverUrl, string token)
|
private void Server_ProctoringInstructionReceived(ProctoringInstructionEventArgs args)
|
||||||
{
|
{
|
||||||
logger.Info("Proctoring instruction received.");
|
logger.Info("Proctoring instruction received.");
|
||||||
|
|
||||||
settings.JitsiMeet.RoomName = roomName;
|
settings.JitsiMeet.RoomName = args.JitsiMeetRoomName;
|
||||||
settings.JitsiMeet.ServerUrl = Sanitize(serverUrl);
|
settings.JitsiMeet.ServerUrl = args.JitsiMeetServerUrl;
|
||||||
settings.JitsiMeet.Token = token;
|
settings.JitsiMeet.Token = args.JitsiMeetToken;
|
||||||
|
|
||||||
|
settings.Zoom.ApiKey = args.ZoomApiKey;
|
||||||
|
settings.Zoom.MeetingNumber = args.ZoomMeetingNumber;
|
||||||
|
settings.Zoom.Password = args.ZoomPassword;
|
||||||
|
settings.Zoom.Signature = args.ZoomSignature;
|
||||||
|
settings.Zoom.UserName = args.ZoomUserName;
|
||||||
|
|
||||||
StopProctoring();
|
StopProctoring();
|
||||||
StartProctoring();
|
StartProctoring();
|
||||||
|
@ -142,6 +149,7 @@ namespace SafeExamBrowser.Proctoring
|
||||||
settings.WindowVisibility = windowVisibility;
|
settings.WindowVisibility = windowVisibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This is apparently not necessary for Zoom, there we can enable / disable the options via API call!
|
||||||
StopProctoring();
|
StopProctoring();
|
||||||
StartProctoring();
|
StartProctoring();
|
||||||
}
|
}
|
||||||
|
@ -237,6 +245,8 @@ namespace SafeExamBrowser.Proctoring
|
||||||
html = html.Replace("%%_API_KEY_%%", settings.Zoom.ApiKey);
|
html = html.Replace("%%_API_KEY_%%", settings.Zoom.ApiKey);
|
||||||
html = html.Replace("%%_API_SECRET_%%", settings.Zoom.ApiSecret);
|
html = html.Replace("%%_API_SECRET_%%", settings.Zoom.ApiSecret);
|
||||||
html = html.Replace("%%_MEETING_NUMBER_%%", settings.Zoom.MeetingNumber);
|
html = html.Replace("%%_MEETING_NUMBER_%%", settings.Zoom.MeetingNumber);
|
||||||
|
html = html.Replace("%%_PASSWORD_%%", settings.Zoom.Password);
|
||||||
|
html = html.Replace("%%_SIGNATURE_%%", settings.Zoom.Signature);
|
||||||
html = html.Replace("%%_USER_NAME_%%", settings.Zoom.UserName);
|
html = html.Replace("%%_USER_NAME_%%", settings.Zoom.UserName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,32 +14,41 @@
|
||||||
<script src="https://source.zoom.us/zoom-meeting-1.9.1.min.js"></script>
|
<script src="https://source.zoom.us/zoom-meeting-1.9.1.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/crypto-js.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/crypto-js.min.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
const API_KEY = "%%_API_KEY_%%";
|
const API_KEY = '%%_API_KEY_%%';
|
||||||
const API_SECRET = "%%_API_SECRET_%%";
|
const API_SECRET = '%%_API_SECRET_%%';
|
||||||
|
const ATTENDEE = 0;
|
||||||
|
|
||||||
|
var configuration = {
|
||||||
|
leaveUrl: 'doesnotexist',
|
||||||
|
meetingNumber: '%%_MEETING_NUMBER_%%',
|
||||||
|
passWord: '%%_PASSWORD_%%',
|
||||||
|
role: ATTENDEE,
|
||||||
|
userName: '%%_USER_NAME_%%'
|
||||||
|
};
|
||||||
|
var signature = '%%_SIGNATURE_%%';
|
||||||
|
|
||||||
|
if (!ZoomMtg.checkSystemRequirements()) {
|
||||||
|
alert('This system does not meet the necessary requirements for Zoom!');
|
||||||
|
}
|
||||||
|
|
||||||
ZoomMtg.setZoomJSLib('https://source.zoom.us/1.9.1/lib', '/av');
|
ZoomMtg.setZoomJSLib('https://source.zoom.us/1.9.1/lib', '/av');
|
||||||
ZoomMtg.preLoadWasm();
|
ZoomMtg.preLoadWasm();
|
||||||
ZoomMtg.prepareJssdk();
|
ZoomMtg.prepareJssdk();
|
||||||
|
|
||||||
const config = {
|
if (!signature) {
|
||||||
meetingNumber: "%%_MEETING_NUMBER_%%",
|
signature = ZoomMtg.generateSignature({
|
||||||
leaveUrl: "doesnotexist",
|
meetingNumber: configuration.meetingNumber,
|
||||||
userName: '%%_USER_NAME_%%',
|
apiKey: API_KEY,
|
||||||
role: 0
|
apiSecret: API_SECRET,
|
||||||
};
|
role: configuration.role,
|
||||||
|
error: function (res) {
|
||||||
const signature = ZoomMtg.generateSignature({
|
alert(`Failed to generate signature: ${JSON.stringify(res)}`)
|
||||||
meetingNumber: config.meetingNumber,
|
}
|
||||||
apiKey: API_KEY,
|
});
|
||||||
apiSecret: API_SECRET,
|
}
|
||||||
role: config.role,
|
|
||||||
error: function (res) {
|
|
||||||
alert(`Failed to generate signature: ${res}`)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ZoomMtg.init({
|
ZoomMtg.init({
|
||||||
leaveUrl: config.leaveUrl,
|
leaveUrl: configuration.leaveUrl,
|
||||||
showMeetingHeader: true,
|
showMeetingHeader: true,
|
||||||
disableInvite: false,
|
disableInvite: false,
|
||||||
disableCallOut: false,
|
disableCallOut: false,
|
||||||
|
@ -48,7 +57,7 @@
|
||||||
audioPanelAlwaysOpen: true,
|
audioPanelAlwaysOpen: true,
|
||||||
showPureSharingContent: false,
|
showPureSharingContent: false,
|
||||||
isSupportAV: true,
|
isSupportAV: true,
|
||||||
isSupportChat: false,
|
isSupportChat: true,
|
||||||
isSupportQA: true,
|
isSupportQA: true,
|
||||||
isSupportCC: true,
|
isSupportCC: true,
|
||||||
screenShare: true,
|
screenShare: true,
|
||||||
|
@ -59,10 +68,6 @@
|
||||||
isSupportNonverbal: true,
|
isSupportNonverbal: true,
|
||||||
isShowJoiningErrorDialog: true,
|
isShowJoiningErrorDialog: true,
|
||||||
inviteUrlFormat: '',
|
inviteUrlFormat: '',
|
||||||
loginWindow: {
|
|
||||||
width: 400,
|
|
||||||
height: 380
|
|
||||||
},
|
|
||||||
meetingInfo: [
|
meetingInfo: [
|
||||||
'topic',
|
'topic',
|
||||||
'host',
|
'host',
|
||||||
|
@ -76,16 +81,17 @@
|
||||||
disableVoIP: false,
|
disableVoIP: false,
|
||||||
disableReport: false,
|
disableReport: false,
|
||||||
error: function (res) {
|
error: function (res) {
|
||||||
alert(`Failed to initialize meeting: ${res}`)
|
alert(`Failed to initialize meeting: ${JSON.stringify(res)}`)
|
||||||
},
|
},
|
||||||
success: function () {
|
success: function () {
|
||||||
ZoomMtg.join({
|
ZoomMtg.join({
|
||||||
signature: signature,
|
|
||||||
apiKey: API_KEY,
|
apiKey: API_KEY,
|
||||||
meetingNumber: config.meetingNumber,
|
meetingNumber: configuration.meetingNumber,
|
||||||
userName: config.userName,
|
passWord: configuration.passWord,
|
||||||
|
signature: signature,
|
||||||
|
userName: configuration.userName,
|
||||||
error: function (res) {
|
error: function (res) {
|
||||||
alert(`Failed to join meeting: ${res}`)
|
alert(`Failed to join meeting: ${JSON.stringify(res)}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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.Server.Contracts.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines all parameters for a proctoring instruction received by the <see cref="IServerProxy"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class ProctoringInstructionEventArgs
|
||||||
|
{
|
||||||
|
public string JitsiMeetRoomName { get; set; }
|
||||||
|
public string JitsiMeetServerUrl { get; set; }
|
||||||
|
public string JitsiMeetToken { get; set; }
|
||||||
|
public string ZoomApiKey { get; set; }
|
||||||
|
public string ZoomMeetingNumber { get; set; }
|
||||||
|
public string ZoomPassword { get; set; }
|
||||||
|
public string ZoomSignature { get; set; }
|
||||||
|
public string ZoomUserName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
namespace SafeExamBrowser.Server.Contracts.Events
|
namespace SafeExamBrowser.Server.Contracts.Events
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event handler used to indicate that a proctoring instruction has been detected.
|
/// Event handler used to indicate that a proctoring instruction has been received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void ProctoringInstructionReceivedEventHandler(string roomName, string serverUrl, string token);
|
public delegate void ProctoringInstructionReceivedEventHandler(ProctoringInstructionEventArgs args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
<Compile Include="Data\ConnectionInfo.cs" />
|
<Compile Include="Data\ConnectionInfo.cs" />
|
||||||
<Compile Include="Data\Exam.cs" />
|
<Compile Include="Data\Exam.cs" />
|
||||||
<Compile Include="Events\ProctoringConfigurationReceivedEventHandler.cs" />
|
<Compile Include="Events\ProctoringConfigurationReceivedEventHandler.cs" />
|
||||||
|
<Compile Include="Events\ProctoringInstructionEventArgs.cs" />
|
||||||
<Compile Include="Events\ProctoringInstructionReceivedEventHandler.cs" />
|
<Compile Include="Events\ProctoringInstructionReceivedEventHandler.cs" />
|
||||||
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
|
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
|
||||||
<Compile Include="IServerProxy.cs" />
|
<Compile Include="IServerProxy.cs" />
|
||||||
|
|
|
@ -6,15 +6,20 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using SafeExamBrowser.Server.Contracts.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Server.Data
|
namespace SafeExamBrowser.Server.Data
|
||||||
{
|
{
|
||||||
internal class Attributes
|
internal class Attributes
|
||||||
{
|
{
|
||||||
public bool AllowChat { get; set; }
|
internal bool AllowChat { get; set; }
|
||||||
public bool ReceiveAudio { get; set; }
|
internal ProctoringInstructionEventArgs Instruction { get; set; }
|
||||||
public bool ReceiveVideo { get; set; }
|
internal bool ReceiveAudio { get; set; }
|
||||||
public string RoomName { get; set; }
|
internal bool ReceiveVideo { get; set; }
|
||||||
public string ServerUrl { get; set; }
|
|
||||||
public string Token { get; set; }
|
internal Attributes()
|
||||||
|
{
|
||||||
|
Instruction = new ProctoringInstructionEventArgs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,19 +161,7 @@ namespace SafeExamBrowser.Server
|
||||||
instructionConfirmation = attributesJson["instruction-confirm"].Value<string>();
|
instructionConfirmation = attributesJson["instruction-confirm"].Value<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (instruction)
|
attributes = ParseProctoringAttributes(attributesJson, instruction);
|
||||||
{
|
|
||||||
case Instructions.PROCTORING:
|
|
||||||
attributes.RoomName = attributesJson["jitsiMeetRoom"].Value<string>();
|
|
||||||
attributes.ServerUrl = attributesJson["jitsiMeetServerURL"].Value<string>();
|
|
||||||
attributes.Token = attributesJson["jitsiMeetToken"].Value<string>();
|
|
||||||
break;
|
|
||||||
case Instructions.PROCTORING_RECONFIGURATION:
|
|
||||||
attributes.AllowChat = attributesJson["jitsiMeetFeatureFlagChat"].Value<bool>();
|
|
||||||
attributes.ReceiveAudio = attributesJson["jitsiMeetReceiveAudio"].Value<bool>();
|
|
||||||
attributes.ReceiveVideo = attributesJson["jitsiMeetReceiveVideo"].Value<bool>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +173,77 @@ namespace SafeExamBrowser.Server
|
||||||
return instruction != default(string);
|
return instruction != default(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Attributes ParseProctoringAttributes(JObject attributesJson, string instruction)
|
||||||
|
{
|
||||||
|
var attributes = new Attributes();
|
||||||
|
|
||||||
|
switch (instruction)
|
||||||
|
{
|
||||||
|
case Instructions.PROCTORING:
|
||||||
|
ParseProctoringInstruction(attributes, attributesJson);
|
||||||
|
break;
|
||||||
|
case Instructions.PROCTORING_RECONFIGURATION:
|
||||||
|
ParseReconfigurationInstruction(attributes, attributesJson);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseProctoringInstruction(Attributes attributes, JObject attributesJson)
|
||||||
|
{
|
||||||
|
var provider = attributesJson["service-type"].Value<string>();
|
||||||
|
|
||||||
|
switch (provider)
|
||||||
|
{
|
||||||
|
case "JITSI_MEET":
|
||||||
|
attributes.Instruction.JitsiMeetRoomName = attributesJson["jitsiMeetRoom"].Value<string>();
|
||||||
|
attributes.Instruction.JitsiMeetServerUrl = attributesJson["jitsiMeetServerURL"].Value<string>();
|
||||||
|
attributes.Instruction.JitsiMeetToken = attributesJson["jitsiMeetToken"].Value<string>();
|
||||||
|
break;
|
||||||
|
case "ZOOM":
|
||||||
|
attributes.Instruction.ZoomApiKey = attributesJson["zoomAPIKey"].Value<string>();
|
||||||
|
attributes.Instruction.ZoomMeetingNumber = attributesJson["zoomRoom"].Value<string>();
|
||||||
|
attributes.Instruction.ZoomPassword = attributesJson["zoomMeetingKey"].Value<string>();
|
||||||
|
attributes.Instruction.ZoomSignature = attributesJson["zoomToken"].Value<string>();
|
||||||
|
attributes.Instruction.ZoomUserName = attributesJson["zoomUserName"].Value<string>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseReconfigurationInstruction(Attributes attributes, JObject attributesJson)
|
||||||
|
{
|
||||||
|
if (attributesJson.ContainsKey("jitsiMeetFeatureFlagChat"))
|
||||||
|
{
|
||||||
|
attributes.AllowChat = attributesJson["jitsiMeetFeatureFlagChat"].Value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributesJson.ContainsKey("zoomFeatureFlagChat"))
|
||||||
|
{
|
||||||
|
attributes.AllowChat = attributesJson["zoomFeatureFlagChat"].Value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributesJson.ContainsKey("jitsiMeetReceiveAudio"))
|
||||||
|
{
|
||||||
|
attributes.ReceiveAudio = attributesJson["jitsiMeetReceiveAudio"].Value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributesJson.ContainsKey("zoomReceiveAudio"))
|
||||||
|
{
|
||||||
|
attributes.ReceiveAudio = attributesJson["zoomReceiveAudio"].Value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributesJson.ContainsKey("jitsiMeetReceiveVideo"))
|
||||||
|
{
|
||||||
|
attributes.ReceiveVideo = attributesJson["jitsiMeetReceiveVideo"].Value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributesJson.ContainsKey("zoomReceiveVideo"))
|
||||||
|
{
|
||||||
|
attributes.ReceiveVideo = attributesJson["zoomReceiveVideo"].Value<bool>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal bool TryParseOauth2Token(HttpContent content, out string oauth2Token)
|
internal bool TryParseOauth2Token(HttpContent content, out string oauth2Token)
|
||||||
{
|
{
|
||||||
oauth2Token = default(string);
|
oauth2Token = default(string);
|
||||||
|
|
|
@ -393,7 +393,7 @@ namespace SafeExamBrowser.Server
|
||||||
switch (instruction)
|
switch (instruction)
|
||||||
{
|
{
|
||||||
case Instructions.PROCTORING:
|
case Instructions.PROCTORING:
|
||||||
Task.Run(() => ProctoringInstructionReceived?.Invoke(attributes.RoomName, attributes.ServerUrl, attributes.Token));
|
Task.Run(() => ProctoringInstructionReceived?.Invoke(attributes.Instruction));
|
||||||
break;
|
break;
|
||||||
case Instructions.PROCTORING_RECONFIGURATION:
|
case Instructions.PROCTORING_RECONFIGURATION:
|
||||||
Task.Run(() => ProctoringConfigurationReceived?.Invoke(attributes.AllowChat, attributes.ReceiveAudio, attributes.ReceiveVideo));
|
Task.Run(() => ProctoringConfigurationReceived?.Invoke(attributes.AllowChat, attributes.ReceiveAudio, attributes.ReceiveVideo));
|
||||||
|
|
|
@ -36,6 +36,16 @@ namespace SafeExamBrowser.Settings.Proctoring
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string MeetingNumber { get; set; }
|
public string MeetingNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The password of the meeting.
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The signature to be used for authentication.
|
||||||
|
/// </summary>
|
||||||
|
public string Signature { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user name to be used for the meeting.
|
/// The user name to be used for the meeting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue