mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Clean up errors and majority of warnings.
This commit is contained in:
parent
28079f887a
commit
0f9ea4957b
@ -52,7 +52,7 @@ public class Logger
|
||||
|
||||
while (exception != null)
|
||||
{
|
||||
File.AppendAllText(LogsPath, $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}\t[Error]\t{exception?.Message}\t{exception?.StackTrace}\t{exception?.Source}{Environment.NewLine}");
|
||||
File.AppendAllText(LogsPath, $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}\t[Error]\t{exception.Message}\t{exception.StackTrace}\t{exception.Source}{Environment.NewLine}");
|
||||
Console.WriteLine(exception.Message);
|
||||
exception = exception.InnerException;
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ public class ApiAuthorizationFilter : IAsyncAuthorizationFilter
|
||||
|
||||
if (http.User.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
var userResult = await _dataService.GetUserByNameWithOrg($"{http.User.Identity.Name}");
|
||||
var userResult = await _dataService.GetUserByName($"{http.User.Identity.Name}");
|
||||
if (userResult.IsSuccess && userResult.Value.IsAdministrator)
|
||||
{
|
||||
http.Request.Headers["OrganizationID"] = userResult.Value.OrganizationID;
|
||||
|
||||
@ -3,26 +3,43 @@ using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Server.Components;
|
||||
|
||||
public class AuthComponentBase : ComponentBase
|
||||
{
|
||||
private RemotelyUser? _user;
|
||||
private string? _userName;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
IsAuthenticated = await AuthService.IsAuthenticated();
|
||||
User = await AuthService.GetUser();
|
||||
Username = User?.UserName;
|
||||
var userResult = await AuthService.GetUser();
|
||||
if (userResult.IsSuccess)
|
||||
{
|
||||
_user = userResult.Value;
|
||||
_userName = userResult.Value.UserName ?? string.Empty;
|
||||
}
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
public bool IsAuthenticated { get; private set; }
|
||||
|
||||
public RemotelyUser User { get; private set; }
|
||||
public RemotelyUser User
|
||||
{
|
||||
get => _user ?? throw new InvalidOperationException("User has not been resolved yet.");
|
||||
private set => _user = value;
|
||||
}
|
||||
|
||||
public string Username { get; private set; }
|
||||
public string UserName
|
||||
{
|
||||
get => _userName ?? throw new InvalidOperationException("User has not been resolved yet.");
|
||||
private set => _userName = value;
|
||||
}
|
||||
|
||||
[Inject]
|
||||
protected IAuthService AuthService { get; set; }
|
||||
protected IAuthService AuthService { get; set; } = null!;
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ public partial class DeviceCard : AuthComponentBase, IDisposable
|
||||
await base.OnInitializedAsync();
|
||||
_theme = await AppState.GetEffectiveTheme();
|
||||
_currentVersion = UpgradeService.GetCurrentVersion();
|
||||
_deviceGroups = DataService.GetDeviceGroups(Username);
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
AppState.PropertyChanged += AppState_PropertyChanged;
|
||||
CircuitConnection.MessageReceived += CircuitConnection_MessageReceived;
|
||||
}
|
||||
|
||||
@ -34,29 +34,26 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
private readonly List<PropertyInfo> _sortableProperties = new();
|
||||
private int _currentPage = 1;
|
||||
private int _devicesPerPage = 25;
|
||||
private string _filter;
|
||||
private string? _filter;
|
||||
private bool _hideOfflineDevices = true;
|
||||
private string _selectedGroupId;
|
||||
private string? _selectedGroupId;
|
||||
private string _selectedSortProperty = "DeviceName";
|
||||
private ListSortDirection _sortDirection;
|
||||
|
||||
[Inject]
|
||||
private IClientAppState AppState { get; set; }
|
||||
private IClientAppState AppState { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ICircuitConnection CircuitConnection { get; set; }
|
||||
private ICircuitConnection CircuitConnection { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IDataService DataService { get; set; }
|
||||
private IDataService DataService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJsInterop JsInterop { get; set; }
|
||||
private IJsInterop JsInterop { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ILogger<DevicesFrame> Logger { get; set; }
|
||||
|
||||
[Inject]
|
||||
private IToastService ToastService { get; set; }
|
||||
private IToastService ToastService { get; init; } = null!;
|
||||
|
||||
private int TotalPages => (int)Math.Max(1, Math.Ceiling((decimal)_filteredDevices.Count / _devicesPerPage));
|
||||
|
||||
@ -82,7 +79,7 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
|
||||
_deviceGroups.Clear();
|
||||
|
||||
_deviceGroups.AddRange(DataService.GetDeviceGroups(User.UserName));
|
||||
_deviceGroups.AddRange(DataService.GetDeviceGroups(UserName));
|
||||
|
||||
_selectedGroupId = _deviceGroupAll;
|
||||
|
||||
@ -105,23 +102,31 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
return shouldRender;
|
||||
}
|
||||
|
||||
private void AddScriptResult(ScriptResult result)
|
||||
private async Task AddScriptResult(ScriptResult result)
|
||||
{
|
||||
var device = DataService.GetDevice(result.DeviceID);
|
||||
AppState.AddTerminalLine($"{device?.DeviceName} @ {result.TimeStamp}", "font-weight-bold");
|
||||
var deviceResult = await DataService.GetDevice(result.DeviceID);
|
||||
if (!deviceResult.IsSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var line in result.StandardOutput)
|
||||
AppState.AddTerminalLine($"{deviceResult.Value.DeviceName} @ {result.TimeStamp}", "font-weight-bold");
|
||||
|
||||
var stdOut = result.StandardOutput ?? Array.Empty<string>();
|
||||
var stdErr = result.ErrorOutput ?? Array.Empty<string>();
|
||||
|
||||
foreach (var line in stdOut)
|
||||
{
|
||||
AppState.AddTerminalLine(line, "text-info");
|
||||
}
|
||||
foreach (var line in result.ErrorOutput)
|
||||
foreach (var line in stdErr)
|
||||
{
|
||||
AppState.AddTerminalLine(line, "text-danger");
|
||||
}
|
||||
AppState.InvokePropertyChanged(nameof(AppState.TerminalLines));
|
||||
}
|
||||
|
||||
private void AppState_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
private void AppState_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(AppState.DevicesFrameFocusedCardState) ||
|
||||
e.PropertyName == nameof(AppState.DevicesFrameFocusedDevice) ||
|
||||
@ -131,7 +136,7 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private void CircuitConnection_MessageReceived(object sender, CircuitEvent args)
|
||||
private async void CircuitConnection_MessageReceived(object? sender, CircuitEvent args)
|
||||
{
|
||||
switch (args.EventName)
|
||||
{
|
||||
@ -165,13 +170,15 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
var className = (string)args.Params[2];
|
||||
AppState.AddTerminalLine(terminalMessage);
|
||||
ToastService.ShowToast(toastMessage, classString: className);
|
||||
InvokeAsync(StateHasChanged);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
break;
|
||||
case CircuitEventName.ScriptResult:
|
||||
{
|
||||
var result = (ScriptResult)args.Params[0];
|
||||
AddScriptResult(result);
|
||||
if (args.Params[0] is ScriptResult result)
|
||||
{
|
||||
await AddScriptResult(result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -181,7 +188,7 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
|
||||
private void ClearSelectedCard()
|
||||
{
|
||||
AppState.DevicesFrameFocusedDevice = null;
|
||||
AppState.DevicesFrameFocusedDevice = string.Empty;
|
||||
AppState.DevicesFrameFocusedCardState = DeviceCardState.Normal;
|
||||
}
|
||||
|
||||
@ -238,8 +245,8 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
|
||||
var propInfo = _sortableProperties.Find(x => x.Name == _selectedSortProperty);
|
||||
|
||||
var valueA = propInfo.GetValue(a);
|
||||
var valueB = propInfo.GetValue(b);
|
||||
var valueA = propInfo?.GetValue(a);
|
||||
var valueB = propInfo?.GetValue(b);
|
||||
|
||||
return Comparer.Default.Compare(valueA, valueB) * direction;
|
||||
});
|
||||
@ -280,7 +287,7 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
{
|
||||
_allDevices.Clear();
|
||||
|
||||
var devices = DataService.GetDevicesForUser(Username)
|
||||
var devices = DataService.GetDevicesForUser(UserName)
|
||||
.OrderByDescending(x => x.IsOnline)
|
||||
.ToList();
|
||||
|
||||
@ -340,7 +347,7 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
private async Task WakeDevices()
|
||||
{
|
||||
var offlineDevices = DataService
|
||||
.GetDevicesForUser(Username)
|
||||
.GetDevicesForUser(UserName)
|
||||
.Where(x => !x.IsOnline);
|
||||
|
||||
if (_selectedGroupId == _deviceGroupNone)
|
||||
|
||||
@ -160,12 +160,25 @@ public partial class Terminal : AuthComponentBase, IDisposable
|
||||
AppState.InvokePropertyChanged(nameof(AppState.TerminalLines));
|
||||
}
|
||||
}
|
||||
private void DisplayCompletions(List<PwshCompletionResult> completionMatches)
|
||||
private async Task DisplayCompletions(List<PwshCompletionResult> completionMatches)
|
||||
{
|
||||
var deviceId = AppState.DevicesFrameSelectedDevices.FirstOrDefault();
|
||||
var device = DataService.GetDevice(deviceId);
|
||||
if (string.IsNullOrWhiteSpace(deviceId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AppState.AddTerminalLine($"Completions for {device?.DeviceName}", className: "font-weight-bold");
|
||||
var deviceResult = await DataService.GetDevice(deviceId);
|
||||
|
||||
if (!deviceResult.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(deviceResult.Reason, Enums.ToastType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
AppState.AddTerminalLine(
|
||||
$"Completions for {deviceResult.Value.DeviceName}",
|
||||
className: "font-weight-bold");
|
||||
|
||||
foreach (var match in completionMatches)
|
||||
{
|
||||
|
||||
@ -31,25 +31,25 @@ public partial class RunScript : AuthComponentBase
|
||||
|
||||
private bool _runOnNextConnect = true;
|
||||
|
||||
private SavedScript _selectedScript;
|
||||
private SavedScript? _selectedScript;
|
||||
|
||||
[Inject]
|
||||
private IDataService DataService { get; set; }
|
||||
private IDataService DataService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJsInterop JsInterop { get; set; }
|
||||
private IJsInterop JsInterop { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IToastService ToastService { get; set; }
|
||||
private IToastService ToastService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IAgentHubSessionCache ServiceSessionCache { get; init; }
|
||||
private IAgentHubSessionCache ServiceSessionCache { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ICircuitConnection CircuitConnection { get; set; }
|
||||
private ICircuitConnection CircuitConnection { get; init; } = null!;
|
||||
|
||||
[CascadingParameter]
|
||||
private ScriptsPage ParentPage { get; set; }
|
||||
private ScriptsPage ParentPage { get; init; } = null!;
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
@ -64,16 +64,20 @@ public partial class RunScript : AuthComponentBase
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
_deviceGroups = DataService.GetDeviceGroups(User.UserName);
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
_devices = DataService
|
||||
.GetDevicesForUser(User.UserName)
|
||||
.GetDevicesForUser(UserName)
|
||||
.OrderBy(x => x.DeviceName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private void DeviceGroupSelectedChanged(ChangeEventArgs args, DeviceGroup deviceGroup)
|
||||
{
|
||||
var isSelected = (bool)args.Value;
|
||||
if (args.Value is not bool isSelected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
_selectedDeviceGroups.Add(deviceGroup.ID);
|
||||
@ -86,7 +90,11 @@ public partial class RunScript : AuthComponentBase
|
||||
|
||||
private void DeviceSelectedChanged(ChangeEventArgs args, Device device)
|
||||
{
|
||||
var isSelected = (bool)args.Value;
|
||||
if (args.Value is not bool isSelected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
_selectedDevices.Add(device.ID);
|
||||
@ -113,7 +121,7 @@ public partial class RunScript : AuthComponentBase
|
||||
}
|
||||
|
||||
var deviceIdsFromDeviceGroups = _devices
|
||||
.Where(x => _selectedDeviceGroups.Contains(x.DeviceGroupID))
|
||||
.Where(x => _selectedDeviceGroups.Contains(x.DeviceGroupID!))
|
||||
.Select(x => x.ID);
|
||||
|
||||
var deviceIds = _selectedDevices
|
||||
@ -121,7 +129,7 @@ public partial class RunScript : AuthComponentBase
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
var filteredDevices = DataService.FilterDeviceIDsByUserPermission(deviceIds.ToArray(), User);
|
||||
var filteredDevices = DataService.FilterDeviceIdsByUserPermission(deviceIds.ToArray(), User);
|
||||
|
||||
var onlineDevices = ServiceSessionCache.FilterDevicesByOnlineStatus(filteredDevices, true);
|
||||
|
||||
@ -157,7 +165,11 @@ public partial class RunScript : AuthComponentBase
|
||||
{
|
||||
if (viewModel.Script is not null)
|
||||
{
|
||||
_selectedScript = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
var scriptResult = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
if (scriptResult.IsSuccess)
|
||||
{
|
||||
_selectedScript = scriptResult.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -17,24 +17,24 @@ namespace Remotely.Server.Components.Scripts;
|
||||
public partial class SavedScripts : AuthComponentBase
|
||||
{
|
||||
[CascadingParameter]
|
||||
private ScriptsPage ParentPage { get; set; }
|
||||
private ScriptsPage ParentPage { get; set; } = null!;
|
||||
|
||||
private SavedScript _selectedScript = new() { Name = "Test Script" };
|
||||
private string _alertMessage;
|
||||
private string _alertOptionsShowClass;
|
||||
private string _environmentVarsShowClass;
|
||||
private string _alertMessage = string.Empty;
|
||||
private string _alertOptionsShowClass = string.Empty;
|
||||
private string _environmentVarsShowClass = string.Empty;
|
||||
|
||||
[Inject]
|
||||
public IDataService DataService { get; set; }
|
||||
public IDataService DataService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
public IToastService ToastService { get; set; }
|
||||
public IToastService ToastService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
public IJsInterop JsInterop { get; set; }
|
||||
public IJsInterop JsInterop { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
public IModalService ModalService { get; set; }
|
||||
public IModalService ModalService { get; set; } = null!;
|
||||
|
||||
private bool CanModifyScript => _selectedScript.Id == Guid.Empty ||
|
||||
_selectedScript.CreatorId == User.Id || User.IsAdministrator;
|
||||
@ -104,18 +104,18 @@ public partial class SavedScripts : AuthComponentBase
|
||||
{
|
||||
if (viewModel.Script is not null)
|
||||
{
|
||||
_selectedScript = await DataService.GetSavedScript(User.Id, viewModel.Script.Id) ?? new()
|
||||
var result = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
Name = "Test Script"
|
||||
};
|
||||
_selectedScript = result.Value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
_selectedScript = new()
|
||||
{
|
||||
_selectedScript = new()
|
||||
{
|
||||
Name = "Test Script"
|
||||
};
|
||||
}
|
||||
Name = string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private void ToggleEnvironmentVarsShown()
|
||||
|
||||
@ -13,12 +13,12 @@
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<AlertBanner Message="@_alertMessage" OnClose="() => _alertMessage = null" />
|
||||
<AlertBanner Message="@_alertMessage" OnClose="() => _alertMessage = string.Empty" />
|
||||
</div>
|
||||
|
||||
<div class="mt-2 col-12">
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary align-middle mr-3" disabled="@(!CanModifyScript)">
|
||||
<button type="submit" class="btn btn-primary align-middle mr-3" disabled="@(!CanModifySchedule)">
|
||||
Save
|
||||
</button>
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
New
|
||||
</button>
|
||||
<button class="btn btn-danger mr-4" type="button"
|
||||
disabled="@(!CanDeleteScript)"
|
||||
disabled="@(!CanDeleteSchedule)"
|
||||
@onclick="DeleteSelectedSchedule">
|
||||
Delete
|
||||
</button>
|
||||
|
||||
@ -21,13 +21,13 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
|
||||
private readonly List<ScriptSchedule> _schedules = new();
|
||||
|
||||
private string _alertMessage;
|
||||
private string _alertMessage = string.Empty;
|
||||
|
||||
private DeviceGroup[] _deviceGroups = Array.Empty<DeviceGroup>();
|
||||
|
||||
private Device[] _devices = Array.Empty<Device>();
|
||||
|
||||
private SavedScript _selectedScript;
|
||||
private SavedScript? _selectedScript;
|
||||
|
||||
private ScriptSchedule _selectedSchedule = new()
|
||||
{
|
||||
@ -36,33 +36,37 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
};
|
||||
|
||||
[CascadingParameter]
|
||||
private ScriptsPage ParentPage { get; set; }
|
||||
private ScriptsPage ParentPage { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IDataService DataService { get; set; }
|
||||
private IDataService DataService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
|
||||
private IJsInterop JsInterop { get; set; }
|
||||
private IJsInterop JsInterop { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IToastService ToastService { get; set; }
|
||||
private IToastService ToastService { get; set; } = null!;
|
||||
|
||||
private bool CanModifyScript => string.IsNullOrWhiteSpace(_selectedSchedule.CreatorId) ||
|
||||
_selectedSchedule.CreatorId == User.Id ||
|
||||
User.IsAdministrator;
|
||||
private bool CanModifySchedule =>
|
||||
_selectedSchedule.CreatorId == User?.Id ||
|
||||
User?.IsAdministrator == true;
|
||||
|
||||
private bool CanDeleteScript => !string.IsNullOrWhiteSpace(_selectedSchedule.CreatorId) &&
|
||||
(_selectedSchedule.CreatorId == User.Id || User.IsAdministrator);
|
||||
private bool CanDeleteSchedule =>
|
||||
_selectedSchedule.CreatorId == User?.Id ||
|
||||
User?.IsAdministrator == true;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
_deviceGroups = DataService.GetDeviceGroups(User.UserName);
|
||||
_devices = DataService
|
||||
.GetDevicesForUser(User.UserName)
|
||||
.OrderBy(x => x.DeviceName)
|
||||
.ToArray();
|
||||
if (IsAuthenticated)
|
||||
{
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
_devices = DataService
|
||||
.GetDevicesForUser(UserName)
|
||||
.OrderBy(x => x.DeviceName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
await RefreshSchedules();
|
||||
}
|
||||
@ -84,7 +88,7 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
|
||||
private async Task DeleteSelectedSchedule()
|
||||
{
|
||||
if (User.Id != _selectedSchedule.CreatorId)
|
||||
if (User?.Id != _selectedSchedule.CreatorId)
|
||||
{
|
||||
ToastService.ShowToast("You can't delete other people's script schedules.", classString: "bg-warning");
|
||||
return;
|
||||
@ -104,7 +108,10 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
|
||||
private void DeviceGroupSelectedChanged(ChangeEventArgs args, DeviceGroup deviceGroup)
|
||||
{
|
||||
var isSelected = (bool)args.Value;
|
||||
if (args.Value is not bool isSelected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (isSelected)
|
||||
{
|
||||
_selectedDeviceGroups.Add(deviceGroup.ID);
|
||||
@ -117,7 +124,10 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
|
||||
private void DeviceSelectedChanged(ChangeEventArgs args, Device device)
|
||||
{
|
||||
var isSelected = (bool)args.Value;
|
||||
if (args.Value is not bool isSelected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (isSelected)
|
||||
{
|
||||
_selectedDevices.Add(device.ID);
|
||||
@ -141,7 +151,7 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanModifyScript)
|
||||
if (!CanModifySchedule)
|
||||
{
|
||||
ToastService.ShowToast("You can't modify other people's schedules.", classString: "bg-warning");
|
||||
return;
|
||||
@ -177,7 +187,10 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
private async Task RefreshSchedules()
|
||||
{
|
||||
_schedules.Clear();
|
||||
_schedules.AddRange(await DataService.GetScriptSchedules(User.OrganizationID));
|
||||
if (User is not null)
|
||||
{
|
||||
_schedules.AddRange(await DataService.GetScriptSchedules(User.OrganizationID));
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTableRowClass(ScriptSchedule schedule)
|
||||
@ -203,14 +216,23 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
{
|
||||
_selectedDeviceGroups.AddRange(schedule.DeviceGroups.Select(x => x.ID));
|
||||
}
|
||||
_selectedScript = await DataService.GetSavedScript(_selectedSchedule.SavedScriptId);
|
||||
|
||||
var result = await DataService.GetSavedScript(_selectedSchedule.SavedScriptId);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
_selectedScript = result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ScriptSelected(ScriptTreeNode viewModel)
|
||||
{
|
||||
if (viewModel.Script is not null)
|
||||
{
|
||||
_selectedScript = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
var result = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
_selectedScript = result.Value;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
@ -11,8 +11,8 @@ public class ScriptTreeNode
|
||||
{
|
||||
public string Id { get; } = Guid.NewGuid().ToString();
|
||||
public TreeItemType ItemType { get; set; }
|
||||
public string Name { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public ScriptTreeNode? ParentNode { get; set; }
|
||||
public List<ScriptTreeNode> ChildItems { get; } = new();
|
||||
public SavedScript Script { get; init; }
|
||||
public SavedScript? Script { get; init; }
|
||||
}
|
||||
|
||||
@ -135,6 +135,10 @@ public class AppDb : IdentityDbContext
|
||||
builder.Entity<Device>()
|
||||
.HasMany(x => x.ScriptSchedules)
|
||||
.WithMany(x => x.Devices);
|
||||
builder.Entity<Device>()
|
||||
.HasOne(x => x.DeviceGroup)
|
||||
.WithMany(x => x.Devices)
|
||||
.IsRequired(false);
|
||||
builder.Entity<Device>()
|
||||
.Property(x => x.MacAddresses)
|
||||
.HasConversion(
|
||||
@ -143,7 +147,9 @@ public class AppDb : IdentityDbContext
|
||||
valueComparer: _stringArrayComparer);
|
||||
|
||||
builder.Entity<DeviceGroup>()
|
||||
.HasMany(x => x.Devices);
|
||||
.HasMany(x => x.Devices)
|
||||
.WithOne(x => x.DeviceGroup)
|
||||
.IsRequired(false);
|
||||
builder.Entity<DeviceGroup>()
|
||||
.HasMany(x => x.ScriptSchedules)
|
||||
.WithMany(x => x.DeviceGroups);
|
||||
|
||||
@ -255,10 +255,15 @@ public class AgentHub : Hub
|
||||
return _circuitManager.InvokeOnConnection(senderConnectionId, CircuitEventName.PowerShellCompletions, completion, intent);
|
||||
}
|
||||
|
||||
public Task ScriptResult(string scriptResultId)
|
||||
public async Task ScriptResult(string scriptResultId)
|
||||
{
|
||||
var result = _dataService.GetScriptResult(scriptResultId);
|
||||
return _circuitManager.InvokeOnConnection(result.SenderConnectionID,
|
||||
var result = await _dataService.GetScriptResult(scriptResultId);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ = await _circuitManager.InvokeOnConnection($"{result.Value.SenderConnectionID}",
|
||||
CircuitEventName.ScriptResult,
|
||||
result);
|
||||
}
|
||||
|
||||
@ -27,8 +27,8 @@ namespace Remotely.Server.Hubs;
|
||||
|
||||
public interface ICircuitConnection
|
||||
{
|
||||
event EventHandler<CircuitEvent> MessageReceived;
|
||||
RemotelyUser User { get; }
|
||||
event EventHandler<CircuitEvent>? MessageReceived;
|
||||
RemotelyUser? User { get; }
|
||||
|
||||
Task DeleteRemoteLogs(string deviceId);
|
||||
|
||||
@ -85,6 +85,8 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
private readonly ILogger<CircuitConnection> _logger;
|
||||
private readonly IAgentHubSessionCache _agentSessionCache;
|
||||
private readonly IToastService _toastService;
|
||||
private RemotelyUser? _user;
|
||||
|
||||
public CircuitConnection(
|
||||
IAuthService authService,
|
||||
IDataService dataService,
|
||||
@ -112,10 +114,15 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler<CircuitEvent> MessageReceived;
|
||||
public event EventHandler<CircuitEvent>? MessageReceived;
|
||||
|
||||
public string ConnectionId { get; set; }
|
||||
public RemotelyUser User { get; internal set; }
|
||||
public string ConnectionId { get; } = Guid.NewGuid().ToString();
|
||||
|
||||
public RemotelyUser User
|
||||
{
|
||||
get => _user ?? throw new InvalidOperationException("User has not been resolved yet.");
|
||||
internal set => _user = value;
|
||||
}
|
||||
|
||||
|
||||
public Task DeleteRemoteLogs(string deviceId)
|
||||
@ -129,14 +136,14 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
|
||||
_logger.LogInformation("Delete logs command sent. Device: {deviceId}. User: {username}",
|
||||
deviceId,
|
||||
User.UserName);
|
||||
User?.UserName);
|
||||
|
||||
return _agentHubContext.Clients.Client(key).SendAsync("DeleteLogs");
|
||||
}
|
||||
|
||||
public Task ExecuteCommandOnAgent(ScriptingShell shell, string command, string[] deviceIDs)
|
||||
{
|
||||
deviceIDs = _dataService.FilterDeviceIDsByUserPermission(deviceIDs, User);
|
||||
deviceIDs = _dataService.FilterDeviceIdsByUserPermission(deviceIDs, User);
|
||||
var connections = GetActiveConnectionsForUserOrg(deviceIDs);
|
||||
|
||||
_logger.LogInformation("Command executed by {username}. Shell: {shell}. Command: {command}. Devices: {deviceIds}",
|
||||
@ -162,7 +169,13 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
|
||||
public Task GetPowerShellCompletions(string inputText, int currentIndex, CompletionIntent intent, bool? forward)
|
||||
{
|
||||
var (canAccess, key) = CanAccessDevice(_appState.DevicesFrameSelectedDevices.FirstOrDefault());
|
||||
var device = _appState.DevicesFrameSelectedDevices.FirstOrDefault();
|
||||
if (device is null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var (canAccess, key) = CanAccessDevice(device);
|
||||
if (!canAccess)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
@ -202,8 +215,13 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
{
|
||||
if (await _authService.IsAuthenticated())
|
||||
{
|
||||
User = await _authService.GetUser();
|
||||
ConnectionId = Guid.NewGuid().ToString();
|
||||
var userResult = await _authService.GetUser();
|
||||
if (!userResult.IsSuccess)
|
||||
{
|
||||
_toastService.ShowToast2("Authorization failure.", Enums.ToastType.Error);
|
||||
return;
|
||||
}
|
||||
_user = userResult.Value;
|
||||
_circuitManager.TryAddConnection(ConnectionId, this);
|
||||
}
|
||||
await base.OnCircuitOpenedAsync(circuit, cancellationToken);
|
||||
@ -211,7 +229,7 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
|
||||
public Task ReinstallAgents(string[] deviceIDs)
|
||||
{
|
||||
deviceIDs = _dataService.FilterDeviceIDsByUserPermission(deviceIDs, User);
|
||||
deviceIDs = _dataService.FilterDeviceIdsByUserPermission(deviceIDs, User);
|
||||
var connections = GetActiveConnectionsForUserOrg(deviceIDs);
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
@ -283,12 +301,20 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
|
||||
_remoteControlSessionCache.AddOrUpdate($"{sessionId}", session);
|
||||
|
||||
var organization = _dataService.GetOrganizationNameByUserName(User.UserName);
|
||||
var orgResult = await _dataService.GetOrganizationNameByUserName($"{User.UserName}");
|
||||
|
||||
if (!orgResult.IsSuccess)
|
||||
{
|
||||
_toastService.ShowToast2(orgResult.Reason, Enums.ToastType.Warning);
|
||||
return Result.Fail<RemoteControlSessionEx>(orgResult.Reason);
|
||||
}
|
||||
|
||||
var organization = _dataService.GetOrganizationNameByUserName($"{User.UserName}");
|
||||
await _agentHubContext.Clients.Client(serviceConnectionId).SendAsync("RemoteControl",
|
||||
sessionId,
|
||||
accessKey,
|
||||
ConnectionId,
|
||||
User.UserOptions.DisplayName,
|
||||
User.UserOptions?.DisplayName,
|
||||
organization,
|
||||
User.OrganizationID);
|
||||
|
||||
@ -297,22 +323,31 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
|
||||
public Task RemoveDevices(string[] deviceIDs)
|
||||
{
|
||||
var filterDevices = _dataService.FilterDeviceIDsByUserPermission(deviceIDs, User);
|
||||
_dataService.RemoveDevices(filterDevices);
|
||||
if (User is not null)
|
||||
{
|
||||
var filterDevices = _dataService.FilterDeviceIdsByUserPermission(deviceIDs, User);
|
||||
_dataService.RemoveDevices(filterDevices);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task RunScript(IEnumerable<string> deviceIds, Guid savedScriptId, int scriptRunId, ScriptInputType scriptInputType, bool runAsHostedService)
|
||||
public async Task RunScript(
|
||||
IEnumerable<string> deviceIds,
|
||||
Guid savedScriptId,
|
||||
int scriptRunId,
|
||||
ScriptInputType scriptInputType,
|
||||
bool runAsHostedService)
|
||||
{
|
||||
string username;
|
||||
var username = string.Empty;
|
||||
if (runAsHostedService)
|
||||
{
|
||||
username = "Remotely Server";
|
||||
}
|
||||
else
|
||||
else if (User is not null)
|
||||
{
|
||||
username = User.UserName;
|
||||
deviceIds = _dataService.FilterDeviceIDsByUserPermission(deviceIds.ToArray(), User);
|
||||
deviceIds = _dataService.FilterDeviceIdsByUserPermission(deviceIds.ToArray(), User);
|
||||
}
|
||||
|
||||
var authToken = _expiringTokenService.GetToken(Time.Now.AddMinutes(AppConstants.ScriptRunExpirationMinutes));
|
||||
@ -326,32 +361,37 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
|
||||
}
|
||||
|
||||
public Task SendChat(string message, string deviceId)
|
||||
public async Task SendChat(string message, string deviceId)
|
||||
{
|
||||
if (!_dataService.DoesUserHaveAccessToDevice(deviceId, User))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_agentSessionCache.TryGetByDeviceId(deviceId, out var device) ||
|
||||
!_agentSessionCache.TryGetConnectionId(deviceId, out var connectionId))
|
||||
{
|
||||
_toastService.ShowToast("Device not found.");
|
||||
return Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
if (device.OrganizationID != User.OrganizationID)
|
||||
{
|
||||
_toastService.ShowToast("Unauthorized.");
|
||||
return Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
var organizationName = _dataService.GetOrganizationNameByUserName(User.UserName);
|
||||
var orgResult = await _dataService.GetOrganizationNameByUserName($"{User.UserName}");
|
||||
if (!orgResult.IsSuccess)
|
||||
{
|
||||
_toastService.ShowToast2("Organization not found.", Enums.ToastType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
return _agentHubContext.Clients.Client(connectionId).SendAsync("Chat",
|
||||
User.UserOptions.DisplayName ?? User.UserName,
|
||||
await _agentHubContext.Clients.Client(connectionId).SendAsync("Chat",
|
||||
User.UserOptions?.DisplayName ?? User.UserName,
|
||||
message,
|
||||
organizationName,
|
||||
orgResult.Value,
|
||||
User.OrganizationID,
|
||||
false,
|
||||
ConnectionId);
|
||||
@ -397,16 +437,15 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
await _agentHubContext.Clients.Client(connectionId).SendAsync("TriggerHeartbeat");
|
||||
}
|
||||
|
||||
public Task UninstallAgents(string[] deviceIDs)
|
||||
public async Task UninstallAgents(string[] deviceIDs)
|
||||
{
|
||||
deviceIDs = _dataService.FilterDeviceIDsByUserPermission(deviceIDs, User);
|
||||
deviceIDs = _dataService.FilterDeviceIdsByUserPermission(deviceIDs, User);
|
||||
var connections = GetActiveConnectionsForUserOrg(deviceIDs);
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
_agentHubContext.Clients.Client(connection).SendAsync("UninstallAgent");
|
||||
await _agentHubContext.Clients.Client(connection).SendAsync("UninstallAgent");
|
||||
}
|
||||
_dataService.RemoveDevices(deviceIDs);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task UpdateTags(string deviceID, string tags)
|
||||
@ -436,7 +475,7 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
User.UserName,
|
||||
string.Join(", ", fileIDs));
|
||||
|
||||
deviceIDs = _dataService.FilterDeviceIDsByUserPermission(deviceIDs, User);
|
||||
deviceIDs = _dataService.FilterDeviceIdsByUserPermission(deviceIDs, User);
|
||||
var connections = GetActiveConnectionsForUserOrg(deviceIDs);
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
@ -477,7 +516,7 @@ public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
try
|
||||
{
|
||||
var deviceIds = devices.Select(x => x.ID).ToArray();
|
||||
var filteredIds = _dataService.FilterDeviceIDsByUserPermission(deviceIds, User);
|
||||
var filteredIds = _dataService.FilterDeviceIdsByUserPermission(deviceIds, User);
|
||||
var filteredDevices = devices.Where(x => filteredIds.Contains(x.ID)).ToArray();
|
||||
|
||||
var availableDevices = _agentSessionCache
|
||||
|
||||
@ -93,7 +93,7 @@ else
|
||||
var secret = RandomGenerator.GenerateString(36);
|
||||
var secretHash = new PasswordHasher<string>().HashPassword(string.Empty, secret);
|
||||
|
||||
var result = await DataService.CreateApiToken(Username, _createKeyName, secretHash);
|
||||
var result = await DataService.CreateApiToken(UserName, _createKeyName, secretHash);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(result.Reason, ToastType.Error);
|
||||
@ -112,7 +112,7 @@ else
|
||||
return;
|
||||
}
|
||||
|
||||
var deleteResult = await DataService.DeleteApiToken(Username, keyId);
|
||||
var deleteResult = await DataService.DeleteApiToken(UserName, keyId);
|
||||
if (!deleteResult.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(deleteResult.Reason, ToastType.Error);
|
||||
@ -137,7 +137,7 @@ else
|
||||
var newName = await JsInterop.Prompt("New key name");
|
||||
if (!string.IsNullOrWhiteSpace(newName))
|
||||
{
|
||||
await DataService.RenameApiToken(Username, keyId, newName);
|
||||
await DataService.RenameApiToken(UserName, keyId, newName);
|
||||
RefreshData();
|
||||
_alertMessage = "Key renamed.";
|
||||
}
|
||||
|
||||
@ -129,14 +129,26 @@
|
||||
|
||||
private async Task LoadBrandingInfo()
|
||||
{
|
||||
var organization = await DataService.GetOrganizationByUserName(User.UserName);
|
||||
var orgResult = await DataService.GetOrganizationByUserName($"{UserName}");
|
||||
|
||||
var brandingInfo = await DataService.GetBrandingInfo(organization.ID);
|
||||
if (!orgResult.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(orgResult.Reason, ToastType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var brandingResult= await DataService.GetBrandingInfo(orgResult.Value.ID);
|
||||
|
||||
if (!brandingResult.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(brandingResult.Reason, ToastType.Warning);
|
||||
return;
|
||||
}
|
||||
var brandingInfo = brandingResult.Value;
|
||||
|
||||
_inputModel.ProductName = brandingInfo.Product;
|
||||
|
||||
if (brandingInfo?.Icon?.Any() == true)
|
||||
if (brandingResult.Value?.Icon?.Any() == true)
|
||||
{
|
||||
_base64Icon = Convert.ToBase64String(brandingInfo.Icon);
|
||||
}
|
||||
|
||||
@ -29,11 +29,11 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (Device is null)
|
||||
else if (_device is null)
|
||||
{
|
||||
<h3>Device not found.</h3>
|
||||
}
|
||||
else if (!DataService.DoesUserHaveAccessToDevice(Device.ID, User))
|
||||
else if (!DataService.DoesUserHaveAccessToDevice(_device.ID, User))
|
||||
{
|
||||
<h3>Unauthorized.</h3>
|
||||
}
|
||||
@ -59,7 +59,7 @@ else
|
||||
Device Details
|
||||
</h3>
|
||||
|
||||
<EditForm Model="Device" OnValidSubmit="HandleValidSubmit" @onkeydown="EditFormKeyDown">
|
||||
<EditForm Model="_device" OnValidSubmit="HandleValidSubmit" @onkeydown="EditFormKeyDown">
|
||||
<DataAnnotationsValidator />
|
||||
<ValidationSummary />
|
||||
|
||||
@ -72,31 +72,31 @@ else
|
||||
<div class="form-group row">
|
||||
<label for="device-name" class="col-sm-2 col-form-label">Device:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="device-name" readonly value="@Device.DeviceName" />
|
||||
<input type="text" class="form-control" name="device-name" readonly value="@_device.DeviceName" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="device-id" class="col-sm-2 col-form-label">Device ID:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="device-id" readonly value="@Device.ID" />
|
||||
<input type="text" class="form-control" name="device-id" readonly value="@_device.ID" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="agent-version" class="col-sm-2 col-form-label">Agent Version:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-version" readonly value="@Device.AgentVersion" />
|
||||
<input type="text" class="form-control" name="agent-version" readonly value="@_device.AgentVersion" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="agent-platform" class="col-sm-2 col-form-label">Platform:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-platform" readonly value="@Device.Platform" />
|
||||
<input type="text" class="form-control" name="agent-platform" readonly value="@_device.Platform" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="agent-os-description" class="col-sm-2 col-form-label">Platform:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-os-description" readonly value="@Device.OSDescription" />
|
||||
<input type="text" class="form-control" name="agent-os-description" readonly value="@_device.OSDescription" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -107,7 +107,7 @@ else
|
||||
</button>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-storage-percent" readonly value="@(MathHelper.GetFormattedPercent(Device.UsedStoragePercent))" />
|
||||
<input type="text" class="form-control" name="agent-storage-percent" readonly value="@(MathHelper.GetFormattedPercent(_device.UsedStoragePercent))" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -115,7 +115,7 @@ else
|
||||
Total Storage:
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-storage-total" readonly value="@(Device.TotalStorage)" />
|
||||
<input type="text" class="form-control" name="agent-storage-total" readonly value="@(_device.TotalStorage)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -123,7 +123,7 @@ else
|
||||
Memory:
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-memory-percent" readonly value="@(MathHelper.GetFormattedPercent(Device.UsedMemoryPercent))" />
|
||||
<input type="text" class="form-control" name="agent-memory-percent" readonly value="@(MathHelper.GetFormattedPercent(_device.UsedMemoryPercent))" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -131,7 +131,7 @@ else
|
||||
Total Memory:
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-memory-total" readonly value="@(Device.TotalMemory)" />
|
||||
<input type="text" class="form-control" name="agent-memory-total" readonly value="@(_device.TotalMemory)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -139,7 +139,7 @@ else
|
||||
Public IP:
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="agent-memory-total" readonly value="@(Device.PublicIP)" />
|
||||
<input type="text" class="form-control" name="agent-memory-total" readonly value="@(_device.PublicIP)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -152,42 +152,42 @@ else
|
||||
class="form-control"
|
||||
name="agent-memory-total"
|
||||
readonly
|
||||
value="@(string.Join(", ", Device.MacAddresses ?? Array.Empty<string>()))" />
|
||||
value="@(string.Join(", ", _device.MacAddresses ?? Array.Empty<string>()))" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="device-alias" class="col-sm-2 col-form-label">Device Alias:</label>
|
||||
<div class="col-sm-10">
|
||||
<InputText class="form-control" @bind-Value="@Device.Alias" />
|
||||
<ValidationMessage For="() => Device.Alias" />
|
||||
<InputText class="form-control" @bind-Value="@_device.Alias" />
|
||||
<ValidationMessage For="() => _device.Alias" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="device-groups" class="col-sm-2 col-form-label">Device Group:</label>
|
||||
<div class="col-sm-10">
|
||||
<InputSelect @bind-Value="Device.DeviceGroupID" class="form-control">
|
||||
<InputSelect @bind-Value="_device.DeviceGroupID" class="form-control">
|
||||
<option value="">None</option>
|
||||
|
||||
@foreach (var group in DataService.GetDeviceGroups(Username))
|
||||
@foreach (var group in DataService.GetDeviceGroups(UserName))
|
||||
{
|
||||
<option @key="group.ID" value="@group.ID">@group.Name</option>
|
||||
}
|
||||
</InputSelect>
|
||||
<ValidationMessage For="() => Device.DeviceGroupID" />
|
||||
<ValidationMessage For="() => _device.DeviceGroupID" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="tags" class="col-sm-2 col-form-label">Tags:</label>
|
||||
<div class="col-sm-10">
|
||||
<InputText @bind-Value="Device.Tags" class="form-control" />
|
||||
<ValidationMessage For="() => Device.Tags" />
|
||||
<InputText @bind-Value="_device.Tags" class="form-control" />
|
||||
<ValidationMessage For="() => _device.Tags" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="notes" class="col-sm-2 col-form-label">Notes:</label>
|
||||
<div class="col-sm-10">
|
||||
<InputTextArea @bind-Value="Device.Notes" style="width:100%; height: 10em;"></InputTextArea>
|
||||
<ValidationMessage For="() => Device.Notes" />
|
||||
<InputTextArea @bind-Value="_device.Notes" style="width:100%; height: 10em;"></InputTextArea>
|
||||
<ValidationMessage For="() => _device.Notes" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
@ -199,7 +199,7 @@ else
|
||||
|
||||
<TabContent Name="remote-logs">
|
||||
<div class="py-3">
|
||||
@if (!Device.IsOnline)
|
||||
@if (!_device.IsOnline)
|
||||
{
|
||||
<h5 class="text-center mt-5">Device must be online to retrieve logs.</h5>
|
||||
}
|
||||
|
||||
@ -20,33 +20,34 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
private readonly ConcurrentQueue<string> _logLines = new();
|
||||
private readonly ConcurrentQueue<ScriptResult> _scriptResults = new();
|
||||
|
||||
private string _alertMessage;
|
||||
private string _inputDeviceId;
|
||||
private string? _alertMessage;
|
||||
private Device? _device;
|
||||
private string? _inputDeviceId;
|
||||
|
||||
[Parameter]
|
||||
public string ActiveTab { get; set; }
|
||||
public string ActiveTab { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string DeviceId { get; set; }
|
||||
[Inject]
|
||||
private ICircuitConnection CircuitConnection { get; set; }
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
[Inject]
|
||||
private IDataService DataService { get; set; }
|
||||
|
||||
private Device Device { get; set; }
|
||||
private ICircuitConnection CircuitConnection { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJsInterop JsInterop { get; set; }
|
||||
private IDataService DataService { get; set; } = null!;
|
||||
|
||||
|
||||
[Inject]
|
||||
private IModalService ModalService { get; set; }
|
||||
private IJsInterop JsInterop { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private NavigationManager NavManager { get; set; }
|
||||
private IModalService ModalService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IToastService ToastService { get; set; }
|
||||
private NavigationManager NavManager { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IToastService ToastService { get; set; } = null!;
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@ -55,13 +56,21 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(DeviceId))
|
||||
{
|
||||
Device = DataService.GetDevice(DeviceId);
|
||||
var deviceResult = await DataService.GetDevice(DeviceId);
|
||||
if (deviceResult.IsSuccess)
|
||||
{
|
||||
_device = deviceResult.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToastService.ShowToast2(deviceResult.Reason, Enums.ToastType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
CircuitConnection.MessageReceived += CircuitConnection_MessageReceived;
|
||||
}
|
||||
|
||||
private void CircuitConnection_MessageReceived(object sender, Models.CircuitEvent e)
|
||||
private void CircuitConnection_MessageReceived(object? sender, Models.CircuitEvent e)
|
||||
{
|
||||
if (e.EventName == Models.CircuitEventName.RemoteLogsReceived)
|
||||
{
|
||||
@ -73,10 +82,15 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
|
||||
private async Task DeleteLogs()
|
||||
{
|
||||
if (_device is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await JsInterop.Confirm("Are you sure you want to delete the remote logs?");
|
||||
if (result)
|
||||
{
|
||||
await CircuitConnection.DeleteRemoteLogs(Device.ID);
|
||||
await CircuitConnection.DeleteRemoteLogs(_device.ID);
|
||||
ToastService.ShowToast("Delete command sent.");
|
||||
}
|
||||
}
|
||||
@ -96,22 +110,32 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
|
||||
private void GetRemoteLogs()
|
||||
{
|
||||
if (_device is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logLines.Clear();
|
||||
|
||||
if (Device.IsOnline)
|
||||
if (_device.IsOnline)
|
||||
{
|
||||
CircuitConnection.GetRemoteLogs(Device.ID);
|
||||
CircuitConnection.GetRemoteLogs(_device.ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetScriptHistory()
|
||||
{
|
||||
if (_device is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_scriptResults.Clear();
|
||||
|
||||
if (User.IsAdministrator)
|
||||
{
|
||||
var results = DataService
|
||||
.GetAllScriptResults(User.OrganizationID, Device.ID)
|
||||
.GetAllScriptResults(User.OrganizationID, _device.ID)
|
||||
.OrderByDescending(x => x.TimeStamp);
|
||||
|
||||
foreach (var result in results)
|
||||
@ -122,7 +146,7 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
else
|
||||
{
|
||||
var results = DataService
|
||||
.GetAllCommandResultsForUser(User.OrganizationID, User.UserName, Device.ID)
|
||||
.GetAllCommandResultsForUser(User.OrganizationID, UserName, _device.ID)
|
||||
.OrderByDescending(x => x.TimeStamp);
|
||||
|
||||
foreach (var result in results)
|
||||
@ -154,11 +178,17 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
|
||||
private Task HandleValidSubmit()
|
||||
{
|
||||
DataService.UpdateDevice(Device.ID,
|
||||
Device.Tags,
|
||||
Device.Alias,
|
||||
Device.DeviceGroupID,
|
||||
Device.Notes);
|
||||
if (_device is null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
DataService.UpdateDevice(
|
||||
_device.ID,
|
||||
_device.Tags,
|
||||
_device.Alias,
|
||||
_device.DeviceGroupID,
|
||||
_device.Notes);
|
||||
|
||||
_alertMessage = "Device details saved.";
|
||||
ToastService.ShowToast("Device details saved.");
|
||||
@ -173,20 +203,25 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
|
||||
private void ShowAllDisks()
|
||||
{
|
||||
var disksString = JsonSerializer.Serialize(Device.Drives, JsonSerializerHelper.IndentedOptions);
|
||||
if (_device is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var disksString = JsonSerializer.Serialize(_device.Drives, JsonSerializerHelper.IndentedOptions);
|
||||
void modalBody(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.AddMarkupContent(0, $"<div style='white-space: pre'>{disksString}</div>");
|
||||
}
|
||||
ModalService.ShowModal($"All Disks for {Device.DeviceName}", modalBody);
|
||||
ModalService.ShowModal($"All Disks for {_device.DeviceName}", modalBody);
|
||||
}
|
||||
|
||||
private void ShowFullScriptOutput(ScriptResult result)
|
||||
{
|
||||
void outputModal(RenderTreeBuilder builder)
|
||||
{
|
||||
var output = string.Join("\r\n", result.StandardOutput);
|
||||
var error = string.Join("\r\n", result.ErrorOutput);
|
||||
var output = string.Join("\r\n", $"{result.StandardOutput}");
|
||||
var error = string.Join("\r\n", $"{result.ErrorOutput}");
|
||||
var textareaStyle = "width: 100%; height: 200px; white-space: pre;";
|
||||
|
||||
builder.AddMarkupContent(0, "<h5>Input</h5>");
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
@using Microsoft.AspNetCore.Hosting
|
||||
@using Microsoft.Extensions.Logging
|
||||
|
||||
@inject AuthenticationStateProvider AuthProvider
|
||||
@inject IAuthService Auth
|
||||
@inject IDataService DataService
|
||||
@inject UserManager<RemotelyUser> UserManager
|
||||
@inject IWebHostEnvironment HostEnv
|
||||
@ -174,24 +174,30 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string _organizationId;
|
||||
private string? _organizationId;
|
||||
private bool _isAuthenticated;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
var authState = await AuthProvider.GetAuthenticationStateAsync();
|
||||
_isAuthenticated = authState.User.Identity.IsAuthenticated;
|
||||
_isAuthenticated = await Auth.IsAuthenticated();
|
||||
|
||||
if (_isAuthenticated)
|
||||
{
|
||||
var currentUser = await DataService.GetUserByName(authState.User.Identity.Name);
|
||||
_organizationId = currentUser.OrganizationID;
|
||||
var userResult = await Auth.GetUser();
|
||||
if (userResult.IsSuccess)
|
||||
{
|
||||
_organizationId = userResult.Value.OrganizationID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_organizationId = (await DataService.GetDefaultOrganization())?.ID;
|
||||
var orgResult = await DataService.GetDefaultOrganization();
|
||||
if (orgResult.IsSuccess)
|
||||
{
|
||||
_organizationId = orgResult.Value.ID;
|
||||
}
|
||||
}
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,7 @@ public class GetSupportModel : PageModel
|
||||
}
|
||||
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
public string? StatusMessage { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public InputModel Input { get; set; }
|
||||
@ -35,8 +35,15 @@ public class GetSupportModel : PageModel
|
||||
return Page();
|
||||
}
|
||||
|
||||
var orgID = _dataService.GetDevice(deviceId)?.OrganizationID;
|
||||
var deviceResult = await _dataService.GetDevice(deviceId);
|
||||
if (!deviceResult.IsSuccess)
|
||||
{
|
||||
StatusMessage = "Device not found.";
|
||||
return Page();
|
||||
}
|
||||
|
||||
var orgId = deviceResult.Value.OrganizationID;
|
||||
|
||||
var alertParts = new string[]
|
||||
{
|
||||
$"{Input.Name} is requesting support.",
|
||||
@ -47,12 +54,16 @@ public class GetSupportModel : PageModel
|
||||
};
|
||||
|
||||
var alertMessage = string.Join(" ", alertParts);
|
||||
await _dataService.AddAlert(deviceId, orgID, alertMessage);
|
||||
await _dataService.AddAlert(deviceId, orgId, alertMessage);
|
||||
|
||||
var orgUsers = await _dataService.GetAllUsersInOrganization(orgID);
|
||||
var orgUsers = await _dataService.GetAllUsersInOrganization(orgId);
|
||||
var emailMessage = string.Join("<br />", alertParts);
|
||||
foreach (var user in orgUsers)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(user.Email))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
await _emailSender.SendEmailAsync(user.Email, "Support Request", emailMessage);
|
||||
}
|
||||
|
||||
@ -65,9 +76,9 @@ public class GetSupportModel : PageModel
|
||||
{
|
||||
[StringLength(150)]
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public bool ChatResponseOk { get; set; }
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,12 @@
|
||||
You've successfully joined the organization!
|
||||
</p>
|
||||
}
|
||||
|
||||
else if (string.IsNullOrWhiteSpace(Model.Input.InviteID))
|
||||
{
|
||||
<div>
|
||||
<strong class="text-danger">Invitation ID is missing from the request.</strong>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post">
|
||||
|
||||
@ -2,22 +2,25 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Remotely.Server.Services;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Server.Pages;
|
||||
|
||||
[Authorize]
|
||||
public class InviteModel : PageModel
|
||||
{
|
||||
private readonly IDataService _dataService;
|
||||
|
||||
public InviteModel(IDataService dataService)
|
||||
{
|
||||
DataService = dataService;
|
||||
_dataService = dataService;
|
||||
}
|
||||
private IDataService DataService { get; }
|
||||
|
||||
public bool Success { get; set; }
|
||||
|
||||
public class InputModel
|
||||
{
|
||||
public string InviteID { get; set; }
|
||||
public string? InviteID { get; set; }
|
||||
}
|
||||
|
||||
[BindProperty]
|
||||
@ -28,12 +31,13 @@ public class InviteModel : PageModel
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
ModelState.AddModelError("MissingID", "No invititation ID is specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
Input.InviteID = id;
|
||||
}
|
||||
|
||||
public IActionResult OnPost()
|
||||
public async Task<IActionResult> OnPost()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Input?.InviteID))
|
||||
{
|
||||
@ -42,8 +46,8 @@ public class InviteModel : PageModel
|
||||
return Page();
|
||||
}
|
||||
|
||||
var result = DataService.JoinViaInvitation(User.Identity.Name, Input.InviteID);
|
||||
if (result == false)
|
||||
var result = await _dataService.JoinViaInvitation($"{User.Identity?.Name}", Input.InviteID);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
Success = false;
|
||||
ModelState.AddModelError("InviteIDNotFound", "The invitation ID wasn't found or is for another account.");
|
||||
|
||||
@ -120,7 +120,7 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
DataService.DeleteInvite(User.OrganizationID, invite.ID);
|
||||
await DataService.DeleteInvite(User.OrganizationID, invite.ID);
|
||||
_invites.RemoveAll(x => x.ID == invite.ID);
|
||||
ToastService.ShowToast("Invitation deleted.");
|
||||
}
|
||||
@ -143,7 +143,7 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
DataService.DeleteDeviceGroup(User.OrganizationID, _selectedDeviceGroupId);
|
||||
await DataService.DeleteDeviceGroup(User.OrganizationID, _selectedDeviceGroupId);
|
||||
_deviceGroups.RemoveAll(x => x.ID == _selectedDeviceGroupId);
|
||||
_selectedDeviceGroupId = string.Empty;
|
||||
}
|
||||
@ -237,14 +237,20 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task RefreshData()
|
||||
{
|
||||
_organization = await DataService.GetOrganizationByUserName(Username);
|
||||
var orgResult = await DataService.GetOrganizationByUserName(UserName);
|
||||
if (!orgResult.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(orgResult.Reason, Enums.ToastType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
_organization = orgResult.Value;
|
||||
_orgUsers.Clear();
|
||||
_invites.Clear();
|
||||
_deviceGroups.Clear();
|
||||
|
||||
_invites.AddRange(DataService.GetAllInviteLinks(User.OrganizationID).OrderBy(x => x.InvitedUser));
|
||||
_deviceGroups.AddRange(DataService.GetDeviceGroups(Username).OrderBy(x => x.Name));
|
||||
_deviceGroups.AddRange(DataService.GetDeviceGroups(UserName).OrderBy(x => x.Name));
|
||||
var orgUsers = await DataService.GetAllUsersInOrganization(User.OrganizationID);
|
||||
_orgUsers.AddRange(orgUsers.OrderBy(x => x.UserName));
|
||||
}
|
||||
@ -277,9 +283,16 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
if (!DataService.DoesUserExist(_inviteEmail))
|
||||
{
|
||||
var result = await DataService.CreateUser(_inviteEmail, _inviteAsAdmin, User.OrganizationID);
|
||||
if (result)
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
var user = await DataService.GetUserByName(_inviteEmail);
|
||||
var userResult = await DataService.GetUserByName(_inviteEmail);
|
||||
if (!userResult.IsSuccess)
|
||||
{
|
||||
ToastService.ShowToast2(userResult.Reason, Enums.ToastType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var user = userResult.Value;
|
||||
|
||||
await UserManager.ConfirmEmailAsync(user, await UserManager.GenerateEmailConfirmationTokenAsync(user));
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
@using Microsoft.AspNetCore.Hosting
|
||||
@using Microsoft.AspNetCore.Mvc.ViewEngines
|
||||
@using Microsoft.EntityFrameworkCore;
|
||||
@using Remotely.Server.Services
|
||||
@using Remotely.Shared.Models
|
||||
@inject IApplicationConfig AppConfig
|
||||
@ -9,14 +10,18 @@
|
||||
|
||||
@{
|
||||
var organizationName = "Remotely";
|
||||
var user = DataService.GetUserByNameWithOrg(User?.Identity?.Name);
|
||||
var userResult = await DataService.GetUserByName(
|
||||
$"{User?.Identity?.Name}",
|
||||
query => query.Include(x => x.Organization));
|
||||
|
||||
var user = userResult.Value;
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
var defaultOrg = await DataService.GetDefaultOrganization();
|
||||
if (!string.IsNullOrWhiteSpace(defaultOrg?.OrganizationName))
|
||||
var orgResult = await DataService.GetDefaultOrganization();
|
||||
if (orgResult.IsSuccess)
|
||||
{
|
||||
organizationName = defaultOrg.OrganizationName;
|
||||
organizationName = orgResult.Value.OrganizationName;
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(user.Organization?.OrganizationName))
|
||||
@ -43,7 +48,7 @@
|
||||
@if (user is RemotelyUser)
|
||||
{
|
||||
|
||||
switch (user.UserOptions.Theme)
|
||||
switch (user.UserOptions?.Theme ?? default)
|
||||
{
|
||||
case Remotely.Shared.Enums.Theme.Light:
|
||||
<link rel="stylesheet" href="~/css/Themes/yeti.min.css" />
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
|
||||
@{
|
||||
Layout = null;
|
||||
var user = DataService.GetUserByNameWithOrg(User?.Identity?.Name);
|
||||
var userResult = await DataService.GetUserByName($"{User?.Identity?.Name}");
|
||||
var user = userResult.Value;
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
@ -26,7 +27,7 @@
|
||||
@if (user is RemotelyUser)
|
||||
{
|
||||
|
||||
switch (user.UserOptions.Theme)
|
||||
switch (user.UserOptions?.Theme ?? default)
|
||||
{
|
||||
case Remotely.Shared.Enums.Theme.Light:
|
||||
<link rel="stylesheet" href="~/css/Themes/yeti.min.css" />
|
||||
|
||||
@ -4,6 +4,7 @@ using Remotely.Server.Models;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -13,9 +14,9 @@ public interface ICircuitManager
|
||||
{
|
||||
ICollection<ICircuitConnection> Connections { get; }
|
||||
bool TryAddConnection(string id, ICircuitConnection connection);
|
||||
bool TryRemoveConnection(string id, out ICircuitConnection connection);
|
||||
Task<bool> InvokeOnConnection(string browserConnectionId, CircuitEventName eventName, params object[] args);
|
||||
bool TryGetConnection(string browserConnectionId, out ICircuitConnection connection);
|
||||
bool TryRemoveConnection(string id, [NotNullWhen(true)] out ICircuitConnection? connection);
|
||||
Task<bool> InvokeOnConnection(string id, CircuitEventName eventName, params object[] args);
|
||||
bool TryGetConnection(string id, [NotNullWhen(true)] out ICircuitConnection? connection);
|
||||
}
|
||||
public class CircuitManager : ICircuitManager
|
||||
{
|
||||
@ -52,12 +53,12 @@ public class CircuitManager : ICircuitManager
|
||||
return _connections.TryAdd(id, connection);
|
||||
}
|
||||
|
||||
public bool TryGetConnection(string connectionId, out ICircuitConnection connection)
|
||||
public bool TryGetConnection(string id, [NotNullWhen(true)] out ICircuitConnection? connection)
|
||||
{
|
||||
return _connections.TryGetValue(connectionId, out connection);
|
||||
return _connections.TryGetValue(id, out connection);
|
||||
}
|
||||
|
||||
public bool TryRemoveConnection(string id, out ICircuitConnection connection)
|
||||
public bool TryRemoveConnection(string id, [NotNullWhen(true)] out ICircuitConnection? connection)
|
||||
{
|
||||
return _connections.TryRemove(id, out connection);
|
||||
}
|
||||
|
||||
@ -89,9 +89,13 @@ public class ClientAppState : ViewModelBase, IClientAppState
|
||||
{
|
||||
if (await _authService.IsAuthenticated())
|
||||
{
|
||||
var user = await _authService.GetUser();
|
||||
return user?.UserOptions?.Theme ?? _appConfig.Theme;
|
||||
var userResult = await _authService.GetUser();
|
||||
if (userResult.IsSuccess)
|
||||
{
|
||||
return userResult.Value.UserOptions?.Theme ?? _appConfig.Theme;
|
||||
}
|
||||
}
|
||||
|
||||
return _appConfig.Theme;
|
||||
}
|
||||
|
||||
|
||||
@ -214,7 +214,7 @@ public interface IDataService
|
||||
|
||||
Task<Result<Device>> UpdateDevice(DeviceSetupOptions deviceOptions, string organizationId);
|
||||
|
||||
Task UpdateDevice(string deviceId, string tag, string alias, string deviceGroupId, string notes);
|
||||
Task UpdateDevice(string deviceId, string? tag, string? alias, string? deviceGroupId, string? notes);
|
||||
|
||||
Task<Result> UpdateOrganizationName(string orgId, string newName);
|
||||
|
||||
@ -1448,6 +1448,11 @@ public class DataService : IDataService
|
||||
|
||||
public async Task<Result<Organization>> GetOrganizationByUserName(string userName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
return Result.Fail<Organization>("User name is required.");
|
||||
}
|
||||
|
||||
using var dbContext = _appDbFactory.GetContext();
|
||||
|
||||
var user = await dbContext
|
||||
@ -1493,6 +1498,11 @@ public class DataService : IDataService
|
||||
|
||||
public async Task<Result<string>> GetOrganizationNameByUserName(string userName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
return Result.Fail<string>("Username cannot be empty.");
|
||||
}
|
||||
|
||||
using var dbContext = _appDbFactory.GetContext();
|
||||
|
||||
var user = await dbContext.Users
|
||||
@ -1737,6 +1747,15 @@ public class DataService : IDataService
|
||||
|
||||
public async Task<Result> JoinViaInvitation(string userName, string inviteId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
return Result.Fail("Username cannot be empty.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(inviteId))
|
||||
{
|
||||
return Result.Fail("Invite ID cannot be empty.");
|
||||
}
|
||||
|
||||
using var dbContext = _appDbFactory.GetContext();
|
||||
|
||||
var invite = await dbContext.InviteLinks.FirstOrDefaultAsync(x =>
|
||||
@ -2014,7 +2033,7 @@ public class DataService : IDataService
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateDevice(string deviceId, string tag, string alias, string deviceGroupId, string notes)
|
||||
public async Task UpdateDevice(string deviceId, string? tag, string? alias, string? deviceGroupId, string? notes)
|
||||
{
|
||||
using var dbContext = _appDbFactory.GetContext();
|
||||
|
||||
|
||||
@ -68,21 +68,22 @@ public class ViewerPageDataProvider : IViewerPageDataProvider
|
||||
//return Task.FromResult(appTheme);
|
||||
}
|
||||
|
||||
public Task<string> GetUserDisplayName(PageModel pageModel)
|
||||
public async Task<string> GetUserDisplayName(PageModel pageModel)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pageModel?.User?.Identity?.Name))
|
||||
{
|
||||
return Task.FromResult(string.Empty);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var user = _dataService.GetUserByNameWithOrg(pageModel.User.Identity.Name);
|
||||
var userResult = await _dataService.GetUserByName(pageModel.User.Identity.Name);
|
||||
|
||||
if (user is null)
|
||||
if (!userResult.IsSuccess)
|
||||
{
|
||||
return Task.FromResult(string.Empty);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var user = userResult.Value;
|
||||
var displayName = user.UserOptions?.DisplayName ?? user.UserName ?? string.Empty;
|
||||
return Task.FromResult(displayName);
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ public class Device
|
||||
[StringLength(200)]
|
||||
[Sortable]
|
||||
[Display(Name = "Tags")]
|
||||
public string Tags { get; set; } = "";
|
||||
public string? Tags { get; set; }
|
||||
|
||||
[Sortable]
|
||||
[Display(Name = "Memory Total")]
|
||||
|
||||
@ -16,8 +16,8 @@ namespace Remotely.Tests;
|
||||
public class DataServiceTests
|
||||
{
|
||||
private readonly string _newDeviceID = "NewDeviceName";
|
||||
private IDataService _dataService;
|
||||
private TestData _testData;
|
||||
private IDataService _dataService = null!;
|
||||
private TestData _testData = null!;
|
||||
|
||||
[TestMethod]
|
||||
public async Task AddAlert()
|
||||
@ -32,7 +32,7 @@ public class DataServiceTests
|
||||
[TestMethod]
|
||||
public async Task AddOrUpdateDevice()
|
||||
{
|
||||
var storedDevice = _dataService.GetDevice(_newDeviceID);
|
||||
var storedDevice = (await _dataService.GetDevice(_newDeviceID)).Value;
|
||||
|
||||
Assert.IsNull(storedDevice);
|
||||
|
||||
@ -47,9 +47,9 @@ public class DataServiceTests
|
||||
var result = await _dataService.AddOrUpdateDevice(newDevice);
|
||||
Assert.IsTrue(result.IsSuccess);
|
||||
|
||||
storedDevice = _dataService.GetDevice(_newDeviceID);
|
||||
storedDevice = (await _dataService.GetDevice(_newDeviceID)).Value;
|
||||
|
||||
Assert.AreEqual(_newDeviceID, storedDevice.ID);
|
||||
Assert.AreEqual(_newDeviceID, storedDevice!.ID);
|
||||
Assert.AreEqual(Environment.MachineName, storedDevice.DeviceName);
|
||||
Assert.AreEqual(Environment.Is64BitOperatingSystem, storedDevice.Is64Bit);
|
||||
}
|
||||
@ -76,12 +76,12 @@ public class DataServiceTests
|
||||
[TestMethod]
|
||||
public void DeviceGroupPermissions()
|
||||
{
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin1.UserName).Length);
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin2.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org1User1.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org1User2.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User1.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User2.UserName).Length);
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin1.UserName!).Length);
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin2.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org1User1.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org1User2.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User1.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User2.UserName!).Length);
|
||||
|
||||
Assert.IsTrue(_dataService.DoesUserHaveAccessToDevice(_testData.Org1Device1.ID, _testData.Org1Admin1));
|
||||
Assert.IsTrue(_dataService.DoesUserHaveAccessToDevice(_testData.Org1Device1.ID, _testData.Org1Admin2));
|
||||
@ -91,16 +91,16 @@ public class DataServiceTests
|
||||
Assert.IsFalse(_dataService.DoesUserHaveAccessToDevice(_testData.Org1Device1.ID, _testData.Org2User2));
|
||||
|
||||
var groupID = _testData.Org1Group1.ID;
|
||||
_dataService.AddUserToDeviceGroup(_testData.Org1Id, groupID, _testData.Org1User1.UserName, out _);
|
||||
_dataService.AddUserToDeviceGroup(_testData.Org1Id, groupID, _testData.Org1User1.UserName!, out _);
|
||||
_testData.Org1Device1.DeviceGroupID = groupID;
|
||||
_dataService.UpdateDevice(_testData.Org1Device1.ID, "", "", groupID, "");
|
||||
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin1.UserName).Length);
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin2.UserName).Length);
|
||||
Assert.AreEqual(1, _dataService.GetDevicesForUser(_testData.Org1User1.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org1User2.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User1.UserName).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User2.UserName).Length);
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin1.UserName!).Length);
|
||||
Assert.AreEqual(2, _dataService.GetDevicesForUser(_testData.Org1Admin2.UserName!).Length);
|
||||
Assert.AreEqual(1, _dataService.GetDevicesForUser(_testData.Org1User1.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org1User2.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User1.UserName!).Length);
|
||||
Assert.AreEqual(0, _dataService.GetDevicesForUser(_testData.Org2User2.UserName!).Length);
|
||||
|
||||
Assert.IsTrue(_dataService.DoesUserHaveAccessToDevice(_testData.Org1Device1.ID, _testData.Org1Admin1));
|
||||
Assert.IsTrue(_dataService.DoesUserHaveAccessToDevice(_testData.Org1Device1.ID, _testData.Org1Admin2));
|
||||
@ -110,12 +110,12 @@ public class DataServiceTests
|
||||
Assert.IsFalse(_dataService.DoesUserHaveAccessToDevice(_testData.Org1Device1.ID, _testData.Org2User2));
|
||||
|
||||
var allDevices = _dataService.GetAllDevices(_testData.Org1Id).Select(x => x.ID).ToArray();
|
||||
Assert.AreEqual(2, _dataService.FilterDeviceIDsByUserPermission(allDevices, _testData.Org1Admin1).Length);
|
||||
Assert.AreEqual(2, _dataService.FilterDeviceIDsByUserPermission(allDevices, _testData.Org1Admin2).Length);
|
||||
Assert.AreEqual(1, _dataService.FilterDeviceIDsByUserPermission(allDevices, _testData.Org1User1).Length);
|
||||
Assert.AreEqual(0, _dataService.FilterDeviceIDsByUserPermission(allDevices, _testData.Org1User2).Length);
|
||||
Assert.AreEqual(0, _dataService.FilterDeviceIDsByUserPermission(allDevices, _testData.Org2User1).Length);
|
||||
Assert.AreEqual(0, _dataService.FilterDeviceIDsByUserPermission(allDevices, _testData.Org2User2).Length);
|
||||
Assert.AreEqual(2, _dataService.FilterDeviceIdsByUserPermission(allDevices, _testData.Org1Admin1).Length);
|
||||
Assert.AreEqual(2, _dataService.FilterDeviceIdsByUserPermission(allDevices, _testData.Org1Admin2).Length);
|
||||
Assert.AreEqual(1, _dataService.FilterDeviceIdsByUserPermission(allDevices, _testData.Org1User1).Length);
|
||||
Assert.AreEqual(0, _dataService.FilterDeviceIdsByUserPermission(allDevices, _testData.Org1User2).Length);
|
||||
Assert.AreEqual(0, _dataService.FilterDeviceIdsByUserPermission(allDevices, _testData.Org2User1).Length);
|
||||
Assert.AreEqual(0, _dataService.FilterDeviceIdsByUserPermission(allDevices, _testData.Org2User2).Length);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -198,12 +198,12 @@ public class DataServiceTests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOrganizationName()
|
||||
public async Task UpdateOrganizationName()
|
||||
{
|
||||
Assert.AreEqual("Org1", _testData.Org1Admin1.Organization.OrganizationName);
|
||||
_dataService.UpdateOrganizationName(_testData.Org1Id, "Test Org");
|
||||
var updatedOrg = _dataService.GetOrganizationById(_testData.Org1Id);
|
||||
Assert.AreEqual("Test Org", updatedOrg.OrganizationName);
|
||||
Assert.AreEqual("Org1", _testData.Org1Admin1.Organization!.OrganizationName);
|
||||
await _dataService.UpdateOrganizationName(_testData.Org1Id, "Test Org");
|
||||
var updatedOrg = (await _dataService.GetOrganizationById(_testData.Org1Id)).Value;
|
||||
Assert.AreEqual("Test Org", updatedOrg!.OrganizationName);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -217,8 +217,8 @@ public class DataServiceTests
|
||||
|
||||
currentAdmins = _dataService.GetServerAdmins();
|
||||
Assert.AreEqual(2, currentAdmins.Count);
|
||||
Assert.IsTrue(currentAdmins.Contains(_testData.Org1Admin1.UserName));
|
||||
Assert.IsTrue(currentAdmins.Contains(_testData.Org1Admin2.UserName));
|
||||
Assert.IsTrue(currentAdmins.Contains(_testData.Org1Admin1.UserName!));
|
||||
Assert.IsTrue(currentAdmins.Contains(_testData.Org1Admin2.UserName!));
|
||||
|
||||
// Shouldn't be able to change themselves.
|
||||
await _dataService.SetIsServerAdmin(_testData.Org1Admin2.Id, false, _testData.Org1Admin2.Id);
|
||||
@ -237,12 +237,12 @@ public class DataServiceTests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void VerifyInitialData()
|
||||
public async Task VerifyInitialData()
|
||||
{
|
||||
Assert.IsNotNull(_dataService.GetUserByNameWithOrg(_testData.Org1Admin1.UserName));
|
||||
Assert.IsNotNull(_dataService.GetUserByNameWithOrg(_testData.Org1Admin2.UserName));
|
||||
Assert.IsNotNull(_dataService.GetUserByNameWithOrg(_testData.Org1User1.UserName));
|
||||
Assert.IsNotNull(_dataService.GetUserByNameWithOrg(_testData.Org1User2.UserName));
|
||||
Assert.IsNotNull((await _dataService.GetUserByName(_testData.Org1Admin1.UserName!)).Value);
|
||||
Assert.IsNotNull((await _dataService.GetUserByName(_testData.Org1Admin2.UserName!)).Value);
|
||||
Assert.IsNotNull((await _dataService.GetUserByName(_testData.Org1User1.UserName!)).Value);
|
||||
Assert.IsNotNull((await _dataService.GetUserByName(_testData.Org1User2.UserName!)).Value);
|
||||
Assert.AreEqual(2, _dataService.GetOrganizationCount());
|
||||
|
||||
var devices1 = _dataService.GetAllDevices(_testData.Org1Id);
|
||||
|
||||
@ -17,7 +17,7 @@ namespace Remotely.Tests;
|
||||
public class TestData
|
||||
{
|
||||
#region Organization1
|
||||
public Organization Org1 => Org1Admin1.Organization;
|
||||
public Organization Org1 => Org1Admin1.Organization!;
|
||||
|
||||
public RemotelyUser Org1Admin1 { get; } = new()
|
||||
{
|
||||
@ -28,11 +28,11 @@ public class TestData
|
||||
UserOptions = new RemotelyUserOptions()
|
||||
};
|
||||
|
||||
public RemotelyUser Org1Admin2 { get; private set; }
|
||||
public RemotelyUser Org1Admin2 { get; private set; } = null!;
|
||||
|
||||
public Device Org1Device1 { get; private set; }
|
||||
public Device Org1Device1 { get; private set; } = null!;
|
||||
|
||||
public Device Org1Device2 { get; private set; }
|
||||
public Device Org1Device2 { get; private set; } = null!;
|
||||
|
||||
public DeviceGroup Org1Group1 { get; private set; } = new DeviceGroup()
|
||||
{
|
||||
@ -45,14 +45,14 @@ public class TestData
|
||||
};
|
||||
|
||||
public string Org1Id => Org1.ID;
|
||||
public RemotelyUser Org1User1 { get; private set; }
|
||||
public RemotelyUser Org1User2 { get; private set; }
|
||||
public RemotelyUser Org1User1 { get; private set; } = null!;
|
||||
public RemotelyUser Org1User2 { get; private set; } = null!;
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Organization2
|
||||
public Organization Org2 => Org2Admin1.Organization;
|
||||
public Organization Org2 => Org2Admin1.Organization!;
|
||||
|
||||
public RemotelyUser Org2Admin1 { get; } = new()
|
||||
{
|
||||
@ -63,11 +63,11 @@ public class TestData
|
||||
UserOptions = new RemotelyUserOptions()
|
||||
};
|
||||
|
||||
public RemotelyUser Org2Admin2 { get; private set; }
|
||||
public RemotelyUser Org2Admin2 { get; private set; } = null!;
|
||||
|
||||
public Device Org2Device1 { get; private set; }
|
||||
public Device Org2Device1 { get; private set; } = null!;
|
||||
|
||||
public Device Org2Device2 { get; private set; }
|
||||
public Device Org2Device2 { get; private set; } = null!;
|
||||
|
||||
public DeviceGroup Org2Group1 { get; private set; } = new DeviceGroup()
|
||||
{
|
||||
@ -80,8 +80,8 @@ public class TestData
|
||||
};
|
||||
|
||||
public string Org2Id => Org2.ID;
|
||||
public RemotelyUser Org2User1 { get; private set; }
|
||||
public RemotelyUser Org2User2 { get; private set; }
|
||||
public RemotelyUser Org2User1 { get; private set; } = null!;
|
||||
public RemotelyUser Org2User2 { get; private set; } = null!;
|
||||
#endregion
|
||||
|
||||
public void ClearData()
|
||||
@ -106,13 +106,13 @@ public class TestData
|
||||
await userManager.CreateAsync(Org1Admin1);
|
||||
|
||||
await dataService.CreateUser("org1admin2@test.com", true, Org1Admin1.OrganizationID);
|
||||
Org1Admin2 = dataService.GetUserByNameWithOrg("org1admin2@test.com");
|
||||
Org1Admin2 = (await dataService.GetUserByName("org1admin2@test.com")).Value!;
|
||||
|
||||
await dataService.CreateUser("org1testuser1@test.com", false, Org1Admin1.OrganizationID);
|
||||
Org1User1 = dataService.GetUserByNameWithOrg("org1testuser1@test.com");
|
||||
Org1User1 = (await dataService.GetUserByName("org1testuser1@test.com")).Value!;
|
||||
|
||||
await dataService.CreateUser("org1testuser2@test.com", false, Org1Admin1.OrganizationID);
|
||||
Org1User2 = dataService.GetUserByNameWithOrg("org1testuser2@test.com");
|
||||
Org1User2 = (await dataService.GetUserByName("org1testuser2@test.com")).Value!;
|
||||
|
||||
var device1 = new DeviceClientDto()
|
||||
{
|
||||
@ -126,12 +126,12 @@ public class TestData
|
||||
DeviceName = "Org1Device2Name",
|
||||
OrganizationID = Org1Id
|
||||
};
|
||||
Org1Device1 = (await dataService.AddOrUpdateDevice(device1)).Value;
|
||||
Org1Device2 = (await dataService.AddOrUpdateDevice(device2)).Value;
|
||||
Org1Device1 = (await dataService.AddOrUpdateDevice(device1)).Value!;
|
||||
Org1Device2 = (await dataService.AddOrUpdateDevice(device2)).Value!;
|
||||
|
||||
await dataService.AddDeviceGroup(Org1Admin1.OrganizationID, Org1Group1);
|
||||
await dataService.AddDeviceGroup(Org1Admin1.OrganizationID, Org1Group2);
|
||||
var deviceGroups1 = dataService.GetDeviceGroups(Org1Admin1.UserName);
|
||||
var deviceGroups1 = dataService.GetDeviceGroups(Org1Admin1.UserName!);
|
||||
Org1Group1 = deviceGroups1.First(x => x.Name == Org1Group1.Name);
|
||||
Org1Group2 = deviceGroups1.First(x => x.Name == Org1Group2.Name);
|
||||
|
||||
@ -140,13 +140,13 @@ public class TestData
|
||||
await userManager.CreateAsync(Org2Admin1);
|
||||
|
||||
await dataService.CreateUser("org2admin2@test.com", true, Org2Admin1.OrganizationID);
|
||||
Org2Admin2 = dataService.GetUserByNameWithOrg("org2admin2@test.com");
|
||||
Org2Admin2 = (await dataService.GetUserByName("org2admin2@test.com")).Value!;
|
||||
|
||||
await dataService.CreateUser("org2testuser1@test.com", false, Org2Admin1.OrganizationID);
|
||||
Org2User1 = dataService.GetUserByNameWithOrg("org2testuser1@test.com");
|
||||
Org2User1 = (await dataService.GetUserByName("org2testuser1@test.com")).Value!;
|
||||
|
||||
await dataService.CreateUser("org2testuser2@test.com", false, Org2Admin1.OrganizationID);
|
||||
Org2User2 = dataService.GetUserByNameWithOrg("org2testuser2@test.com");
|
||||
Org2User2 = (await dataService.GetUserByName("org2testuser2@test.com")).Value!;
|
||||
|
||||
var device3 = new DeviceClientDto()
|
||||
{
|
||||
@ -160,12 +160,12 @@ public class TestData
|
||||
DeviceName = "Org2Device2Name",
|
||||
OrganizationID = Org2Id
|
||||
};
|
||||
Org2Device1 = (await dataService.AddOrUpdateDevice(device3)).Value;
|
||||
Org2Device2 = (await dataService.AddOrUpdateDevice(device4)).Value;
|
||||
Org2Device1 = (await dataService.AddOrUpdateDevice(device3)).Value!;
|
||||
Org2Device2 = (await dataService.AddOrUpdateDevice(device4)).Value!;
|
||||
|
||||
await dataService.AddDeviceGroup(Org2Admin1.OrganizationID, Org2Group1);
|
||||
await dataService.AddDeviceGroup(Org2Admin1.OrganizationID, Org2Group2);
|
||||
var deviceGroups2 = dataService.GetDeviceGroups(Org2Admin1.UserName);
|
||||
var deviceGroups2 = dataService.GetDeviceGroups(Org2Admin1.UserName!);
|
||||
Org2Group1 = deviceGroups2.First(x => x.Name == Org2Group1.Name);
|
||||
Org2Group2 = deviceGroups2.First(x => x.Name == Org2Group2.Name);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user