Clean up errors and majority of warnings.

This commit is contained in:
Jared Goodwin 2023-07-25 14:05:59 -07:00
parent 28079f887a
commit 0f9ea4957b
32 changed files with 543 additions and 305 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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!;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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)
{

View File

@ -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
{

View File

@ -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()

View File

@ -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>

View File

@ -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

View File

@ -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; }
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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.";
}

View File

@ -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);
}

View File

@ -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>
}

View File

@ -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>");

View File

@ -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();
}
}

View File

@ -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; }
}
}

View File

@ -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">

View File

@ -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.");

View File

@ -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));

View File

@ -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" />

View File

@ -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" />

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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")]

View File

@ -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);

View File

@ -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);
}