Skip to content

Commit 68d019d

Browse files
authored
Merge pull request #279 from relaystr/broadcast-deletion-upgrade
Broadcast deletion upgrade (delete multiple ids)
2 parents 36a43c3 + 0f4ffff commit 68d019d

4 files changed

Lines changed: 109 additions & 7 deletions

File tree

packages/ndk/lib/domain_layer/usecases/broadcast/broadcast.dart

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,25 +106,40 @@ class Broadcast {
106106

107107
/// request a deletion of an event \
108108
/// [eventId] event you want to delete \
109+
/// [eventIds] events you want to delete \
109110
/// [customRelays] relay URls to send the deletion request to specific relays \
110111
/// [customSigner] if you want to use a different signer than the default specified in [NdkConfig]
111112
NdkBroadcastResponse broadcastDeletion({
112-
required String eventId,
113+
String? eventId,
114+
List<String>? eventIds,
113115
Iterable<String>? customRelays,
114116
EventSigner? customSigner,
117+
String reason = "delete",
115118
}) {
116119
final EventSigner mySigner = _checkSinger(customSigner: customSigner);
117120

121+
List<String> idsToDelete = [];
122+
if (eventId != null) {
123+
idsToDelete.add(eventId);
124+
}
125+
if (eventIds != null) {
126+
idsToDelete.addAll(eventIds);
127+
}
128+
129+
if (idsToDelete.isEmpty) {
130+
throw ArgumentError("At least one eventId must be provided for deletion.");
131+
}
132+
118133
Nip01Event event = Nip01Event(
119134
pubKey: mySigner.getPublicKey(),
120135
kind: Deletion.kKind,
121-
tags: [
122-
["e", eventId]
123-
],
124-
content: "delete",
136+
tags: idsToDelete.map((e) => ["e", e]).toList(),
137+
content: reason,
125138
createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000);
126139
// TODO not bulletproof, think of better way
127-
_cacheManager.removeEvent(eventId);
140+
for (final id in idsToDelete) {
141+
_cacheManager.removeEvent(id);
142+
}
128143
return broadcast(
129144
nostrEvent: event,
130145
specificRelays: customRelays,

packages/ndk/test/mocks/mock_relay.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,10 @@ class MockRelay {
137137
} else if (newEvent.kind == Metadata.kKind) {
138138
_metadatas[newEvent.pubKey] = newEvent;
139139
} else if (newEvent.kind == Deletion.kKind) {
140-
_storedEvents.removeWhere((e) => newEvent.getEId() == e.id);
140+
final eventIdsToDelete = newEvent.getTags("e");
141+
for (final idToDelete in eventIdsToDelete) {
142+
_storedEvents.removeWhere((e) => idToDelete == e.id);
143+
}
141144
} else if (newEvent.kind == kNip46Kind) {
142145
// Handle NIP-46 remote signer request
143146
_handleNip46Request(newEvent, webSocket);

packages/ndk/test/usecases/broadcast_jit_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,48 @@ void main() async {
103103
expect(list, isEmpty);
104104
});
105105

106+
test('broadcast deletion', () async {
107+
ndk.accounts
108+
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);
109+
Nip01Event event1 = Nip01Event(
110+
pubKey: key0.publicKey,
111+
kind: Nip01Event.kTextNodeKind,
112+
tags: [],
113+
content: "1");
114+
Nip01Event event2 = Nip01Event(
115+
pubKey: key0.publicKey,
116+
kind: Nip01Event.kTextNodeKind,
117+
tags: [],
118+
content: "2");
119+
NdkBroadcastResponse response1 =
120+
ndk.broadcast.broadcast(nostrEvent: event1);
121+
await response1.broadcastDoneFuture;
122+
NdkBroadcastResponse response2 =
123+
ndk.broadcast.broadcast(nostrEvent: event2);
124+
await response2.broadcastDoneFuture;
125+
126+
List<Nip01Event> list = await ndk.requests.query(filters: [
127+
Filter(authors: [event1.pubKey], kinds: [Nip01Event.kTextNodeKind])
128+
]).future;
129+
130+
response1 = ndk.broadcast.broadcastDeletion(eventIds: [event1.id, event2.id]);
131+
await response1.broadcastDoneFuture;
132+
133+
list = await ndk.requests.query(filters: [
134+
Filter(authors: [event1.pubKey], kinds: [Nip01Event.kTextNodeKind])
135+
]).future;
136+
expect(list, isEmpty);
137+
});
138+
139+
test('broadcast deletion with empty eventIds throws ArgumentError', () async {
140+
ndk.accounts
141+
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);
142+
expect(
143+
() => ndk.broadcast.broadcastDeletion(eventIds: []),
144+
throwsA(isA<ArgumentError>()),
145+
);
146+
});
147+
106148
test('broadcast reaction', () async {
107149
ndk.accounts
108150
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);

packages/ndk/test/usecases/broadcast_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,39 @@ void main() async {
105105
expect(list, isEmpty);
106106
});
107107

108+
test('broadcast deletion 2', () async {
109+
ndk.accounts
110+
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);
111+
Nip01Event event1 = Nip01Event(
112+
pubKey: key0.publicKey,
113+
kind: Nip01Event.kTextNodeKind,
114+
tags: [],
115+
content: "1");
116+
Nip01Event event2 = Nip01Event(
117+
pubKey: key0.publicKey,
118+
kind: Nip01Event.kTextNodeKind,
119+
tags: [],
120+
content: "2");
121+
NdkBroadcastResponse response1 =
122+
ndk.broadcast.broadcast(nostrEvent: event1);
123+
await response1.broadcastDoneFuture;
124+
NdkBroadcastResponse response2 =
125+
ndk.broadcast.broadcast(nostrEvent: event2);
126+
await response2.broadcastDoneFuture;
127+
128+
List<Nip01Event> list = await ndk.requests.query(filters: [
129+
Filter(authors: [event1.pubKey], kinds: [Nip01Event.kTextNodeKind])
130+
]).future;
131+
132+
response1 = ndk.broadcast.broadcastDeletion(eventIds: [event1.id, event2.id]);
133+
await response1.broadcastDoneFuture;
134+
135+
list = await ndk.requests.query(filters: [
136+
Filter(authors: [event1.pubKey], kinds: [Nip01Event.kTextNodeKind])
137+
]).future;
138+
expect(list, isEmpty);
139+
});
140+
108141
test('broadcast reaction', () async {
109142
ndk.accounts
110143
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);
@@ -133,6 +166,15 @@ void main() async {
133166
expect(list.first.content, reaction);
134167
});
135168

169+
test('broadcast deletion with empty eventIds throws ArgumentError', () async {
170+
ndk.accounts
171+
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);
172+
expect(
173+
() => ndk.broadcast.broadcastDeletion(eventIds: []),
174+
throwsA(isA<ArgumentError>()),
175+
);
176+
});
177+
136178
test('broadcast respects timeout parameter', () async {
137179
ndk.accounts
138180
.loginPrivateKey(pubkey: key0.publicKey, privkey: key0.privateKey!);

0 commit comments

Comments
 (0)