Skip to content

Commit 9770b16

Browse files
committed
compose: Don't show compose box for private, unsubscribed channels
1 parent 842e70d commit 9770b16

File tree

2 files changed

+95
-4
lines changed

2 files changed

+95
-4
lines changed

lib/widgets/compose_box.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,8 +2064,12 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
20642064
case ChannelNarrow(:final streamId):
20652065
case TopicNarrow(:final streamId):
20662066
final channel = store.streams[streamId];
2067-
if (channel == null || !store.hasPostingPermission(inChannel: channel,
2068-
user: store.selfUser, byDate: DateTime.now())) {
2067+
if (
2068+
channel == null
2069+
|| (channel.inviteOnly && channel is! Subscription)
2070+
|| !store.hasPostingPermission(inChannel: channel,
2071+
user: store.selfUser, byDate: DateTime.now())
2072+
) {
20692073
return _ErrorBanner(getLabel: (zulipLocalizations) =>
20702074
zulipLocalizations.errorBannerCannotPostInChannelLabel);
20712075
}

test/widgets/compose_box_test.dart

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ void main() {
5858
User? selfUser,
5959
List<User> otherUsers = const [],
6060
List<ZulipStream> streams = const [],
61+
List<Subscription> subscriptions = const [],
6162
List<Message>? messages,
6263
bool? mandatoryTopics,
6364
int? zulipFeatureLevel,
@@ -81,6 +82,7 @@ void main() {
8182
await testBinding.globalStore.add(selfAccount, eg.initialSnapshot(
8283
realmUsers: [selfUser, ...otherUsers],
8384
streams: streams,
85+
subscriptions: subscriptions,
8486
zulipFeatureLevel: zulipFeatureLevel,
8587
realmMandatoryTopics: mandatoryTopics,
8688
realmAllowMessageEditing: true,
@@ -1281,7 +1283,7 @@ void main() {
12811283
});
12821284
});
12831285

1284-
group('in channel/topic narrow according to channel post policy', () {
1286+
group('in channel/topic narrow according to channel post policy and privacy/subscribed', () {
12851287
void checkComposeBox({required bool isShown}) => checkComposeBoxIsShown(isShown,
12861288
bannerLabel: zulipLocalizations.errorBannerCannotPostInChannelLabel);
12871289

@@ -1300,14 +1302,25 @@ void main() {
13001302
checkComposeBox(isShown: true);
13011303
});
13021304

1303-
testWidgets('error banner is shown in $narrowType narrow', (tester) async {
1305+
testWidgets('error banner is shown in $narrowType narrow without posting permission', (tester) async {
13041306
await prepareComposeBox(tester,
13051307
narrow: narrow,
13061308
selfUser: eg.user(role: UserRole.moderator),
13071309
streams: [eg.stream(streamId: 1,
13081310
channelPostPolicy: ChannelPostPolicy.administrators)]);
13091311
checkComposeBox(isShown: false);
13101312
});
1313+
1314+
testWidgets('error banner is shown in $narrowType when private and unsubscribed', (tester) async {
1315+
await prepareComposeBox(tester,
1316+
narrow: narrow,
1317+
selfUser: eg.user(role: UserRole.moderator),
1318+
streams: [eg.stream(streamId: 1,
1319+
channelPostPolicy: ChannelPostPolicy.any,
1320+
inviteOnly: true)]);
1321+
check(store.subscriptions[1]).isNull();
1322+
checkComposeBox(isShown: false);
1323+
});
13111324
}
13121325

13131326
testWidgets('user loses privilege -> compose box is replaced with the banner', (tester) async {
@@ -1375,6 +1388,80 @@ void main() {
13751388
await tester.pump();
13761389
checkComposeBox(isShown: true);
13771390
});
1391+
1392+
testWidgets('unsubscribed private channel becomes public -> banner is replaced with the compose box', (tester) async {
1393+
final selfUser = eg.user(role: UserRole.moderator);
1394+
final channel = eg.stream(streamId: 1, inviteOnly: true,
1395+
channelPostPolicy: ChannelPostPolicy.any);
1396+
1397+
await prepareComposeBox(tester,
1398+
narrow: const ChannelNarrow(1),
1399+
selfUser: selfUser,
1400+
streams: [channel]);
1401+
check(store.subscriptions[1]).isNull();
1402+
checkComposeBox(isShown: false);
1403+
1404+
await store.handleEvent(eg.channelUpdateEvent(channel,
1405+
property: ChannelPropertyName.inviteOnly,
1406+
value: false));
1407+
await tester.pump();
1408+
checkComposeBox(isShown: true);
1409+
});
1410+
1411+
testWidgets('unsubscribed public channel becomes private -> compose box is replaced with the banner', (tester) async {
1412+
final selfUser = eg.user(role: UserRole.moderator);
1413+
final channel = eg.stream(streamId: 1, inviteOnly: false,
1414+
channelPostPolicy: ChannelPostPolicy.any);
1415+
1416+
await prepareComposeBox(tester,
1417+
narrow: const ChannelNarrow(1),
1418+
selfUser: selfUser,
1419+
streams: [channel]);
1420+
check(store.subscriptions[1]).isNull();
1421+
checkComposeBox(isShown: true);
1422+
1423+
await store.handleEvent(eg.channelUpdateEvent(channel,
1424+
property: ChannelPropertyName.inviteOnly,
1425+
value: true));
1426+
await tester.pump();
1427+
checkComposeBox(isShown: false);
1428+
});
1429+
1430+
testWidgets('unsubscribed private channel becomes subscribed -> banner is replaced with the compose box', (tester) async {
1431+
final selfUser = eg.user(role: UserRole.moderator);
1432+
final channel = eg.stream(streamId: 1, inviteOnly: true,
1433+
channelPostPolicy: ChannelPostPolicy.any);
1434+
1435+
await prepareComposeBox(tester,
1436+
narrow: const ChannelNarrow(1),
1437+
selfUser: selfUser,
1438+
streams: [channel]);
1439+
check(store.subscriptions[1]).isNull();
1440+
checkComposeBox(isShown: false);
1441+
1442+
await store.handleEvent(SubscriptionAddEvent(id: 1,
1443+
subscriptions: [eg.subscription(channel)]));
1444+
await tester.pump();
1445+
checkComposeBox(isShown: true);
1446+
});
1447+
1448+
testWidgets('subscribed private channel becomes unsubscribed -> compose box is replaced with the banner', (tester) async {
1449+
final selfUser = eg.user(role: UserRole.moderator);
1450+
final channel = eg.stream(streamId: 1, inviteOnly: true,
1451+
channelPostPolicy: ChannelPostPolicy.any);
1452+
1453+
await prepareComposeBox(tester,
1454+
narrow: const ChannelNarrow(1),
1455+
selfUser: selfUser,
1456+
streams: [channel],
1457+
subscriptions: [eg.subscription(channel)]);
1458+
checkComposeBox(isShown: true);
1459+
1460+
await store.handleEvent(SubscriptionRemoveEvent(id: 1,
1461+
streamIds: [channel.streamId]));
1462+
await tester.pump();
1463+
checkComposeBox(isShown: false);
1464+
});
13781465
});
13791466
});
13801467

0 commit comments

Comments
 (0)