8000 Check if founder has pending messages by dangershony · Pull Request #375 · block-core/angor · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Check if founder has pending messages #375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Angor/Client/Models/FounderProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class FounderProject : Project
{
public int ProjectIndex { get; set; }
public DateTime? LastRequestForSignaturesTime { get; set; }
public DateTime? LastRequestForMessagesTime { get; set; }

public string ProjectInfoEventId { get; set; }
public bool NostrProfileCreated { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions src/Angor/Client/Models/InvestorProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class InvestorProject : Project

public string AdditionalNpub { get; set; }

public DateTime? LastRequestForMessagesTime { get; set; }

public bool WaitingForFounderResponse()
{
return ReceivedFounderSignatures() == false && SignaturesInfo?.TimeOfSignatureRequest != null;
Expand Down
39 changes: 38 additions & 1 deletion src/Angor/Client/Pages/Invest.razor
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,14 @@ else
</button>
<button class="btn btn-border-success ms-2" @>
<Icon IconName="chat" Width="16" Height="16" class="me-1" />
<span class="button-text ms-2">Message</span>
@if (hasMessges)
{
<span class="button-text ms-2">Pending Message</span>
}
else
{
<span class="button-text ms-2">Message</span>
}
</button>
</div>
</div>
Expand Down Expand Up @@ -631,6 +638,8 @@ else
if (passwordComponent.HasPassword())
{
await ScanForPendingSignatures();

await ScanForDmMessages();
}
else
{
Expand Down Expand Up @@ -1275,6 +1284,10 @@ else
var words = await passwordComponent.GetWalletAsync();
var investorNostrPrivateKey = _derivationOperations.DeriveProjectNostrPrivateKey(words, project.ProjectInfo.FounderKey);
currentUserPrivateKeyHex = Encoders.Hex.EncodeData(investorNostrPrivateKey.ToBytes());
hasMessges = false;
var investorProject = project as InvestorProject;
investorProject.LastRequestForMessagesTime = DateTime.UtcNow;
storage.UpdateInvestmentProject(investorProject);
StateHasChanged();
}
catch (Exception ex)
Expand Down Expand Up @@ -1321,4 +1334,28 @@ else
}
}

bool hasMessges = false;

protected async Task ScanForDmMessages()
{
if (project is InvestorProject)
{
var investorProject = project as InvestorProject;

await _RelayService.LookupDirectMessagesForPubKeyAsync(
investorProject.InvestorNPub,
investorProject.LastRequestForMessagesTime?.AddSeconds(1),
1,
_ =>
{
if (!string.IsNullOrEmpty(_.Pubkey))
{
hasMessges = true;
InvokeAsync(StateHasChanged);
}

return Task.CompletedTask;
}, new[] { project.ProjectInfo.NostrPubKey });
}
}
}
43 changes: 42 additions & 1 deletion src/Angor/Client/Pages/Investor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@using Angor.Shared
@using Angor.Shared.Services
@using Blockcore.NBitcoin.DataEncoders
@using Nostr.Client.Messages.Direct

@inject ILogger<Investor> _Logger
@inject NavMenuState NavMenuState
Expand Down Expand Up @@ -259,6 +260,21 @@
}
</div>
</div>

<div class="stat-row">
<span class="stat-label">Messages</span>
<div class="stat-value-group">
@if (pubkeyWithMessages.Contains(project.InvestorNPub))
{
<span class="status-badge status-success">Pending Messages</span>
}
else
{
<span class="status-badge status-inactive">None</span>
}
</div>
</div>

</div>
<div class="project-actions d-flex flex-column flex-lg-row gap-2">
@if (hasInvestmentReleaseRequests && project.UnfundedReleaseTransactionId == null)
Expand Down Expand Up @@ -335,6 +351,7 @@
var refreshTask = RefreshBalance();
CheckSignatureFromFounder();
CheckReleaseFromFounder();
await ScanForDmMessages();
await refreshTask;
}
}
Expand Down Expand Up @@ -504,7 +521,7 @@
{
_Logger.LogError(e, "failed to get handle investment list event from relay");
}
}, storageAccountKey);
}, new[] { storageAccountKey });
}

//TODO David check if we should replace the logic to get all projects first and then get signatures for them?
Expand Down Expand Up @@ -630,5 +647,29 @@
NavigationManager.NavigateTo("/penalties");
}

HashSet<string> pubkeyWithMessages = new();

protected async Task ScanForDmMessages()
{
foreach (var project in projects)
{
if (!pubkeyWithMessages.Contains(project.InvestorNPub))
{
await _RelayService.LookupDirectMessagesForPubKeyAsync(
project.InvestorNPub,
project.LastRequestForMessagesTime?.AddSeconds(1),
1,
_ =>
{
NostrEncryptedEvent nostrEncryptedEvent = (NostrEncryptedEvent)_;
if (!string.IsNullOrEmpty(nostrEncryptedEvent.RecipientPubkey))
{
pubkeyWithMessages.Add(nostrEncryptedEvent.RecipientPubkey);
InvokeAsync(StateHasChanged);
}
return Task.CompletedTask;
}, new[] { project.ProjectInfo.NostrPubKey });
}
}
}
}
38 changes: 37 additions & 1 deletion src/Angor/Client/Pages/Recover.razor
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
@inject NavMenuState NavMenuState
@inject IJSRuntime JS
@inject NostrConversionHelper NostrHelper
@inject IRelayService _RelayService

@inherits BaseComponent

Expand Down Expand Up @@ -64,7 +65,14 @@
</button>
<button class="btn btn-border-success ms-2" @ title="Message">
<Icon IconName="chat" Width="24" Height="24" />
<span class="button-text ms-2">Message</span>
@if (hasMessges)
{
<span class="button-text ms-2">Pending Message</span>
}
else
{
<span class="button-text ms-2">Message</span>
}
</button>
</div>
</div>
Expand Down Expand Up @@ -643,6 +651,8 @@
await FindInvestments();

await CheckSpentFund();

await ScanForDmMessages();
}
catch (Exception e)
{
Expand Down Expand Up @@ -1324,6 +1334,9 @@
var words = await passwordComponent.GetWalletAsync();
var privateKey = _derivationOperations.DeriveProjectNostrPrivateKey(words, project.ProjectInfo.FounderKey);
currentUserPrivateKeyHex = Encoders.Hex.EncodeData(privateKey.ToBytes());
hasMessges = false;
project.LastRequestForMessagesTime = DateTime.UtcNow;
storage.UpdateInvestmentProject(project);
StateHasChanged();
}
catch (Exception ex)
Expand Down Expand Up @@ -1375,4 +1388,27 @@
notificationComponent.ShowErrorMessage("Failed to retrieve NSEC: " + e.Message);
}
}

bool hasMessges = false;

protected async Task ScanForDmMessages()
{
if (project != null)
{
await _RelayService.LookupDirectMessagesForPubKeyAsync(
project.InvestorNPub ,
project.LastRequestForMessagesTime?.AddSeconds(1),
1,
_ =>
{
if (!string.IsNullOrEmpty(_.Pubkey))
{
hasMessges = true;
InvokeAsync(StateHasChanged);
}

return Task.CompletedTask;
}, new[] { project.ProjectInfo.NostrPubKey });
}
}
}
48 changes: 45 additions & 3 deletions src/Angor/Client/Pages/Signatures.razor
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
@inject ILogger<Signatures> Logger
@inject IDerivationOperations DerivationOperations
@inject IClientStorage Storage;
@inject ICacheStorage SessionStorage;
@inject ISignService SignService
@inject IInvestorTransactionActions InvestorTransactionActions
@inject IFounderTransactionActions FounderTransactionActions
Expand Down Expand Up @@ -212,7 +213,15 @@
<button class="btn btn-sm btn-border-success animate-scale"
@ => ShowMessageModal(signature.investorNostrPubKey)"
aria-label="Message investor">
<Icon IconName="chat" Width="16" Height="16" Class="me-1" />
@if (pubkeyWithMessages.Contains(signature.investorNostrPubKey))
{
<Icon IconName="chat" Width="16" Height="16" Class="me-1" />
<p>Has messages</p>
}
else
{
<Icon IconName="chat" Width="16" Height="16" Class="me-1" />
}
</button>
<span class="animate-scale"
@ => ToggleAccordion(accordionId)"
Expand Down Expand Up @@ -353,7 +362,7 @@
await FetchPendingSignatures(FounderProject);

investments = await indexerService.GetInvestmentsAsync(FounderProject.ProjectInfo.ProjectIdentifier);

}
Logger.LogDebug("End of OnInitializedAsync");
}
Expand Down Expand Up @@ -527,6 +536,8 @@
() =>
{
Logger.LogDebug($"End of messages");

ScanForDmMessages();

if (!messagesReceived)
return;
Expand Down Expand Up @@ -758,6 +769,14 @@
// Get founder's npub
founderNpub = NostrHelper.ConvertHexToNpub(FounderProject.ProjectInfo.NostrPubKey) ??
FounderProject.ProjectInfo.NostrPubKey;

// Remove this npub from the HashSet of pubkeys with messages
pubkeyWithMessages.Remove(investorNostrPubKey);

var lastScanList = SessionStorage.GetFounderMessagesTimes();
lastScanList[investorNostrPubKey] = DateTime.UtcNow;
SessionStorage.SetFounderMessagesTimes(lastScanList);

// Show Message
ShowMessageAndCheckPassword();
}
Expand Down Expand Up @@ -786,7 +805,6 @@
var words = await passwordComponent.GetWalletAsync();
var founderNostrPrivateKey = DerivationOperations.DeriveProjectNostrPrivateKey(words, FounderProject.ProjectInfo.FounderKey);
currentUserPrivateKeyHex = Encoders.Hex.EncodeData(founderNostrPrivateKey.ToBytes());

