Skip to content

Commit 5c812e7

Browse files
PIG208gnprice
authored andcommitted
channel: Maintain maps consistently when removing subscriptions
When a subscription is removed, the data in streams and streamsByName are left as instances of `Subscription`. This is inconsistent with the data store's assumption that unsubscribed channels should have plain `ZulipStream` instances. This doesn't seem to have user-facing effects, though. The assertion errors only affect debug builds. CZO discussion: https://chat.zulip.org/#narrow/channel/48-mobile/topic/Unsubscribe.20then.20resubscribe.20to.20channel/with/2160241
1 parent 2739149 commit 5c812e7

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

lib/api/model/model.dart

+18
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,24 @@ class ZulipStream {
363363
required this.streamWeeklyTraffic,
364364
});
365365

366+
/// Construct a plain [ZulipStream] from [subscription].
367+
factory ZulipStream.fromSubscription(Subscription subscription) {
368+
return ZulipStream(
369+
streamId: subscription.streamId,
370+
name: subscription.name,
371+
description: subscription.description,
372+
renderedDescription: subscription.renderedDescription,
373+
dateCreated: subscription.dateCreated,
374+
firstMessageId: subscription.firstMessageId,
375+
inviteOnly: subscription.inviteOnly,
376+
isWebPublic: subscription.isWebPublic,
377+
historyPublicToSubscribers: subscription.historyPublicToSubscribers,
378+
messageRetentionDays: subscription.messageRetentionDays,
379+
channelPostPolicy: subscription.channelPostPolicy,
380+
streamWeeklyTraffic: subscription.streamWeeklyTraffic,
381+
);
382+
}
383+
366384
factory ZulipStream.fromJson(Map<String, dynamic> json) =>
367385
_$ZulipStreamFromJson(json);
368386

lib/model/channel.dart

+10-1
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,16 @@ class ChannelStoreImpl with ChannelStore {
301301

302302
case SubscriptionRemoveEvent():
303303
for (final streamId in event.streamIds) {
304-
subscriptions.remove(streamId);
304+
assert(streams.containsKey(streamId));
305+
assert(streams[streamId] is Subscription);
306+
assert(streamsByName.containsKey(streams[streamId]!.name));
307+
assert(streamsByName[streams[streamId]!.name] is Subscription);
308+
assert(subscriptions.containsKey(streamId));
309+
final subscription = subscriptions.remove(streamId);
310+
if (subscription == null) continue; // TODO(log)
311+
final stream = ZulipStream.fromSubscription(subscription);
312+
streams[streamId] = stream;
313+
streamsByName[subscription.name] = stream;
305314
}
306315

307316
case SubscriptionUpdateEvent():

test/model/channel_test.dart

+17
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,23 @@ void main() {
6868
));
6969
checkUnified(store);
7070
});
71+
72+
test('unsubscribed then subscribed by events', () async {
73+
// Regression test for: https://chat.zulip.org/#narrow/channel/48-mobile/topic/Unsubscribe.20then.20resubscribe.20to.20channel/with/2160241
74+
final stream = eg.stream();
75+
final store = eg.store();
76+
await store.addStream(stream);
77+
await store.addSubscription(eg.subscription(stream));
78+
checkUnified(store);
79+
80+
await store.handleEvent(SubscriptionRemoveEvent(id: 1,
81+
streamIds: [stream.streamId]));
82+
checkUnified(store);
83+
84+
await store.handleEvent(SubscriptionAddEvent(id: 1,
85+
subscriptions: [eg.subscription(stream)]));
86+
checkUnified(store);
87+
});
7188
});
7289

7390
group('SubscriptionEvent', () {

0 commit comments

Comments
 (0)