diff --git a/src/Data/Repositories/ChannelOperationRequestRepository.cs b/src/Data/Repositories/ChannelOperationRequestRepository.cs index 0e423ad7..8351d839 100644 --- a/src/Data/Repositories/ChannelOperationRequestRepository.cs +++ b/src/Data/Repositories/ChannelOperationRequestRepository.cs @@ -197,7 +197,7 @@ public async Task> GetPendingRequests() .Where(request => request.Status == ChannelOperationRequestStatus.OnChainConfirmationPending || request.Status == ChannelOperationRequestStatus.Pending || request.Status == ChannelOperationRequestStatus.PSBTSignaturesPending) - .Include(request => request.Wallet) + .Include(request => request.Wallet).ThenInclude(x => x.Keys) .Include(request => request.SourceNode) .Include(request => request.DestNode) .Include(request => request.ChannelOperationRequestPsbts) diff --git a/src/Pages/ChannelRequests.razor b/src/Pages/ChannelRequests.razor index 087d9c55..c5a574bf 100644 --- a/src/Pages/ChannelRequests.razor +++ b/src/Pages/ChannelRequests.razor @@ -9,11 +9,18 @@ Channel Operation Requests -@if (!_hidePendingRequests) +@if (_isFinanceManager || _isNodeManager) { + @if (_isFinanceManager) + {

Requests awaiting my signature

+ } + else if (_isNodeManager) + { +

Requests awaiting signature by a Finance Manager

+ }

@@ -154,9 +161,9 @@ - + @{ - if (LoggedUser.Id == context.Item.UserId) + if (LoggedUser?.Id == context.Item.UserId) { - - - - + + + + @inject IChannelOperationRequestRepository ChannelOperationRequestRepository @inject IChannelOperationRequestPSBTRepository ChannelOperationRequestPsbtRepository @@ -306,18 +303,13 @@ private List? _allRequests; private ChannelOperationRequest? _selectedRequest; private ChannelOperationRequestStatus _selectedStatus; - private bool _hideApprove; - private bool _showRejectButton; - private bool _showCancelButton; - private bool _hidePendingRequests; - private bool _modalVisible; - private bool _rejectCancelModalVisible; private string? _psbt; private string? _templatePSBTString; private string? _cancelOrRejectReason; + private CancelOrRejectPopup _rejectCancelModalRef; private string? _selectedStatusActionString; - private bool _isSignedPSBTInvalid = true; - private Validation? _reasonValidation; + private bool _isFinanceManager = false; + private bool _isNodeManager = false; // New Request integration private List _allWallets = new List(); @@ -330,10 +322,10 @@ private long _amount = Constants.MINIMUM_CHANNEL_CAPACITY_SATS; //Validation - private Validation _walletValidation; - private Validation _sourceNodeValidation; - private Validation _destNodeValidation; - private Validation _capacityValidation; + private Validation? _walletValidation; + private Validation? _sourceNodeValidation; + private Validation? _destNodeValidation; + private Validation? _capacityValidation; private decimal _btcPrice; @@ -349,53 +341,44 @@ protected override async Task OnInitializedAsync() { - if (LoggedUser != null) + if (LoggedUser == null) return; + + _isFinanceManager = ClaimsPrincipal != null && ClaimsPrincipal.IsInRole(ApplicationUserRole.FinanceManager.ToString()); + _isNodeManager = ClaimsPrincipal != null && ClaimsPrincipal.IsInRole(ApplicationUserRole.NodeManager.ToString()); + + _btcPrice = PriceConversionHelper.GetBtcToUsdPrice(); + if (_btcPrice == 0) { - _btcPrice = PriceConversionHelper.GetBtcToUsdPrice(); - if (_btcPrice == 0) - { - ToastService.ShowError("Bitcoin price in USD could not be retrieved."); - } - await FetchRequests(); - await LoadData(); - if (ClaimsPrincipal != null && !ClaimsPrincipal.IsInRole(ApplicationUserRole.FinanceManager.ToString())) - { - _hideApprove = true; - _showCancelButton = true; - _hidePendingRequests = true; - } - else - { - _showRejectButton = true; - } + ToastService.ShowError("Bitcoin price in USD could not be retrieved."); } + await FetchRequests(); + await LoadData(); } private async Task ResetChannelRequestRejectModal() { - if (datagridRef != null) await datagridRef.Edit(null); + await datagridRef.Cancel(); _destNodeName = ""; _selectedDestNode = null; _amount = Constants.MINIMUM_CHANNEL_CAPACITY_SATS; } - private void ResetChannelCancelModal() + private async void ResetChannelCancelModal() { - _rejectCancelModalVisible = false; _cancelOrRejectReason = null; + await _rejectCancelModalRef.CloseModal(); } private async Task FetchRequests() { - if (LoggedUser != null) - { - _allRequests = await ChannelOperationRequestRepository.GetAll(); + if (LoggedUser == null) return; + + _allRequests = await ChannelOperationRequestRepository.GetAll(); - if (ClaimsPrincipal != null && ClaimsPrincipal.IsInRole(ApplicationUserRole.FinanceManager.ToString())) - { - _channelRequests = await ChannelOperationRequestRepository.GetUnsignedPendingRequestsByUser(LoggedUser.Id); - _allRequests = _allRequests.Except(_channelRequests).ToList(); - } + if (_isFinanceManager || _isNodeManager) + { + _channelRequests = await ChannelOperationRequestRepository.GetPendingRequests(); + _allRequests = _allRequests.Except(_channelRequests).ToList(); } } @@ -405,7 +388,7 @@ { if (LoggedUser != null) { - _manageableNodes = await NodeRepository.GetAllManagedByUser(LoggedUser.Id); + _manageableNodes = await NodeRepository.GetAll(); if (_selectedDestNode != null) { _manageableNodes = _manageableNodes.Where(node => node.Id != _selectedDestNode.Id).ToList(); @@ -456,8 +439,8 @@ } // Refresh the list of available source nodes and take out the one selected - _manageableNodes = await NodeRepository.GetAllManagedByUser(LoggedUser?.Id!); - _manageableNodes = _manageableNodes.Where(node => node.Id != _selectedDestNode.Id).ToList(); + _manageableNodes = await NodeRepository.GetAll(); + _manageableNodes = _manageableNodes.Where(node => node.Id != _selectedDestNode?.Id).ToList(); _destNodeValidation.Clear(); } } @@ -465,12 +448,13 @@ private async Task CreateChannelRequest() { - if ((int)_destNodeValidation.Validate() == 1 && - (int)_sourceNodeValidation.Validate() == 1 && - (int)_walletValidation.Validate() == 1 && - (int)_capacityValidation.Validate() == 1) + if (LoggedUser == null) return; + + Validation?[] validators = {_destNodeValidation, _sourceNodeValidation, _walletValidation, _capacityValidation}; + + if (validators.All(v => v != null && (int)v.Validate() == 1)) { - if (_selectedDestNode.Id != _selectedSourceNodeId) + if (_selectedDestNode?.Id != _selectedSourceNodeId) { ChannelOperationRequest request = new() { @@ -481,7 +465,7 @@ Status = ChannelOperationRequestStatus.Pending, //TODO Reject and cancel UserId = LoggedUser.Id, SourceNodeId = _selectedSourceNodeId, - DestNodeId = _selectedDestNode.Id + DestNodeId = _selectedDestNode?.Id }; var createChannelResult = await ChannelOperationRequestRepository.AddAsync(request); @@ -498,8 +482,8 @@ { ToastService.ShowError("The Source Node cannot be the same as the Destitation Node"); } + await ResetChannelRequestRejectModal(); } - await ResetChannelRequestRejectModal(); await LoadData(); await FetchRequests(); } @@ -517,16 +501,16 @@ return ResetChannelRequestRejectModal(); } - private void OpenModalForRejectOrCancelRequest(ChannelOperationRequest req, ChannelOperationRequestStatus status) + private async void OpenModalForRejectOrCancelRequest(ChannelOperationRequest req, ChannelOperationRequestStatus status) { _selectedRequest = req; _selectedStatus = status; - _rejectCancelModalVisible = true; switch(_selectedStatus) { case ChannelOperationRequestStatus.Rejected: _selectedStatusActionString = "Reject"; break; case ChannelOperationRequestStatus.Cancelled: _selectedStatusActionString = "Cancel"; break; } + await _rejectCancelModalRef.ShowModal(); } private async Task RejectOrCancelRequest() @@ -586,7 +570,7 @@ { _psbtSignRef?.HideModal(); - if (_selectedRequest == null || string.IsNullOrEmpty(_psbtSignRef.SignedPSBT) || LoggedUser == null) + if (_selectedRequest == null || string.IsNullOrEmpty(_psbtSignRef?.SignedPSBT) || LoggedUser == null) { ToastService.ShowError("Error: Not all fields were set"); } @@ -659,4 +643,15 @@ or ChannelOperationRequestStatus.Approved; } + private void RejectReasonValidator(ValidatorEventArgs e) + { + if (_selectedStatus == ChannelOperationRequestStatus.Rejected) + { + ValidationRule.IsNotEmpty(e); + } + else + { + ValidationRule.None(e); + } + } } \ No newline at end of file diff --git a/src/Pages/Channels.razor b/src/Pages/Channels.razor index 95682318..b63e8f51 100644 --- a/src/Pages/Channels.razor +++ b/src/Pages/Channels.razor @@ -147,7 +147,7 @@ if (LoggedUser != null) { _channels = await ChannelRepository.GetAll(); - if (ClaimsPrincipal != null && (ClaimsPrincipal.IsInRole(ApplicationUserRole.NodeManager.ToString()) || ClaimsPrincipal.IsInRole(ApplicationUserRole.Superadmin.ToString()))) + if (ClaimsPrincipal != null && ClaimsPrincipal.IsInRole(ApplicationUserRole.NodeManager.ToString())) { _hideDelete = false; } diff --git a/src/Pages/Wallets.razor b/src/Pages/Wallets.razor index a3c469c2..95bed1c1 100644 --- a/src/Pages/Wallets.razor +++ b/src/Pages/Wallets.razor @@ -4,7 +4,6 @@ @using NBitcoin @using NBXplorer.DerivationStrategy @using Key = FundsManager.Data.Models.Key -@using Helpers @inject IWalletRepository WalletRepository @inject IToastService ToastService @inject IApplicationUserRepository ApplicationUserRepository @@ -284,8 +283,14 @@ private async Task GetData() { - - _wallets = await WalletRepository.GetAll(); + if (ClaimsPrincipal != null && ClaimsPrincipal.IsInRole(ApplicationUserRole.FinanceManager.ToString())) + { + _wallets = await WalletRepository.GetAll(); + } + else + { + _wallets = await WalletRepository.GetAvailableWallets(); + } var financeManagers = (await ApplicationUserRepository.GetUsersInRole(ApplicationUserRole.FinanceManager)); _financeManagers = financeManagers.Where(x => x.Keys.Any()).ToList(); diff --git a/src/Pages/Withdrawals.razor b/src/Pages/Withdrawals.razor index 208a69aa..e2521c07 100644 --- a/src/Pages/Withdrawals.razor +++ b/src/Pages/Withdrawals.razor @@ -3,11 +3,8 @@ @using System.Security.Claims @using Quartz @using NBitcoin -@using System.Globalization @using FundsManager.Jobs - -@inject IToastService ToastService -@attribute [Authorize(Roles = "SuperAdmin,NodeManager,FinanceManager")] +@attribute [Authorize(Roles = "Superadmin,NodeManager,FinanceManager")] @if (_isFinanceManager) @@ -355,59 +352,40 @@ - - - - - - Wallet withdrawal: @_selectedRequest?.Id - - - - - - - Please type a reason before performing this operation - - - - - - - - - - - - - + + + -@code { - [Inject] - private IWalletWithdrawalRequestRepository WalletWithdrawalRequestRepository { get; set; } - - [Inject] - private IWalletWithdrawalRequestPsbtRepository WalletWithdrawalRequestPsbtRepository { get; set; } - - [Inject] - private IWalletRepository WalletRepository { get; set; } - - [Inject] - private IBitcoinService BitcoinService { get; set; } +@inject IToastService ToastService +@inject IWalletWithdrawalRequestRepository WalletWithdrawalRequestRepository +@inject IWalletWithdrawalRequestPsbtRepository WalletWithdrawalRequestPsbtRepository +@inject IWalletRepository WalletRepository +@inject IBitcoinService BitcoinService +@inject ISchedulerFactory SchedulerFactory - [Inject] - private ISchedulerFactory SchedulerFactory { get; set; } +@code { [CascadingParameter] private ApplicationUser? LoggedUser { get; set; } [CascadingParameter] - private ClaimsPrincipal ClaimsPrincipal { get; set; } + private ClaimsPrincipal? ClaimsPrincipal { get; set; } private List _userPendingRequests = new List(); private List _availableWallets = new List(); @@ -418,13 +396,12 @@ private WalletWithdrawalRequest? _selectedRequest; private PSBTSign? _psbtSignRef; - private string? _signedPSBT; + private string _signedPSBT; private string? _templatePsbtString; private string? _cancelOrRejectReason; - private Modal? _rejectCancelModalRef; + private CancelOrRejectPopup? _rejectCancelModalRef; private WalletWithdrawalRequestStatus? _rejectCancelStatus = WalletWithdrawalRequestStatus.Rejected; - private Validation? _rejectCancelValidation; private bool _isAmountDisabled; private decimal? _selectedRequestWalletBalance; @@ -434,26 +411,22 @@ protected override async Task OnInitializedAsync() { + if (LoggedUser == null) return; + _btcPrice = PriceConversionHelper.GetBtcToUsdPrice(); if (_btcPrice == 0) { ToastService.ShowError("Bitcoin price in USD could not be retrieved."); } - if (LoggedUser != null) - { - if (ClaimsPrincipal.IsInRole(ApplicationUserRole.FinanceManager.ToString())) - { - _isFinanceManager = true; - } - await GetData(); - } + _isFinanceManager = ClaimsPrincipal != null && ClaimsPrincipal.IsInRole(ApplicationUserRole.FinanceManager.ToString()); + await GetData(); } private async Task GetData() { if (LoggedUser?.Id != null) - _userPendingRequests = await WalletWithdrawalRequestRepository.GetUnsignedPendingRequestsByUser(LoggedUser?.Id); + _userPendingRequests = await WalletWithdrawalRequestRepository.GetUnsignedPendingRequestsByUser(LoggedUser.Id); _allRequests = (await WalletWithdrawalRequestRepository.GetAll()).Except(_userPendingRequests).ToList(); @@ -554,7 +527,7 @@ try { - BitcoinAddress.Create(str, CurrentNetworkHelper.GetCurrentNetwork()); + BitcoinAddress.Create(str!, CurrentNetworkHelper.GetCurrentNetwork()); } catch (Exception) { @@ -736,8 +709,7 @@ _cancelOrRejectReason = null; await GetData(); - if (_rejectCancelModalRef != null) - await _rejectCancelModalRef.Close(CloseReason.UserClosing); + await _rejectCancelModalRef.CloseModal(); } private async Task ShowRejectCancelModal(WalletWithdrawalRequest walletWithdrawalRequest, WalletWithdrawalRequestStatus walletWithdrawalRequestStatus) @@ -745,10 +717,7 @@ _rejectCancelStatus = walletWithdrawalRequestStatus; _selectedRequest = walletWithdrawalRequest; - if (_rejectCancelModalRef != null) - await _rejectCancelModalRef.Show(); - - + await _rejectCancelModalRef.ShowModal(); } @@ -764,6 +733,17 @@ _selectedRequestWalletBalance = balance; } - + } + + private void RejectReasonValidator(ValidatorEventArgs e) + { + if (_rejectCancelStatus == WalletWithdrawalRequestStatus.Rejected) + { + ValidationRule.IsNotEmpty(e); + } + else + { + ValidationRule.None(e); + } } } diff --git a/src/Shared/CancelOrRejectPopup.razor b/src/Shared/CancelOrRejectPopup.razor new file mode 100644 index 00000000..3cffece5 --- /dev/null +++ b/src/Shared/CancelOrRejectPopup.razor @@ -0,0 +1,56 @@ + + + + @Title + + + + + + + Please type a reason before performing this operation + + + + + + + + + + + + + + +@code { + [Parameter, EditorRequired] + public string Title { get; set; } = ""; + + [Parameter, EditorRequired] + public string Reason { get; set; } = ""; + + public Modal? _modalRef { get; set; } + private Validation? _reasonValidation; + + [Parameter, EditorRequired] + public Action Validator { get; set; } = ValidationRule.None; + + [Parameter, EditorRequired] + public EventCallback OnCancel { get; set; } + [Parameter, EditorRequired] + public EventCallback OnSubmit { get; set; } + + public async Task CloseModal() + { + await _modalRef.Close(CloseReason.UserClosing); + } + + public async Task ShowModal() + { + await _modalRef.Show(); + } +} \ No newline at end of file