StateHasChanged();
}
catch (Exception ex)
Expand Down Expand Up @@ -844,6 +862,30 @@
}
}

HashSet<string> pubkeyWithMessages = new();

protected async Task ScanForDmMessages()
{
var lastScanList = SessionStorage.GetFounderMessagesTimes();

foreach (var signatureRequest in signaturesRequests)
{
await _RelayService.LookupDirectMessagesForPubKeyAsync(
FounderProject.ProjectInfo.NostrPubKey,
lastScanList.TryGet(signatureRequest.investorNostrPubKey)?.AddSeconds(1),
1,
_ =>
{
if (!string.IsNullOrEmpty(_.Pubkey))
{
pubkeyWithMessages.Add(_.Pubkey);
}
return Task.CompletedTask;
}, new[] { signatureRequest.investorNostrPubKey });

}
}

private string GetShortenedNpub(string npub)
{
if (string.IsNullOrEmpty(npub) || npub.Length <= 20) return npub;
Expand Down
4 changes: 2 additions & 2 deletions src/Angor/Client/Services/MessageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ await _relayService.LookupDirectMessagesForPubKeyAsync(
_sinceTime,
100,
async eventMessage => await ProcessDirectMessage(eventMessage),
_otherUserHexPub,
new [] { _otherUserHexPub },
true
);

Expand All @@ -135,7 +135,7 @@ await _relayService.LookupDirectMessagesForPubKeyAsync(
_sinceTime,
100,
async eventMessage => await ProcessDirectMessage(eventMessage),
_currentUserHexPub,
new [] { _currentUserHexPub },
true
);

Expand Down
2 changes: 2 additions & 0 deletions src/Angor/Client/Storage/ICacheStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ public interface ICacheStorage
void SetCurrencyRate(string currencyCode, RateCacheEntry rateCacheEntry);
RateCacheEntry? GetCurrencyRate(string currencyCode);
void WipeSession();
void SetFounderMessagesTimes(Dictionary<string, DateTime?> dictionary);
Dictionary<string, DateTime?> GetFounderMessagesTimes();
}
13 changes: 13 additions & 0 deletions src/Angor/Client/Storage/LocalSessionStorage.cs
47C5
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Reactive;
using System.Text.Json;
using Angor.Client.Models;
using Angor.Client.Services;
Expand All @@ -12,6 +13,7 @@ public class LocalSessionStorage : ICacheStorage
private const string BrowseIndexerData = "subscriptions";
private const string NostrPubKeyMapping = "NostrPubKeyMapping";
private const string ActiveMenuPageKey = "activeMenuPage";
private const string FounderRequestForMessagesTime = "FounderRequestForMessagesTime";
private readonly ISyncSessionStorageService _sessionStorageService;

public LocalSessionStorage(ISyncSessionStorageService sessionStorageService)
Expand Down Expand Up @@ -136,4 +138,15 @@ public List<string> GetNamesOfCommunicatorsThatReceivedEose(string subscriptionN
return _sessionStorageService.GetItem<List<string>>("Eose" + subscriptionName);
}

public void SetFounderMessagesTimes(Dictionary<string, DateTime?> dictionary)
{
_sessionStorageService.SetItem(FounderRequestForMessagesTime, dictionary);
}

public Dictionary<string, DateTime?> GetFounderMessagesTimes()
{
var dictionary = _sessionStorageService.GetItem<Dictionary<string, DateTime?>>(FounderRequestForMessagesTime);

return dictionary ?? new Dictionary<string, DateTime?>();
}
}
2 changes: 1 addition & 1 deletion src/Angor/Shared/Services/IRelayService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface IRelayService

Task LookupSignaturesDirectMessagesForPubKeyAsync(string nostrPubKey, DateTime? since, int? limit, Action<NostrEvent> onResponseAction);

Task LookupDirectMessagesForPubKeyAsync(string nostrPubKey, DateTime? since, int? limit, Func<NostrEvent,Task> onResponseAction, string? fromNpub = null, bool keepActive = false);
Task LookupDirectMessagesForPubKeyAsync(string nostrPubKey, DateTime? since, int? limit, Func<NostrEvent,Task> onResponseAction, string[]? sendersPubkey = null, bool keepActive = false);

string SendDirectMessagesForPubKeyAsync(string senderNosterPrivateKey, string nostrPubKey, string encryptedMessage,
Action<NostrOkResponse> onResponseAction);
Expand Down
Loading
Loading
0