feature: specify device profile/batch during pending enrolment

This commit is contained in:
Gary Sharp
2025-06-27 14:51:03 +10:00
parent 57ae665070
commit 8b8b26116e
13 changed files with 418 additions and 156 deletions
@@ -1,4 +1,5 @@
using Disco.Models.ClientServices.EnrolmentInformation; using Disco.Models.ClientServices.EnrolmentInformation;
using Newtonsoft.Json;
using System; using System;
namespace Disco.Models.ClientServices namespace Disco.Models.ClientServices
@@ -10,6 +11,11 @@ namespace Disco.Models.ClientServices
public string DomainName { get; set; } public string DomainName { get; set; }
public string ComputerName { get; set; } public string ComputerName { get; set; }
[JsonIgnore]
public int? DeviceProfileId { get; set; }
[JsonIgnore]
public int? DeviceBatchId { get; set; }
public string AssignedUserDomain { get; set; } public string AssignedUserDomain { get; set; }
public string AssignedUserUsername { get; set; } public string AssignedUserUsername { get; set; }
public string AssignedUserSID { get; set; } public string AssignedUserSID { get; set; }
@@ -1,6 +1,11 @@
namespace Disco.Models.UI.Config.Enrolment using System.Collections.Generic;
namespace Disco.Models.UI.Config.Enrolment
{ {
public interface ConfigEnrolmentStatusModel : BaseUIModel public interface ConfigEnrolmentStatusModel : BaseUIModel
{ {
int DefaultDeviceProfileId { get; set; }
List<Repository.DeviceProfile> DeviceProfiles { get; set; }
List<Repository.DeviceBatch> DeviceBatches { get; set; }
} }
} }
@@ -81,7 +81,7 @@ namespace Disco.Services.Devices.Enrolment
System.Enum.GetName(EnrolmentType.GetType(), EnrolmentType) System.Enum.GetName(EnrolmentType.GetType(), EnrolmentType)
}); });
} }
public static void LogSessionPending(string SessionId, string HostId, EnrolmentTypes EnrolmentType, string Reason, string Identifier) public static void LogSessionPending(string SessionId, string HostId, EnrolmentTypes EnrolmentType, string Reason, string Identifier, int? DeviceProfileId, int? DeviceBatchId)
{ {
Log(EventTypeIds.SessionPending, new object[] Log(EventTypeIds.SessionPending, new object[]
{ {
@@ -89,7 +89,9 @@ namespace Disco.Services.Devices.Enrolment
HostId, HostId,
System.Enum.GetName(EnrolmentType.GetType(), EnrolmentType), System.Enum.GetName(EnrolmentType.GetType(), EnrolmentType),
Reason, Reason,
Identifier Identifier,
DeviceProfileId,
DeviceBatchId,
}); });
} }
public static void LogSessionPendingApproved(string SessionId, string Username, string Reason) public static void LogSessionPendingApproved(string SessionId, string Username, string Reason)
@@ -59,7 +59,7 @@ namespace Disco.Services.Devices.Enrolment
.ToList(); .ToList();
} }
public static void ResolvePendingEnrolment(string sessionId, bool approve, string username, string reason) public static void ResolvePendingEnrolment(string sessionId, bool approve, string username, int? deviceProfileId, int? deviceBatchId, string reason)
{ {
if (!pendingEnrolments.TryGetValue(sessionId, out var enrolResponse)) if (!pendingEnrolments.TryGetValue(sessionId, out var enrolResponse))
throw new InvalidOperationException("The pending session is invalid or has expired"); throw new InvalidOperationException("The pending session is invalid or has expired");
@@ -71,7 +71,6 @@ namespace Disco.Services.Devices.Enrolment
if (!enrolResponse.IsPending) if (!enrolResponse.IsPending)
return; return;
enrolResponse.IsPending = false;
if (approve) if (approve)
{ {
enrolResponse.ErrorMessage = null; enrolResponse.ErrorMessage = null;
@@ -82,6 +81,9 @@ namespace Disco.Services.Devices.Enrolment
enrolResponse.ErrorMessage = $"Enrolment rejected"; enrolResponse.ErrorMessage = $"Enrolment rejected";
EnrolmentLog.LogSessionPendingRejected(sessionId, username, reason); EnrolmentLog.LogSessionPendingRejected(sessionId, username, reason);
} }
enrolResponse.DeviceProfileId = deviceProfileId;
enrolResponse.DeviceBatchId = deviceBatchId;
enrolResponse.IsPending = false;
} }
public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Enrol Request) public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Enrol Request)
@@ -216,7 +218,7 @@ namespace Disco.Services.Devices.Enrolment
response.PendingTimeout = DateTimeOffset.Now.Add(Database.DiscoConfiguration.Bootstrapper.PendingTimeout); response.PendingTimeout = DateTimeOffset.Now.Add(Database.DiscoConfiguration.Bootstrapper.PendingTimeout);
response.PendingIdentifier = GeneratePendingIdentifier(); response.PendingIdentifier = GeneratePendingIdentifier();
EnrolmentLog.LogSessionPending(sessionId, Request.SerialNumber, EnrolmentTypes.Normal, response.PendingReason, response.PendingIdentifier); EnrolmentLog.LogSessionPending(sessionId, Request.SerialNumber, EnrolmentTypes.Normal, response.PendingReason, response.PendingIdentifier, device?.DeviceProfileId, device?.DeviceBatchId);
if (pendingEnrolments.TryAdd(sessionId, response)) if (pendingEnrolments.TryAdd(sessionId, response))
return response; return response;
@@ -248,7 +250,19 @@ namespace Disco.Services.Devices.Enrolment
{ {
EnrolmentLog.LogSessionProgress(sessionId, 30, "New Device, Creating Disco Instance"); EnrolmentLog.LogSessionProgress(sessionId, 30, "New Device, Creating Disco Instance");
EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.SerialNumber); EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.SerialNumber);
DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
int deviceProfileId;
if (response.DeviceProfileId.HasValue)
deviceProfileId = response.DeviceProfileId.Value;
else
deviceProfileId = Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId;
var deviceProfile = Database.DeviceProfiles.Find(deviceProfileId)
?? throw new InvalidOperationException($"Device profile {deviceProfileId} was not found, please check your default profile configuration");
var deviceBatch = default(DeviceBatch);
if (response.DeviceBatchId.HasValue)
deviceBatch = Database.DeviceBatches.Find(response.DeviceBatchId.Value);
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.Hardware.Manufacturer, Request.Hardware.Model, Request.Hardware.ModelType); var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.Hardware.Manufacturer, Request.Hardware.Model, Request.Hardware.ModelType);
DeviceModel deviceModel = deviceModelResult.Item1; DeviceModel deviceModel = deviceModelResult.Item1;
@@ -263,6 +277,7 @@ namespace Disco.Services.Devices.Enrolment
DeviceDomainId = domain == null ? Request.ComputerName : $@"{domain.NetBiosName}\{Request.ComputerName}", DeviceDomainId = domain == null ? Request.ComputerName : $@"{domain.NetBiosName}\{Request.ComputerName}",
DeviceProfile = deviceProfile, DeviceProfile = deviceProfile,
DeviceModel = deviceModel, DeviceModel = deviceModel,
DeviceBatch = deviceBatch,
AllowUnauthenticatedEnrol = false, AllowUnauthenticatedEnrol = false,
CreatedDate = DateTime.Now, CreatedDate = DateTime.Now,
EnrolledDate = DateTime.Now, EnrolledDate = DateTime.Now,
@@ -285,6 +300,26 @@ namespace Disco.Services.Devices.Enrolment
device.DeviceModel = deviceModel; device.DeviceModel = deviceModel;
if (response.DeviceProfileId.HasValue && device.DeviceProfile.Id != response.DeviceProfileId.Value)
{
var deviceProfile = Database.DeviceProfiles.Find(response.DeviceProfileId.Value);
if (deviceProfile != null)
{
device.DeviceProfile = deviceProfile;
device.DeviceProfileId = deviceProfile.Id;
}
}
if (response.DeviceBatchId.HasValue && device.DeviceBatch?.Id != response.DeviceBatchId.Value)
{
var deviceBatch = Database.DeviceBatches.Find(response.DeviceBatchId.Value);
if (deviceBatch != null)
{
device.DeviceBatch = deviceBatch;
device.DeviceBatchId = deviceBatch.Id;
}
}
var deviceDomainId = domain == null ? Request.ComputerName : $@"{domain.NetBiosName}\{Request.ComputerName}"; var deviceDomainId = domain == null ? Request.ComputerName : $@"{domain.NetBiosName}\{Request.ComputerName}";
if (!string.Equals(device.DeviceDomainId, deviceDomainId, StringComparison.Ordinal)) if (!string.Equals(device.DeviceDomainId, deviceDomainId, StringComparison.Ordinal))
device.DeviceDomainId = deviceDomainId; device.DeviceDomainId = deviceDomainId;
@@ -11,9 +11,12 @@ namespace Disco.Web.Areas.API.Controllers
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
[DiscoAuthorize(Claims.Device.Actions.EnrolDevices)] [DiscoAuthorize(Claims.Device.Actions.EnrolDevices)]
public virtual ActionResult ResolveSessionPending(string sessionId, bool approve, string reason) public virtual ActionResult ResolveSessionPending(string sessionId, bool approve, int? deviceProfileId, int? deviceBatchId, string reason)
{ {
WindowsDeviceEnrolment.ResolvePendingEnrolment(sessionId, approve, CurrentUser.UserId, reason); if (approve && deviceProfileId == null)
throw new Exception("You must select a device profile to approve the enrollment");
WindowsDeviceEnrolment.ResolvePendingEnrolment(sessionId, approve, CurrentUser.UserId, deviceProfileId, deviceBatchId, reason);
return new HttpStatusCodeResult(200); return new HttpStatusCodeResult(200);
} }
@@ -2,6 +2,7 @@
using Disco.Services.Authorization; using Disco.Services.Authorization;
using Disco.Services.Plugins.Features.UIExtension; using Disco.Services.Plugins.Features.UIExtension;
using Disco.Services.Web; using Disco.Services.Web;
using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
namespace Disco.Web.Areas.Config.Controllers namespace Disco.Web.Areas.Config.Controllers
@@ -28,6 +29,10 @@ namespace Disco.Web.Areas.Config.Controllers
{ {
var m = new Models.Enrolment.StatusModel(); var m = new Models.Enrolment.StatusModel();
m.DefaultDeviceProfileId = Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId;
m.DeviceProfiles = Database.DeviceProfiles.ToList();
m.DeviceBatches = Database.DeviceBatches.ToList();
// UI Extensions // UI Extensions
UIExtensions.ExecuteExtensions<ConfigEnrolmentStatusModel>(this.ControllerContext, m); UIExtensions.ExecuteExtensions<ConfigEnrolmentStatusModel>(this.ControllerContext, m);
@@ -1,8 +1,12 @@
using Disco.Models.UI.Config.Enrolment; using Disco.Models.UI.Config.Enrolment;
using System.Collections.Generic;
namespace Disco.Web.Areas.Config.Models.Enrolment namespace Disco.Web.Areas.Config.Models.Enrolment
{ {
public class StatusModel : ConfigEnrolmentStatusModel public class StatusModel : ConfigEnrolmentStatusModel
{ {
public int DefaultDeviceProfileId { get; set; }
public List<Disco.Models.Repository.DeviceProfile> DeviceProfiles { get; set; }
public List<Disco.Models.Repository.DeviceBatch> DeviceBatches { get; set; }
} }
} }
@@ -1,4 +1,5 @@
@{ @model Disco.Web.Areas.Config.Models.Enrolment.StatusModel
@{
Authorization.Require(Claims.Config.Enrolment.ShowStatus); Authorization.Require(Claims.Config.Enrolment.ShowStatus);
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Device Enrolment", MVC.Config.Enrolment.Index(), "Status"); ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Device Enrolment", MVC.Config.Enrolment.Index(), "Status");
@@ -6,7 +7,7 @@
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR"); Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Isotope"); Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Isotope");
} }
<div id="enrolStatus"> <div id="enrolStatus" data-defaultdeviceprofileid="@Model.DefaultDeviceProfileId">
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
<div id="noSessions" data-bind="visible: noSessions"> <div id="noSessions" data-bind="visible: noSessions">
<h2>No enrolment sessions today</h2> <h2>No enrolment sessions today</h2>
@@ -35,10 +36,34 @@
<code data-bind="text: pendingIdentifier"></code> <code data-bind="text: pendingIdentifier"></code>
@Html.AntiForgeryToken(); @Html.AntiForgeryToken();
<input type="hidden" name="sessionId" data-bind="value: id" /> <input type="hidden" name="sessionId" data-bind="value: id" />
<div class="reason"> <div class="device-profile">
<input type="text" name="reason" placeholder="Reason (optional)" /> <label>
Device Profile
<select name="deviceProfileId" data-bind="value: deviceProfileId">
@foreach (var deviceProfile in Model.DeviceProfiles)
{
<option value="@deviceProfile.Id">@deviceProfile.Name (@deviceProfile.Id)</option>
}
</select>
</label>
</div> </div>
<div class="buttons"> if (Model.DeviceBatches.Count != 0)
{
<div class="device-batch">
<label>
Device Batch
<select name="deviceBatchId" data-bind="value: deviceBatchId">
<option value="" selected>&lt;None&gt;</option>
@foreach (var deviceBatch in Model.DeviceBatches)
{
<option value="@deviceBatch.Id">@deviceBatch.Name (@deviceBatch.Id)</option>
}
</select>
</label>
</div>
}
<div>
<input class="reason" type="text" name="reason" placeholder="Reason (optional)" />
<button type="button" value="True" class="button">Approve</button> <button type="button" value="True" class="button">Approve</button>
<button type="button" value="False" class="button">Reject</button> <button type="button" value="False" class="button">Reject</button>
</div> </div>
@@ -119,7 +144,6 @@
var host = $('#enrolStatus'); var host = $('#enrolStatus');
var hostSessions = $('#sessions'); var hostSessions = $('#sessions');
var hostDialogSessions = $('#dialogSession'); var hostDialogSessions = $('#dialogSession');
//var hostDialogSessionsProgress = $('#dialogSession').find('.sessionProgress');
var deviceModels = {}; var deviceModels = {};
var logHub; var logHub;
var deviceBaseUrl = '@(Url.Action(MVC.Device.Show()))/' var deviceBaseUrl = '@(Url.Action(MVC.Device.Show()))/'
@@ -168,6 +192,8 @@
self.hasError = ko.observable(false); self.hasError = ko.observable(false);
self.hasWarning = ko.observable(false); self.hasWarning = ko.observable(false);
self.deviceModelId = ko.observable(); self.deviceModelId = ko.observable();
self.deviceProfileId = ko.observable(parseInt(host.attr('data-defaultdeviceprofileid')));
self.deviceBatchId = ko.observable(null);
self.deviceModelDescription = ko.computed(function () { self.deviceModelDescription = ko.computed(function () {
var deviceModelId = self.deviceModelId(); var deviceModelId = self.deviceModelId();
var sessionDeviceInfo = self.sessionDeviceInfo(); var sessionDeviceInfo = self.sessionDeviceInfo();
@@ -231,7 +257,6 @@
session.messages.unshift(log); session.messages.unshift(log);
break; break;
case 11: // SessionProgress case 11: // SessionProgress
//session.progressbar.progressbar('option', 'value', log.Arguments[1]);
session.progressValue(log.Arguments[1]); session.progressValue(log.Arguments[1]);
session.progressStatus(log.Arguments[2]); session.progressStatus(log.Arguments[2]);
break; break;
@@ -252,6 +277,12 @@
case 14: // SessionPending case 14: // SessionPending
session.isPending(true); session.isPending(true);
session.pendingIdentifier(log.Arguments[4]); session.pendingIdentifier(log.Arguments[4]);
if (log.Arguments[5]) {
session.deviceProfileId(log.Arguments[5]);
}
if (log.Arguments[6]) {
session.deviceBatchId(log.Arguments[6]);
}
session.messages.unshift(log); session.messages.unshift(log);
session.progressValue(-1); session.progressValue(-1);
session.progressStatus('Pending enrolment approval'); session.progressStatus('Pending enrolment approval');
@@ -309,9 +340,11 @@
height: 574, height: 574,
width: 900, width: 900,
resizable: false, resizable: false,
autoOpen: false autoOpen: false,
open: function (e, ui) {
}
}); });
//hostDialogSessionsProgress.progressbar();
// Create View Model // Create View Model
vm = new pageViewModel(); vm = new pageViewModel();
@@ -333,9 +366,10 @@
// Load Logs // Load Logs
var d = new Date(); var d = new Date();
d = new Date(d.getTime() - (d.getTimezoneOffset() * 60 * 1000));
var loadData = { var loadData = {
Format: "json", Format: "json",
Start: d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate(), Start: d.toISOString().substring(0, 10),
End: null, End: null,
ModuleId: 50, ModuleId: 50,
Take: 2000, Take: 2000,
@@ -36,7 +36,7 @@ namespace Disco.Web.Areas.Config.Views.Enrolment
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Enrolment/Status.cshtml")] [System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Enrolment/Status.cshtml")]
public partial class Status : Disco.Services.Web.WebViewPage<dynamic> public partial class Status : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Enrolment.StatusModel>
{ {
public Status() public Status()
{ {
@@ -44,7 +44,7 @@ namespace Disco.Web.Areas.Config.Views.Enrolment
public override void Execute() public override void Execute()
{ {
#line 1 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 2 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Authorization.Require(Claims.Config.Enrolment.ShowStatus); Authorization.Require(Claims.Config.Enrolment.ShowStatus);
@@ -60,12 +60,23 @@ WriteLiteral("\r\n<div");
WriteLiteral(" id=\"enrolStatus\""); WriteLiteral(" id=\"enrolStatus\"");
WriteLiteral(" data-defaultdeviceprofileid=\"");
#line 10 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Model.DefaultDeviceProfileId);
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
WriteLiteral(" "); WriteLiteral(" ");
#line 10 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 11 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Html.AntiForgeryToken()); Write(Html.AntiForgeryToken());
@@ -171,13 +182,13 @@ WriteLiteral(" data-bind=\"visible: isPending\"");
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
#line 33 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 34 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
#line default #line default
#line hidden #line hidden
#line 33 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 34 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
using (Html.BeginForm(MVC.API.Enrolment.ResolveSessionPending(), FormMethod.Post)) using (Html.BeginForm(MVC.API.Enrolment.ResolveSessionPending(), FormMethod.Post))
{ {
@@ -191,20 +202,20 @@ WriteLiteral(" data-bind=\"text: pendingIdentifier\"");
WriteLiteral("></code>\r\n"); WriteLiteral("></code>\r\n");
#line 36 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 37 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
#line default #line default
#line hidden #line hidden
#line 36 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 37 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Html.AntiForgeryToken()); Write(Html.AntiForgeryToken());
#line default #line default
#line hidden #line hidden
#line 36 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 37 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
; ;
@@ -222,9 +233,164 @@ WriteLiteral(" />\r\n");
WriteLiteral(" <div"); WriteLiteral(" <div");
WriteLiteral(" class=\"reason\""); WriteLiteral(" class=\"device-profile\"");
WriteLiteral(">\r\n <input"); WriteLiteral(">\r\n <label>\r\n Device Profile\r\n " +
" <select");
WriteLiteral(" name=\"deviceProfileId\"");
WriteLiteral(" data-bind=\"value: deviceProfileId\"");
WriteLiteral(">\r\n");
#line 43 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
#line default
#line hidden
#line 43 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
foreach (var deviceProfile in Model.DeviceProfiles)
{
#line default
#line hidden
WriteLiteral(" <option");
WriteAttribute("value", Tuple.Create(" value=\"", 2814), Tuple.Create("\"", 2839)
#line 45 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
, Tuple.Create(Tuple.Create("", 2822), Tuple.Create<System.Object, System.Int32>(deviceProfile.Id
#line default
#line hidden
, 2822), false)
);
WriteLiteral(">");
#line 45 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(deviceProfile.Name);
#line default
#line hidden
WriteLiteral(" (");
#line 45 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(deviceProfile.Id);
#line default
#line hidden
WriteLiteral(")</option>\r\n");
#line 46 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
}
#line default
#line hidden
WriteLiteral(" </select>\r\n </label>\r\n " +
" </div>\r\n");
#line 50 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
if (Model.DeviceBatches.Count != 0)
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" class=\"device-batch\"");
WriteLiteral(">\r\n <label>\r\n Device Ba" +
"tch\r\n <select");
WriteLiteral(" name=\"deviceBatchId\"");
WriteLiteral(" data-bind=\"value: deviceBatchId\"");
WriteLiteral(">\r\n <option");
WriteLiteral(" value=\"\"");
WriteLiteral(" selected>&lt;None&gt;</option>\r\n");
#line 57 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
#line default
#line hidden
#line 57 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
foreach (var deviceBatch in Model.DeviceBatches)
{
#line default
#line hidden
WriteLiteral(" <option");
WriteAttribute("value", Tuple.Create(" value=\"", 3596), Tuple.Create("\"", 3619)
#line 59 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
, Tuple.Create(Tuple.Create("", 3604), Tuple.Create<System.Object, System.Int32>(deviceBatch.Id
#line default
#line hidden
, 3604), false)
);
WriteLiteral(">");
#line 59 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(deviceBatch.Name);
#line default
#line hidden
WriteLiteral(" (");
#line 59 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(deviceBatch.Id);
#line default
#line hidden
WriteLiteral(")</option>\r\n");
#line 60 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
}
#line default
#line hidden
WriteLiteral(" </select>\r\n </label>\r\n" +
" </div>\r\n");
#line 64 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
}
#line default
#line hidden
WriteLiteral(" <div>\r\n <input");
WriteLiteral(" class=\"reason\"");
WriteLiteral(" type=\"text\""); WriteLiteral(" type=\"text\"");
@@ -232,13 +398,7 @@ WriteLiteral(" name=\"reason\"");
WriteLiteral(" placeholder=\"Reason (optional)\""); WriteLiteral(" placeholder=\"Reason (optional)\"");
WriteLiteral(" />\r\n </div>\r\n"); WriteLiteral(" />\r\n <button");
WriteLiteral(" <div");
WriteLiteral(" class=\"buttons\"");
WriteLiteral(">\r\n <button");
WriteLiteral(" type=\"button\""); WriteLiteral(" type=\"button\"");
@@ -257,7 +417,7 @@ WriteLiteral(" class=\"button\"");
WriteLiteral(">Reject</button>\r\n </div>\r\n"); WriteLiteral(">Reject</button>\r\n </div>\r\n");
#line 45 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 70 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
} }
@@ -431,13 +591,12 @@ WriteLiteral(@">
var host = $('#enrolStatus'); var host = $('#enrolStatus');
var hostSessions = $('#sessions'); var hostSessions = $('#sessions');
var hostDialogSessions = $('#dialogSession'); var hostDialogSessions = $('#dialogSession');
//var hostDialogSessionsProgress = $('#dialogSession').find('.sessionProgress');
var deviceModels = {}; var deviceModels = {};
var logHub; var logHub;
var deviceBaseUrl = '"); var deviceBaseUrl = '");
#line 125 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 149 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Url.Action(MVC.Device.Show())); Write(Url.Action(MVC.Device.Show()));
@@ -446,7 +605,7 @@ WriteLiteral(@">
WriteLiteral("/\'\r\n var deviceModelImageUrl = \'"); WriteLiteral("/\'\r\n var deviceModelImageUrl = \'");
#line 126 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 150 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Url.Action(MVC.API.DeviceModel.Image())); Write(Url.Action(MVC.API.DeviceModel.Image()));
@@ -455,7 +614,7 @@ WriteLiteral("/\'\r\n var deviceModelImageUrl = \'");
WriteLiteral("/\'\r\n var iconWarningUrl = \'url("); WriteLiteral("/\'\r\n var iconWarningUrl = \'url(");
#line 127 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 151 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Links.ClientSource.Style.Images.Status.warning32_png); Write(Links.ClientSource.Style.Images.Status.warning32_png);
@@ -464,7 +623,7 @@ WriteLiteral("/\'\r\n var iconWarningUrl = \'url(");
WriteLiteral(")\';\r\n var iconErrorUrl = \'url("); WriteLiteral(")\';\r\n var iconErrorUrl = \'url(");
#line 128 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 152 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Links.ClientSource.Style.Images.Status.fail32_png); Write(Links.ClientSource.Style.Images.Status.fail32_png);
@@ -490,104 +649,108 @@ WriteLiteral(")\';\r\n\r\n function pageViewModel() {\r\n var
"vable();\r\n self.sessionEnded = ko.observable(false);\r\n sel" + "vable();\r\n self.sessionEnded = ko.observable(false);\r\n sel" +
"f.progressbar = null;\r\n self.hasError = ko.observable(false);\r\n " + "f.progressbar = null;\r\n self.hasError = ko.observable(false);\r\n " +
" self.hasWarning = ko.observable(false);\r\n self.deviceModelId = " + " self.hasWarning = ko.observable(false);\r\n self.deviceModelId = " +
"ko.observable();\r\n self.deviceModelDescription = ko.computed(function" + "ko.observable();\r\n self.deviceProfileId = ko.observable(parseInt(host" +
" () {\r\n var deviceModelId = self.deviceModelId();\r\n " + ".attr(\'data-defaultdeviceprofileid\')));\r\n self.deviceBatchId = ko.obs" +
" var sessionDeviceInfo = self.sessionDeviceInfo();\r\n if (deviceM" + "ervable(null);\r\n self.deviceModelDescription = ko.computed(function (" +
"odelId) {\r\n var dm = deviceModels[deviceModelId];\r\n " + ") {\r\n var deviceModelId = self.deviceModelId();\r\n " +
"var sessionDeviceInfo = self.sessionDeviceInfo();\r\n if (deviceMod" +
"elId) {\r\n var dm = deviceModels[deviceModelId];\r\n " +
" if (dm) {\r\n if (dm.Description)\r\n " + " if (dm) {\r\n if (dm.Description)\r\n " +
" return dm.Description;\r\n else\r\n " + " return dm.Description;\r\n else\r\n " +
" return dm.Manufacturer + \' \' + dm.Model;\r\n }\r" + " return dm.Manufacturer + \' \' + dm.Model;\r\n }\r\n " +
"\n }\r\n if (sessionDeviceInfo) {\r\n " + " }\r\n if (sessionDeviceInfo) {\r\n " +
" return sessionDeviceInfo.Arguments[6] + \' \' + sessionDeviceInfo.Arguments[7];\r" + "return sessionDeviceInfo.Arguments[6] + \' \' + sessionDeviceInfo.Arguments[7];\r\n " +
"\n }\r\n });\r\n self.deviceUrl = ko.computed(fu" + " }\r\n });\r\n self.deviceUrl = ko.computed(func" +
"nction () {\r\n var serialNumber = self.serialNumber();\r\n " + "tion () {\r\n var serialNumber = self.serialNumber();\r\n " +
" if (serialNumber)\r\n return deviceBaseUrl + serialNumber" + " if (serialNumber)\r\n return deviceBaseUrl + serialNumber;\r" +
";\r\n else\r\n return null;\r\n });\r\n " + "\n else\r\n return null;\r\n });\r\n " +
" self.deviceModelImageUrl = ko.computed(function () {\r\n va" + " self.deviceModelImageUrl = ko.computed(function () {\r\n var " +
"r deviceModelImage;\r\n if (self.deviceModelId())\r\n " + "deviceModelImage;\r\n if (self.deviceModelId())\r\n " +
" deviceModelImage = \'url(\' + deviceModelImageUrl + self.deviceModelId() + \')\'" + " deviceModelImage = \'url(\' + deviceModelImageUrl + self.deviceModelId() + \')\';\r" +
";\r\n else\r\n deviceModelImage = \'url(\' + deviceM" + "\n else\r\n deviceModelImage = \'url(\' + deviceMod" +
"odelImageUrl + \')\';\r\n if (self.hasError())\r\n r" + "elImageUrl + \')\';\r\n if (self.hasError())\r\n ret" +
"eturn iconErrorUrl + \', \' + deviceModelImage;\r\n else\r\n " + "urn iconErrorUrl + \', \' + deviceModelImage;\r\n else\r\n " +
" if (self.hasWarning())\r\n return iconWarningUrl +" + " if (self.hasWarning())\r\n return iconWarningUrl + \'" +
" \', \' + deviceModelImage;\r\n else\r\n ret" + ", \' + deviceModelImage;\r\n else\r\n retur" +
"urn \'none, \' + deviceModelImage;\r\n });\r\n self.select = fun" + "n \'none, \' + deviceModelImage;\r\n });\r\n self.select = funct" +
"ction (e, d) {\r\n vm.currentSession(self);\r\n hostDi" + "ion (e, d) {\r\n vm.currentSession(self);\r\n hostDial" +
"alogSessions.dialog(\'open\');\r\n hostDialogSessions.dialog(\'option\'" + "ogSessions.dialog(\'open\');\r\n hostDialogSessions.dialog(\'option\', " +
", \'title\', \'Device Enrolment: \' + self.title());\r\n }\r\n }\r\n\r\n " + "\'title\', \'Device Enrolment: \' + self.title());\r\n }\r\n }\r\n\r\n " +
" function parseLog(log) {\r\n if (log.ModuleId === 50 && log.Argum" + " function parseLog(log) {\r\n if (log.ModuleId === 50 && log.Argumen" +
"ents && log.Arguments.length > 0) {\r\n // find session\r\n " + "ts && log.Arguments.length > 0) {\r\n // find session\r\n " +
" var sessionId = log.Arguments[0];\r\n var session = vm.sessio" + " var sessionId = log.Arguments[0];\r\n var session = vm.sessionI" +
"nIndex[sessionId];\r\n if (!session && log.EventTypeId === 10) { //" + "ndex[sessionId];\r\n if (!session && log.EventTypeId === 10) { // S" +
" Starting Session (Ignore \'partial\' sessions)\r\n session = new" + "tarting Session (Ignore \'partial\' sessions)\r\n session = new s" +
" sessionViewModel(sessionId);\r\n vm.sessionIndex[sessionId] = " + "essionViewModel(sessionId);\r\n vm.sessionIndex[sessionId] = se" +
"session;\r\n vm.sessions.unshift(session);\r\n " + "ssion;\r\n vm.sessions.unshift(session);\r\n v" +
" vm.noSessions(false);\r\n }\r\n if (session) {\r\n " + "m.noSessions(false);\r\n }\r\n if (session) {\r\n " +
" switch (log.EventTypeId) {\r\n case 10: // S" + " switch (log.EventTypeId) {\r\n case 10: // Ses" +
"essionStarting\r\n session.title(log.Arguments[1]);\r\n " + "sionStarting\r\n session.title(log.Arguments[1]);\r\n " +
" session.startTime(log.FormattedTimestamp.substring(log" + " session.startTime(log.FormattedTimestamp.substring(log.F" +
".FormattedTimestamp.indexOf(\' \') + 1));\r\n session.mes" + "ormattedTimestamp.indexOf(\' \') + 1));\r\n session.messa" +
"sages.unshift(log);\r\n break;\r\n " + "ges.unshift(log);\r\n break;\r\n c" +
" case 11: // SessionProgress\r\n //session.progressbar." + "ase 11: // SessionProgress\r\n session.progressValue(lo" +
"progressbar(\'option\', \'value\', log.Arguments[1]);\r\n s" + "g.Arguments[1]);\r\n session.progressStatus(log.Argumen" +
"ession.progressValue(log.Arguments[1]);\r\n session.pro" + "ts[2]);\r\n break;\r\n case 12: //" +
"gressStatus(log.Arguments[2]);\r\n break;\r\n " + " SessionDevice\r\n session.title(log.Arguments[1]);\r\n " +
" case 12: // SessionDevice\r\n session.title" + " session.serialNumber(log.Arguments[1]);\r\n " +
"(log.Arguments[1]);\r\n session.serialNumber(log.Argume" + " if (log.Arguments.length >= 3 && log.Arguments[2])\r\n " +
"nts[1]);\r\n if (log.Arguments.length >= 3 && log.Argum" + " session.deviceModelId(log.Arguments[2]);\r\n " +
"ents[2])\r\n session.deviceModelId(log.Arguments[2]" + " break;\r\n break;\r\n cas" +
");\r\n break;\r\n break;\r\n " + "e 13: // SessionDeviceInfo\r\n session.title(log.Argume" +
" case 13: // SessionDeviceInfo\r\n s" + "nts[1]);\r\n session.serialNumber(log.Arguments[1]);\r\n " +
"ession.title(log.Arguments[1]);\r\n session.serialNumbe" + " session.sessionDeviceInfo(log);\r\n " +
"r(log.Arguments[1]);\r\n session.sessionDeviceInfo(log)" + " if (log.Arguments.length >= 10 && log.Arguments[9])\r\n " +
";\r\n if (log.Arguments.length >= 10 && log.Arguments[9" + " session.deviceModelId(log.Arguments[9]);\r\n " +
"])\r\n session.deviceModelId(log.Arguments[9]);\r\n " + " break;\r\n case 14: // SessionPending\r\n " +
" break;\r\n case 14: // SessionPen" + " session.isPending(true);\r\n session.pending" +
"ding\r\n session.isPending(true);\r\n " + "Identifier(log.Arguments[4]);\r\n if (log.Arguments[5])" +
" session.pendingIdentifier(log.Arguments[4]);\r\n " + " {\r\n session.deviceProfileId(log.Arguments[5]);\r\n" +
" session.messages.unshift(log);\r\n session.progressVa" + " }\r\n if (log.Arguments[6])" +
"lue(-1);\r\n session.progressStatus(\'Pending enrolment " + " {\r\n session.deviceBatchId(log.Arguments[6]);\r\n " +
"approval\');\r\n break;\r\n case 15" + " }\r\n session.messages.unshif" +
": // SessionPendingApproved\r\n session.isPending(false" + "t(log);\r\n session.progressValue(-1);\r\n " +
");\r\n session.messages.unshift(log);\r\n " + " session.progressStatus(\'Pending enrolment approval\');\r\n " +
" session.progressValue(-1);\r\n session.prog" + " break;\r\n case 15: // SessionPendingApprov" +
"ressStatus(\'Enrolment approval, waiting for client\');\r\n " + "ed\r\n session.isPending(false);\r\n " +
" break;\r\n case 16: // SessionPendingRejected\r\n " + " session.messages.unshift(log);\r\n session.progr" +
" session.isPending(false);\r\n sessio" + "essValue(-1);\r\n session.progressStatus(\'Enrolment app" +
"n.messages.unshift(log);\r\n session.progressValue(-1);" + "roval, waiting for client\');\r\n break;\r\n " +
"\r\n session.progressStatus(\'Enrolment rejected, waitin" + " case 16: // SessionPendingRejected\r\n sessio" +
"g for client\');\r\n break;\r\n cas" + "n.isPending(false);\r\n session.messages.unshift(log);\r" +
"e 17: // SessionContinuing\r\n session.isPending(false)" + "\n session.progressValue(-1);\r\n " +
";\r\n session.messages.unshift(log);\r\n " + " session.progressStatus(\'Enrolment rejected, waiting for client\');\r\n " +
" break;\r\n case 20: // SessionFinished\r\n " + " break;\r\n case 17: // SessionContinuin" +
" session.sessionEnded(true);\r\n ses" + "g\r\n session.isPending(false);\r\n " +
"sion.isPending(false);\r\n if (session.hasError())\r\n " +
" session.progressStatus(\'Enrolment Finished with an " +
"Error\');\r\n else\r\n if (" +
"session.hasWarning())\r\n session.progressStatu" +
"s(\'Enrolment Finished with a Warning\');\r\n else\r\n " +
" session.progressStatus(\'Enrolment Finished Su" +
"ccessfully\');\r\n session.messages.unshift(log);\r\n " +
" break;\r\n case 21: // SessionDiagno" +
"sticInformation\r\n session.console.push(log);\r\n " +
" break;\r\n case 22: // SessionWarning\r" +
"\n session.hasWarning(true);\r\n " +
" session.messages.unshift(log);\r\n break;\r\n " + " session.messages.unshift(log);\r\n break;\r\n " +
" case 23: // SessionError\r\n case 24: // Se" + " case 20: // SessionFinished\r\n sessi" +
"ssionErrorWithInner\r\n case 25: // SessionClientError\r\n " + "on.sessionEnded(true);\r\n session.isPending(false);\r\n " +
" session.hasError(true);\r\n se" + " if (session.hasError())\r\n " +
"ssion.messages.unshift(log);\r\n break;\r\n " + " session.progressStatus(\'Enrolment Finished with an Error\');\r\n " +
" default:\r\n session.messages.unshift(log);\r\n" + " else\r\n if (session.hasWarning())\r\n " +
" }\r\n }\r\n }\r\n }\r\n func" + " session.progressStatus(\'Enrolment Finished wit" +
"tion init() {\r\n hostDialogSessions.dialog({\r\n modal: t" + "h a Warning\');\r\n else\r\n " +
"rue,\r\n height: 574,\r\n width: 900,\r\n " + " session.progressStatus(\'Enrolment Finished Successfully\');\r\n " +
" resizable: false,\r\n autoOpen: false\r\n });\r\n " + " session.messages.unshift(log);\r\n br" +
" //hostDialogSessionsProgress.progressbar();\r\n\r\n // Create View Mode" + "eak;\r\n case 21: // SessionDiagnosticInformation\r\n " +
"l\r\n vm = new pageViewModel();\r\n $.ajax({\r\n " + " session.console.push(log);\r\n brea" +
"url: \'"); "k;\r\n case 22: // SessionWarning\r\n " +
" session.hasWarning(true);\r\n session.messages.unsh" +
"ift(log);\r\n break;\r\n case 23: " +
"// SessionError\r\n case 24: // SessionErrorWithInner\r\n " +
" case 25: // SessionClientError\r\n " +
"session.hasError(true);\r\n session.messages.unshift(lo" +
"g);\r\n break;\r\n default:\r\n " +
" session.messages.unshift(log);\r\n }\r\n " +
" }\r\n }\r\n }\r\n function init() {\r\n " +
" hostDialogSessions.dialog({\r\n modal: true,\r\n hei" +
"ght: 574,\r\n width: 900,\r\n resizable: false,\r\n " +
" autoOpen: false,\r\n open: function (e, ui) {\r\n\r\n " +
" }\r\n });\r\n\r\n // Create View Model\r\n vm " +
"= new pageViewModel();\r\n $.ajax({\r\n url: \'");
#line 319 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 352 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Url.Action(MVC.API.DeviceModel.Index())); Write(Url.Action(MVC.API.DeviceModel.Index()));
@@ -610,9 +773,10 @@ WriteLiteral(@"',
// Load Logs // Load Logs
var d = new Date(); var d = new Date();
d = new Date(d.getTime() - (d.getTimezoneOffset() * 60 * 1000));
var loadData = { var loadData = {
Format: ""json"", Format: ""json"",
Start: d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate(), Start: d.toISOString().substring(0, 10),
End: null, End: null,
ModuleId: 50, ModuleId: 50,
Take: 2000, Take: 2000,
@@ -622,7 +786,7 @@ WriteLiteral(@"',
url: '"); url: '");
#line 345 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 379 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Url.Action(MVC.API.Logging.RetrieveEvents())); Write(Url.Action(MVC.API.Logging.RetrieveEvents()));
@@ -661,7 +825,7 @@ WriteLiteral(@"',
$.connection.hub.qs = { LogModules: '"); $.connection.hub.qs = { LogModules: '");
#line 375 "..\..\Areas\Config\Views\Enrolment\Status.cshtml" #line 409 "..\..\Areas\Config\Views\Enrolment\Status.cshtml"
Write(Disco.Services.Devices.Enrolment.EnrolmentLog.Current.LiveLogGroupName); Write(Disco.Services.Devices.Enrolment.EnrolmentLog.Current.LiveLogGroupName);
+4 -4
View File
@@ -525,19 +525,19 @@ div.logEventsViewport table.logEventsViewport > tbody > tr > td.message {
} }
#dialogSession .sessionProgress > p.sessionStart { #dialogSession .sessionProgress > p.sessionStart {
color: #888; color: #888;
margin-bottom: 2px; margin-bottom: 0;
} }
#dialogSession .sessionProgress > p.sessionStatus { #dialogSession .sessionProgress > p.sessionStatus {
height: 1.6em; height: 1.6em;
overflow: hidden; overflow: hidden;
margin-bottom: 3px; margin-bottom: 0;
} }
#dialogSession .sessionProgress code { #dialogSession .sessionProgress code {
font-size: 2em; font-size: 2em;
color: #E51400; color: #E51400;
} }
#dialogSession .sessionProgress div.reason { #dialogSession .sessionProgress .reason {
margin-bottom: 3px; width: 160px;
} }
#dialogSession .sessionInfoContainer > div { #dialogSession .sessionInfoContainer > div {
float: left; float: left;
+5 -5
View File
@@ -545,22 +545,22 @@ div.logEventsViewport {
& > p.sessionStart { & > p.sessionStart {
color: #888; color: #888;
margin-bottom: 2px; margin-bottom: 0;
} }
& > p.sessionStatus { & > p.sessionStatus {
height: 1.6em; height: 1.6em;
overflow: hidden; overflow: hidden;
margin-bottom: 3px; margin-bottom: 0;
} }
& code { code {
font-size: 2em; font-size: 2em;
color: @ThemeRed; color: @ThemeRed;
} }
& div.reason { .reason {
margin-bottom: 3px; width: 160px;
} }
} }
File diff suppressed because one or more lines are too long
@@ -107,6 +107,8 @@ namespace Disco.Web.Areas.API.Controllers
{ {
public readonly string sessionId = "sessionId"; public readonly string sessionId = "sessionId";
public readonly string approve = "approve"; public readonly string approve = "approve";
public readonly string deviceProfileId = "deviceProfileId";
public readonly string deviceBatchId = "deviceBatchId";
public readonly string reason = "reason"; public readonly string reason = "reason";
} }
static readonly ActionParamsClass_PendingTimeoutMinutes s_params_PendingTimeoutMinutes = new ActionParamsClass_PendingTimeoutMinutes(); static readonly ActionParamsClass_PendingTimeoutMinutes s_params_PendingTimeoutMinutes = new ActionParamsClass_PendingTimeoutMinutes();
@@ -137,16 +139,18 @@ namespace Disco.Web.Areas.API.Controllers
public T4MVC_EnrolmentController() : base(Dummy.Instance) { } public T4MVC_EnrolmentController() : base(Dummy.Instance) { }
[NonAction] [NonAction]
partial void ResolveSessionPendingOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string sessionId, bool approve, string reason); partial void ResolveSessionPendingOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string sessionId, bool approve, int? deviceProfileId, int? deviceBatchId, string reason);
[NonAction] [NonAction]
public override System.Web.Mvc.ActionResult ResolveSessionPending(string sessionId, bool approve, string reason) public override System.Web.Mvc.ActionResult ResolveSessionPending(string sessionId, bool approve, int? deviceProfileId, int? deviceBatchId, string reason)
{ {
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ResolveSessionPending); var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ResolveSessionPending);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "sessionId", sessionId); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "sessionId", sessionId);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "approve", approve); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "approve", approve);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "deviceProfileId", deviceProfileId);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "deviceBatchId", deviceBatchId);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "reason", reason); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "reason", reason);
ResolveSessionPendingOverride(callInfo, sessionId, approve, reason); ResolveSessionPendingOverride(callInfo, sessionId, approve, deviceProfileId, deviceBatchId, reason);
return callInfo; return callInfo;
} }