feat(social): local blocklist — hide blocked authors' offers, chats and incoming messages, with unblock management
This commit is contained in:
parent
5d25f65f76
commit
11b242edbf
13 changed files with 399 additions and 4 deletions
|
|
@ -61,6 +61,23 @@ void main() {
|
|||
text: text,
|
||||
at: DateTime.fromMillisecondsSinceEpoch(atMs));
|
||||
|
||||
test('messages from a blocked peer are dropped before storage', () async {
|
||||
final settings = SocialSettings(InMemorySecretStore());
|
||||
await settings.block('mallory');
|
||||
inbox = InboxService(
|
||||
connection: await offlineConnection(),
|
||||
selfPubkey: 'me',
|
||||
store: store,
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
await inbox.ingest(msg('mallory', 'spam', 1000));
|
||||
await inbox.ingest(msg('alice', 'hola', 2000));
|
||||
|
||||
final convos = await store.conversations();
|
||||
expect(convos.single.peerPubkey, 'alice'); // mallory never landed
|
||||
});
|
||||
|
||||
test('an incoming message is persisted into its conversation', () async {
|
||||
await inbox.ingest(msg('alice', 'got seeds?', 1000));
|
||||
final convos = await store.conversations();
|
||||
|
|
|
|||
|
|
@ -71,4 +71,25 @@ void main() {
|
|||
await store.write('tane.social.search_precision', 'oops');
|
||||
expect(await SocialSettings(store).searchPrecision(), 4);
|
||||
});
|
||||
|
||||
test('the blocklist starts empty and round-trips block/unblock', () async {
|
||||
expect(await settings.blockedPubkeys(), isEmpty);
|
||||
|
||||
await settings.block('AB' * 32);
|
||||
expect(await settings.isBlocked('ab' * 32), isTrue); // normalised
|
||||
expect(await settings.blockedPubkeys(), {'ab' * 32});
|
||||
|
||||
await settings.block('cd' * 32);
|
||||
expect(await settings.blockedPubkeys(), hasLength(2));
|
||||
|
||||
await settings.unblock('ab' * 32);
|
||||
expect(await settings.isBlocked('ab' * 32), isFalse);
|
||||
expect(await settings.blockedPubkeys(), {'cd' * 32});
|
||||
});
|
||||
|
||||
test('blocking twice keeps a single entry', () async {
|
||||
await settings.block('ab' * 32);
|
||||
await settings.block(' AB' * 1 + 'ab' * 31); // messy spacing/case
|
||||
expect(await settings.blockedPubkeys(), hasLength(1));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,6 +184,42 @@ void main() {
|
|||
await cubit.close();
|
||||
});
|
||||
|
||||
test('blocked authors disappear from the visible list and can resurface',
|
||||
() async {
|
||||
final transport = FakeOfferTransport();
|
||||
await transport.publish(OfferMapper.fromSharedLot(
|
||||
lotId: 'lot-good',
|
||||
authorPubkeyHex: 'ab' * 32,
|
||||
summary: 'Tomate rosa',
|
||||
sharing: OfferStatus.shared,
|
||||
areaGeohash: 'sp3e9',
|
||||
));
|
||||
await transport.publish(OfferMapper.fromSharedLot(
|
||||
lotId: 'lot-spam',
|
||||
authorPubkeyHex: 'cd' * 32,
|
||||
summary: 'Spam total',
|
||||
sharing: OfferStatus.shared,
|
||||
areaGeohash: 'sp3e9',
|
||||
));
|
||||
final cubit = OffersCubit(transport);
|
||||
await cubit.discover('sp3');
|
||||
await pumpEventQueue();
|
||||
expect(cubit.state.visibleOffers, hasLength(2));
|
||||
|
||||
cubit.setBlockedAuthors({'cd' * 32});
|
||||
expect(cubit.state.visibleOffers.map((o) => o.summary), ['Tomate rosa']);
|
||||
expect(cubit.state.offers, hasLength(2)); // discoveries kept underneath
|
||||
|
||||
// The blocklist survives a refresh (re-discovery resets results only).
|
||||
await cubit.discover('sp3');
|
||||
await pumpEventQueue();
|
||||
expect(cubit.state.visibleOffers.map((o) => o.summary), ['Tomate rosa']);
|
||||
|
||||
cubit.setBlockedAuthors(const {}); // unblock resurfaces
|
||||
expect(cubit.state.visibleOffers, hasLength(2));
|
||||
await cubit.close();
|
||||
});
|
||||
|
||||
test('the search filter survives a refresh (re-discovery)', () async {
|
||||
final transport = FakeOfferTransport();
|
||||
await transport.publish(OfferMapper.fromSharedLot(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue