mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Make User nullable in AuthComponentBase. Add utility method to make sure it's populated. Refactor as necessary.
This commit is contained in:
parent
b8153c03c3
commit
ce9d65a236
@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Entities;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -7,23 +8,26 @@ namespace Remotely.Server.Auth;
|
||||
|
||||
public class OrganizationAdminRequirementHandler : AuthorizationHandler<OrganizationAdminRequirement>
|
||||
{
|
||||
private readonly UserManager<RemotelyUser> _userManager;
|
||||
private readonly IDataService _dataService;
|
||||
|
||||
public OrganizationAdminRequirementHandler(UserManager<RemotelyUser> userManager)
|
||||
public OrganizationAdminRequirementHandler(IDataService dataService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_dataService = dataService;
|
||||
}
|
||||
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OrganizationAdminRequirement requirement)
|
||||
{
|
||||
if (context.User.Identity?.IsAuthenticated != true)
|
||||
if (context.User.Identity?.IsAuthenticated != true ||
|
||||
string.IsNullOrWhiteSpace(context.User.Identity.Name))
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(context.User);
|
||||
if (user?.IsAdministrator != true)
|
||||
var userResult = await _dataService.GetUserByName(context.User.Identity.Name);
|
||||
|
||||
if (!userResult.IsSuccess ||
|
||||
!userResult.Value.IsAdministrator)
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Entities;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -9,28 +10,31 @@ namespace Remotely.Server.Auth;
|
||||
|
||||
public class ServerAdminRequirementHandler : AuthorizationHandler<ServerAdminRequirement>
|
||||
{
|
||||
private readonly UserManager<RemotelyUser> _userManager;
|
||||
private readonly IDataService _dataService;
|
||||
|
||||
public ServerAdminRequirementHandler(UserManager<RemotelyUser> userManager)
|
||||
public ServerAdminRequirementHandler(IDataService dataService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_dataService = dataService;
|
||||
}
|
||||
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ServerAdminRequirement requirement)
|
||||
{
|
||||
if (context.User.Identity?.IsAuthenticated != true)
|
||||
if (context.User.Identity?.IsAuthenticated != true ||
|
||||
string.IsNullOrWhiteSpace(context.User.Identity.Name))
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(context.User);
|
||||
if (user?.IsServerAdmin != true)
|
||||
var userResult = await _dataService.GetUserByName(context.User.Identity.Name);
|
||||
|
||||
if (!userResult.IsSuccess ||
|
||||
!userResult.Value.IsServerAdmin)
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,21 +11,25 @@ namespace Remotely.Server.Auth;
|
||||
|
||||
public class TwoFactorRequiredHandler : AuthorizationHandler<TwoFactorRequiredRequirement>
|
||||
{
|
||||
private readonly UserManager<RemotelyUser> _userManager;
|
||||
private readonly IDataService _dataService;
|
||||
private readonly IApplicationConfig _appConfig;
|
||||
|
||||
public TwoFactorRequiredHandler(UserManager<RemotelyUser> userManager, IApplicationConfig appConfig)
|
||||
public TwoFactorRequiredHandler(IDataService dataService, IApplicationConfig appConfig)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_dataService = dataService;
|
||||
_appConfig = appConfig;
|
||||
}
|
||||
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, TwoFactorRequiredRequirement requirement)
|
||||
{
|
||||
if (context.User.Identity?.IsAuthenticated == true && _appConfig.Require2FA)
|
||||
if (context.User.Identity?.IsAuthenticated == true &&
|
||||
context.User.Identity.Name is not null &&
|
||||
_appConfig.Require2FA)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(context.User);
|
||||
if (user?.TwoFactorEnabled != true)
|
||||
var userResult = await _dataService.GetUserByName(context.User.Identity.Name);
|
||||
|
||||
if (!userResult.IsSuccess ||
|
||||
!userResult.Value.TwoFactorEnabled)
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
|
||||
@ -63,10 +63,8 @@
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (IsAuthenticated)
|
||||
{
|
||||
GetAlerts();
|
||||
}
|
||||
EnsureUserSet();
|
||||
GetAlerts();
|
||||
}
|
||||
|
||||
private async Task ClearAlert(Alert alert)
|
||||
@ -77,12 +75,14 @@
|
||||
|
||||
private async Task ClearAllAlerts()
|
||||
{
|
||||
EnsureUserSet();
|
||||
await DataService.DeleteAllAlerts(User.OrganizationID, User.UserName);
|
||||
_alerts.Clear();
|
||||
}
|
||||
|
||||
private void GetAlerts()
|
||||
{
|
||||
EnsureUserSet();
|
||||
_alerts.Clear();
|
||||
var alerts = DataService.GetAlerts(User.Id);
|
||||
if (alerts.Any())
|
||||
|
||||
@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Entities;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -12,62 +13,34 @@ namespace Remotely.Server.Components;
|
||||
[Authorize]
|
||||
public class AuthComponentBase : ComponentBase
|
||||
{
|
||||
private readonly ManualResetEventSlim _initSignal = new();
|
||||
private RemotelyUser? _user;
|
||||
private string? _userName;
|
||||
|
||||
public bool IsAuthenticated { get; private set; }
|
||||
|
||||
public bool IsUserSet => _user is not null;
|
||||
|
||||
public RemotelyUser User
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initSignal.Wait(TimeSpan.FromSeconds(5)) && _user is not null)
|
||||
{
|
||||
return _user;
|
||||
}
|
||||
// This should never happen, since AuthBasedComponent is only
|
||||
// used on components that require authentication. This was easier
|
||||
// than making this explicitly nullable and refactoring everywhere.
|
||||
Logger.LogError("Failed to resolve user.");
|
||||
throw new InvalidOperationException("Failed to resolve user.");
|
||||
}
|
||||
private set => _user = value;
|
||||
}
|
||||
|
||||
public string UserName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initSignal.Wait(TimeSpan.FromSeconds(5)) && _userName is not null)
|
||||
{
|
||||
return _userName;
|
||||
}
|
||||
Logger.LogError("Failed to resolve user.");
|
||||
throw new InvalidOperationException("Failed to resolve user.");
|
||||
}
|
||||
private set => _userName = value;
|
||||
}
|
||||
|
||||
[Inject]
|
||||
protected IAuthService AuthService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ILogger<AuthComponentBase> Logger { get; init; } = null!;
|
||||
protected RemotelyUser? User { get; private set; }
|
||||
|
||||
protected string? UserName => User?.UserName;
|
||||
|
||||
[MemberNotNull(nameof(User), nameof(UserName))]
|
||||
protected void EnsureUserSet()
|
||||
{
|
||||
if (User is null)
|
||||
{
|
||||
throw new InvalidOperationException("User has not been set.");
|
||||
}
|
||||
|
||||
if (UserName is null)
|
||||
{
|
||||
throw new InvalidOperationException("UserName has not been set.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
IsAuthenticated = await AuthService.IsAuthenticated();
|
||||
var userResult = await AuthService.GetUser();
|
||||
if (userResult.IsSuccess)
|
||||
{
|
||||
_user = userResult.Value;
|
||||
_userName = userResult.Value.UserName ?? string.Empty;
|
||||
User = userResult.Value;
|
||||
}
|
||||
_initSignal.Set();
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,23 +18,27 @@
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (AppConfig.Require2FA && !User.TwoFactorEnabled)
|
||||
if (User is not null &&
|
||||
AppConfig.Require2FA &&
|
||||
!User.TwoFactorEnabled)
|
||||
{
|
||||
NavManager.NavigateTo("/TwoFactorRequired");
|
||||
}
|
||||
base.OnAfterRender(firstRender);
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
var isAuthenticated = await AuthService.IsAuthenticated();
|
||||
var userResult = await AuthService.GetUser();
|
||||
// This handles a weird edge case when the user has been
|
||||
// deleted but still has an authentication cookie in their
|
||||
// browser.
|
||||
if (IsAuthenticated == true && !IsUserSet)
|
||||
if (isAuthenticated == true && !userResult.IsSuccess)
|
||||
{
|
||||
await SignInManager.SignOutAsync();
|
||||
NavManager.NavigateTo("/");
|
||||
|
||||
@ -79,6 +79,7 @@ public partial class DeviceCard : AuthComponentBase, IDisposable
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
EnsureUserSet();
|
||||
_theme = await AppState.GetEffectiveTheme();
|
||||
_currentVersion = UpgradeService.GetCurrentVersion();
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
@ -180,6 +181,7 @@ public partial class DeviceCard : AuthComponentBase, IDisposable
|
||||
}
|
||||
private async Task HandleValidSubmit()
|
||||
{
|
||||
EnsureUserSet();
|
||||
if (!DataService.DoesUserHaveAccessToDevice(Device.ID, User))
|
||||
{
|
||||
ToastService.ShowToast("Unauthorized.", classString: "bg-warning");
|
||||
@ -199,6 +201,8 @@ public partial class DeviceCard : AuthComponentBase, IDisposable
|
||||
|
||||
private async Task OnFileInputChanged(InputFileChangeEventArgs args)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
ToastService.ShowToast("File upload started.");
|
||||
|
||||
var fileId = await DataService.AddSharedFile(args.File, User.OrganizationID, OnFileInputProgress);
|
||||
|
||||
@ -74,6 +74,8 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
CircuitConnection.MessageReceived += CircuitConnection_MessageReceived;
|
||||
AppState.PropertyChanged += AppState_PropertyChanged;
|
||||
|
||||
@ -283,6 +285,8 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
|
||||
private void LoadDevices()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
lock (_devicesLock)
|
||||
{
|
||||
_allDevices.Clear();
|
||||
@ -346,6 +350,8 @@ public partial class DevicesFrame : AuthComponentBase, IDisposable
|
||||
|
||||
private async Task WakeDevices()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var offlineDevices = DataService
|
||||
.GetDevicesForUser(UserName)
|
||||
.Where(x => !x.IsOnline);
|
||||
|
||||
@ -64,6 +64,8 @@ public partial class Terminal : AuthComponentBase, IDisposable
|
||||
private EventCallback<SavedScript> RunQuickScript =>
|
||||
EventCallback.Factory.Create<SavedScript>(this, async script =>
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var scriptRun = new ScriptRun
|
||||
{
|
||||
OrganizationID = User.OrganizationID,
|
||||
@ -285,6 +287,8 @@ public partial class Terminal : AuthComponentBase, IDisposable
|
||||
|
||||
private async Task ShowQuickScripts()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var quickScripts = await DataService.GetQuickScripts(User.Id);
|
||||
if (quickScripts?.Any() != true)
|
||||
{
|
||||
@ -344,6 +348,8 @@ public partial class Terminal : AuthComponentBase, IDisposable
|
||||
}
|
||||
private bool TryMatchShellShortcuts()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var currentText = InputText?.Trim()?.ToLower();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(currentText))
|
||||
|
||||
@ -63,7 +63,7 @@ public partial class RunScript : AuthComponentBase
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
EnsureUserSet();
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
_devices = DataService
|
||||
.GetDevicesForUser(UserName)
|
||||
@ -107,6 +107,8 @@ public partial class RunScript : AuthComponentBase
|
||||
|
||||
private async Task ExecuteScript()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (_selectedScript is null)
|
||||
{
|
||||
ToastService.ShowToast("You must select a script.", classString: "bg-warning");
|
||||
@ -163,6 +165,8 @@ public partial class RunScript : AuthComponentBase
|
||||
|
||||
private async Task ScriptSelected(ScriptTreeNode viewModel)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (viewModel.Script is not null)
|
||||
{
|
||||
var scriptResult = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
|
||||
@ -36,11 +36,35 @@ public partial class SavedScripts : AuthComponentBase
|
||||
[Inject]
|
||||
public IModalService ModalService { get; set; } = null!;
|
||||
|
||||
private bool CanModifyScript => _selectedScript.Id == Guid.Empty ||
|
||||
_selectedScript.CreatorId == User.Id || User.IsAdministrator;
|
||||
private bool CanModifyScript
|
||||
{
|
||||
get
|
||||
{
|
||||
if (User is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CanDeleteScript => !string.IsNullOrWhiteSpace(_selectedScript.CreatorId) &&
|
||||
(_selectedScript.CreatorId == User.Id || User.IsAdministrator);
|
||||
return
|
||||
_selectedScript.Id == Guid.Empty ||
|
||||
_selectedScript.CreatorId == User.Id || User.IsAdministrator;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanDeleteScript
|
||||
{
|
||||
get
|
||||
{
|
||||
if (User is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return
|
||||
!string.IsNullOrWhiteSpace(_selectedScript.CreatorId) &&
|
||||
(_selectedScript.CreatorId == User.Id || User.IsAdministrator);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
@ -53,6 +77,8 @@ public partial class SavedScripts : AuthComponentBase
|
||||
|
||||
private async Task OnValidSubmit(EditContext context)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (_selectedScript is null)
|
||||
{
|
||||
return;
|
||||
@ -63,7 +89,7 @@ public partial class SavedScripts : AuthComponentBase
|
||||
ToastService.ShowToast("You can't modify other people's scripts.", classString: "bg-warning");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await DataService.AddOrUpdateSavedScript(_selectedScript, User.Id);
|
||||
await ParentPage.RefreshScripts();
|
||||
ToastService.ShowToast("Script saved.");
|
||||
@ -102,6 +128,7 @@ public partial class SavedScripts : AuthComponentBase
|
||||
|
||||
private async Task ScriptSelected(ScriptTreeNode viewModel)
|
||||
{
|
||||
EnsureUserSet();
|
||||
if (viewModel.Script is not null)
|
||||
{
|
||||
var result = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
|
||||
@ -48,25 +48,39 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
[Inject]
|
||||
private IToastService ToastService { get; set; } = null!;
|
||||
|
||||
private bool CanModifySchedule =>
|
||||
_selectedSchedule.CreatorId == User.Id ||
|
||||
User.IsAdministrator;
|
||||
private bool CanModifySchedule
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureUserSet();
|
||||
return
|
||||
_selectedSchedule.CreatorId == User.Id ||
|
||||
User.IsAdministrator;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanDeleteSchedule =>
|
||||
_selectedSchedule.CreatorId == User.Id ||
|
||||
User.IsAdministrator;
|
||||
private bool CanDeleteSchedule
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureUserSet();
|
||||
return
|
||||
_selectedSchedule.CreatorId == User.Id ||
|
||||
User.IsAdministrator;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
if (IsAuthenticated)
|
||||
{
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
_devices = DataService
|
||||
.GetDevicesForUser(UserName)
|
||||
.OrderBy(x => x.DeviceName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
_devices = DataService
|
||||
.GetDevicesForUser(UserName)
|
||||
.OrderBy(x => x.DeviceName)
|
||||
.ToArray();
|
||||
|
||||
await RefreshSchedules();
|
||||
}
|
||||
@ -140,6 +154,8 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
|
||||
private async Task OnValidSubmit(EditContext context)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (_selectedSchedule is null)
|
||||
{
|
||||
return;
|
||||
@ -226,6 +242,8 @@ public partial class ScriptSchedules : AuthComponentBase
|
||||
|
||||
private async Task ScriptSelected(ScriptTreeNode viewModel)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (viewModel.Script is not null)
|
||||
{
|
||||
var result = await DataService.GetSavedScript(User.Id, viewModel.Script.Id);
|
||||
|
||||
@ -18,7 +18,11 @@
|
||||
<AlertBanner Message="@_alertMessage" />
|
||||
}
|
||||
|
||||
@if (User?.IsAdministrator == true)
|
||||
@if (_isLoading)
|
||||
{
|
||||
<h5>Loading...</h5>
|
||||
}
|
||||
else if (User is not null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_newKeySecret))
|
||||
{
|
||||
@ -71,26 +75,25 @@
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h5 class="text-muted">Only organization administrators can view this page.</h5>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<ApiToken> _apiTokens = new();
|
||||
private string _alertMessage = string.Empty;
|
||||
private string _createKeyName = string.Empty;
|
||||
private string _newKeySecret = string.Empty;
|
||||
private bool _isLoading = true;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
RefreshData();
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private async Task CreateNewKey()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var secret = RandomGenerator.GenerateString(48);
|
||||
var secretHash = new PasswordHasher<string>().HashPassword(string.Empty, secret);
|
||||
|
||||
@ -107,6 +110,8 @@ else
|
||||
|
||||
private async Task DeleteKey(string keyId)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var result = await JsInterop.Confirm("Are you sure you want to delete this key?");
|
||||
if (!result)
|
||||
{
|
||||
@ -125,6 +130,7 @@ else
|
||||
|
||||
private void RefreshData()
|
||||
{
|
||||
EnsureUserSet();
|
||||
_apiTokens.Clear();
|
||||
_apiTokens.AddRange(DataService.GetAllApiTokens(User.Id));
|
||||
_createKeyName = string.Empty;
|
||||
@ -135,6 +141,7 @@ else
|
||||
|
||||
private async Task RenameKey(string keyId)
|
||||
{
|
||||
EnsureUserSet();
|
||||
var newName = await JsInterop.Prompt("New key name");
|
||||
if (!string.IsNullOrWhiteSpace(newName))
|
||||
{
|
||||
|
||||
@ -92,6 +92,8 @@
|
||||
|
||||
private async Task HandleValidSubmit(EditContext context)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
await DataService.UpdateBrandingInfo(
|
||||
User.OrganizationID,
|
||||
_inputModel.ProductName,
|
||||
@ -168,6 +170,7 @@
|
||||
|
||||
private async Task ResetBranding()
|
||||
{
|
||||
EnsureUserSet();
|
||||
var result = await JsInterop.Confirm("Are you sure you want to reset branding to default?");
|
||||
if (result)
|
||||
{
|
||||
|
||||
@ -29,11 +29,15 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (_isLoading)
|
||||
{
|
||||
<h5>Loading...</h5>
|
||||
}
|
||||
else if (_device is null)
|
||||
{
|
||||
<h3>Device not found.</h3>
|
||||
}
|
||||
else if (!DataService.DoesUserHaveAccessToDevice(_device.ID, User))
|
||||
else if (!_userHasAccess)
|
||||
{
|
||||
<h3>Unauthorized.</h3>
|
||||
}
|
||||
@ -168,7 +172,7 @@ else
|
||||
<InputSelect @bind-Value="_device.DeviceGroupID" class="form-control">
|
||||
<option value="">None</option>
|
||||
|
||||
@foreach (var group in DataService.GetDeviceGroups(UserName))
|
||||
@foreach (var group in _deviceGroups)
|
||||
{
|
||||
<option @key="group.ID" value="@group.ID">@group.Name</option>
|
||||
}
|
||||
|
||||
@ -22,7 +22,10 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
|
||||
private string? _alertMessage;
|
||||
private Device? _device;
|
||||
private bool _userHasAccess;
|
||||
private string? _inputDeviceId;
|
||||
private bool _isLoading = true;
|
||||
private DeviceGroup[] _deviceGroups = Array.Empty<DeviceGroup>();
|
||||
|
||||
[Parameter]
|
||||
public string ActiveTab { get; set; } = string.Empty;
|
||||
@ -54,12 +57,15 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(DeviceId))
|
||||
{
|
||||
var deviceResult = await DataService.GetDevice(DeviceId);
|
||||
if (deviceResult.IsSuccess)
|
||||
{
|
||||
_device = deviceResult.Value;
|
||||
_userHasAccess = DataService.DoesUserHaveAccessToDevice(_device.ID, User);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -67,7 +73,9 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
_deviceGroups = DataService.GetDeviceGroups(UserName);
|
||||
CircuitConnection.MessageReceived += CircuitConnection_MessageReceived;
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private void CircuitConnection_MessageReceived(object? sender, Models.CircuitEvent e)
|
||||
@ -130,6 +138,8 @@ public partial class DeviceDetails : AuthComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
_scriptResults.Clear();
|
||||
|
||||
if (User.IsAdministrator)
|
||||
|
||||
@ -4,8 +4,11 @@
|
||||
|
||||
<h3 class="mb-3">Manage Organization</h3>
|
||||
|
||||
|
||||
@if (User?.IsAdministrator == true)
|
||||
@if (_isLoading)
|
||||
{
|
||||
<h5>Loading...</h5>
|
||||
}
|
||||
else if (User is not null)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
@ -195,9 +198,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<h5 class="text-muted">Only organization administrators can view this page.</h5>
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,6 +25,7 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
private readonly List<RemotelyUser> _orgUsers = new();
|
||||
private bool _inviteAsAdmin;
|
||||
private string _inviteEmail = string.Empty;
|
||||
private bool _isLoading = true;
|
||||
private string _newDeviceGroupName = string.Empty;
|
||||
private Organization? _organization;
|
||||
private string _selectedDeviceGroupId = string.Empty;
|
||||
@ -55,10 +56,14 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
await RefreshData();
|
||||
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private async Task CreateNewDeviceGroup()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -93,6 +98,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsServerAdmin)
|
||||
{
|
||||
return;
|
||||
@ -109,6 +116,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task DeleteInvite(InviteLink invite)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -127,6 +136,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task DeleteSelectedDeviceGroup()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -150,6 +161,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task DeleteUser(RemotelyUser user)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -208,6 +221,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -237,6 +252,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task RefreshData()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
var orgResult = await DataService.GetOrganizationByUserName(UserName);
|
||||
if (!orgResult.IsSuccess)
|
||||
{
|
||||
@ -256,6 +273,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
}
|
||||
private async Task ResetPassword(RemotelyUser user)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -275,6 +294,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task SendInvite()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
@ -352,6 +373,8 @@ public partial class ManageOrganization : AuthComponentBase
|
||||
|
||||
private async Task SetUserIsAdmin(ChangeEventArgs args, RemotelyUser orgUser)
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsAdministrator)
|
||||
{
|
||||
return;
|
||||
|
||||
@ -62,6 +62,8 @@ public partial class ScriptsPage : AuthComponentBase
|
||||
|
||||
public async Task RefreshScripts()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
_treeNodes.Clear();
|
||||
|
||||
_allScripts = await DataService.GetSavedScriptsWithoutContent(User.Id, User.OrganizationID);
|
||||
@ -119,6 +121,13 @@ public partial class ScriptsPage : AuthComponentBase
|
||||
|
||||
private void RefreshTreeNodes()
|
||||
{
|
||||
if (User is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
_treeNodes.Clear();
|
||||
|
||||
foreach (var script in _allScripts)
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
@foreach (var user in UserList)
|
||||
{
|
||||
<div @key="user.Id">
|
||||
<input type="checkbox" disabled="@(user.Id == User.Id)" checked="@user.IsServerAdmin" @onchange="ev => SetIsServerAdmin(ev, user)" />
|
||||
<input type="checkbox" disabled="@(user.Id == User?.Id)" checked="@user.IsServerAdmin" @onchange="ev => SetIsServerAdmin(ev, user)" />
|
||||
<span class="ml-2 align-top" style="line-height:1.3em">@user.UserName</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -188,6 +188,13 @@ public partial class ServerConfig : AuthComponentBase
|
||||
{
|
||||
get
|
||||
{
|
||||
if (User is null)
|
||||
{
|
||||
return Enumerable.Empty<RemotelyUser>();
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
return _userList.Where(x =>
|
||||
(!_showAdminsOnly || x.IsServerAdmin) &&
|
||||
(!_showMyOrgAdminsOnly || x.OrganizationID == User.OrganizationID));
|
||||
@ -197,7 +204,7 @@ public partial class ServerConfig : AuthComponentBase
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
EnsureUserSet();
|
||||
if (!User.IsServerAdmin)
|
||||
{
|
||||
return;
|
||||
@ -338,8 +345,8 @@ public partial class ServerConfig : AuthComponentBase
|
||||
|
||||
private async Task SaveAndTestSmtpSettings()
|
||||
{
|
||||
EnsureUserSet();
|
||||
await SaveInputToAppSettings();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(User.Email))
|
||||
{
|
||||
ToastService.ShowToast2("User email is not set.", Enums.ToastType.Warning);
|
||||
@ -417,6 +424,9 @@ public partial class ServerConfig : AuthComponentBase
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureUserSet();
|
||||
|
||||
DataService.SetIsServerAdmin(user.Id, isAdmin, User.Id);
|
||||
ToastService.ShowToast("Server admins updated.");
|
||||
}
|
||||
@ -443,6 +453,8 @@ public partial class ServerConfig : AuthComponentBase
|
||||
|
||||
private async Task UpdateAllDevices()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!User.IsServerAdmin)
|
||||
{
|
||||
return;
|
||||
|
||||
@ -97,11 +97,13 @@
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
_options = User.UserOptions ?? new();
|
||||
_options = User?.UserOptions ?? new();
|
||||
}
|
||||
|
||||
private Task HandleValidSubmit()
|
||||
{
|
||||
EnsureUserSet();
|
||||
|
||||
if (!_options.CommandModeShortcutBash.StartsWith("/"))
|
||||
{
|
||||
_options.CommandModeShortcutBash = "/" + _options.CommandModeShortcutBash;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user