Skip to content

Commit

Permalink
compose: Respect realm setting for mandatory topics
Browse files Browse the repository at this point in the history
Signed-off-by: Zixuan James Li <[email protected]>
  • Loading branch information
PIG208 committed Jan 23, 2025
1 parent b977a1b commit f0dccf5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 14 deletions.
33 changes: 20 additions & 13 deletions lib/widgets/compose_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ enum TopicValidationError {
}

class ComposeTopicController extends ComposeController<TopicValidationError> {
ComposeTopicController() {
ComposeTopicController({required this.store}) {
_update();
}

PerAccountStore store;

// TODO: subscribe to this value:
// https://zulip.com/help/require-topics
final mandatory = true;
bool get mandatory => store.realmMandatoryTopics;

@override
String _computeTextNormalized() {
Expand Down Expand Up @@ -1194,7 +1196,10 @@ sealed class ComposeBoxController {
}

class StreamComposeBoxController extends ComposeBoxController {
final topic = ComposeTopicController();
StreamComposeBoxController({required PerAccountStore store})
: topic = ComposeTopicController(store: store);

final ComposeTopicController topic;
final topicFocusNode = FocusNode();

@override
Expand Down Expand Up @@ -1271,16 +1276,17 @@ abstract class ComposeBoxState extends State<ComposeBox> {
ComposeBoxController get controller;
}

class _ComposeBoxState extends State<ComposeBox> implements ComposeBoxState {
@override ComposeBoxController get controller => _controller;
late final ComposeBoxController _controller;
class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateMixin<ComposeBox> implements ComposeBoxState {
@override ComposeBoxController get controller => _controller!;
ComposeBoxController? _controller;

@override
void initState() {
super.initState();
void onNewStore() {
switch (widget.narrow) {
case ChannelNarrow():
_controller = StreamComposeBoxController();
final store = PerAccountStoreWidget.of(context);
_controller ??= StreamComposeBoxController(store: store);
(controller as StreamComposeBoxController).topic.store = store;
case TopicNarrow():
case DmNarrow():
_controller = FixedDestinationComposeBoxController();
Expand All @@ -1293,7 +1299,7 @@ class _ComposeBoxState extends State<ComposeBox> implements ComposeBoxState {

@override
void dispose() {
_controller.dispose();
_controller!.dispose();
super.dispose();
}

Expand Down Expand Up @@ -1333,15 +1339,16 @@ class _ComposeBoxState extends State<ComposeBox> implements ComposeBoxState {
return _ComposeBoxContainer(body: null, errorBanner: errorBanner);
}

final controller = _controller!;
final narrow = widget.narrow;
switch (_controller) {
switch (controller) {
case StreamComposeBoxController(): {
narrow as ChannelNarrow;
body = _StreamComposeBoxBody(controller: _controller, narrow: narrow);
body = _StreamComposeBoxBody(controller: controller, narrow: narrow);
}
case FixedDestinationComposeBoxController(): {
narrow as SendableNarrow;
body = _FixedDestinationComposeBoxBody(controller: _controller, narrow: narrow);
body = _FixedDestinationComposeBoxBody(controller: controller, narrow: narrow);
}
}

Expand Down
3 changes: 2 additions & 1 deletion test/model/autocomplete_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,8 @@ void main() {

final description = 'topic-input with text: $markedText produces: ${expectedQuery?.raw ?? 'No Query!'}';
test(description, () {
final controller = ComposeTopicController();
final store = eg.store();
final controller = ComposeTopicController(store: store);
controller.value = parsed.value;
if (expectedQuery == null) {
check(controller).autocompleteIntent.isNull();
Expand Down
65 changes: 65 additions & 0 deletions test/widgets/compose_box_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,71 @@ void main() {
});
});

group('sending to empty topic', () {
late ZulipStream channel;

Future<void> setupAndTapSend(WidgetTester tester, {
bool? mandatoryTopics,
required String topicInputText,
}) async {
TypingNotifier.debugEnable = false;
addTearDown(TypingNotifier.debugReset);
addTearDown(testBinding.reset);

channel = eg.stream();
final account = eg.account(user: eg.selfUser);
final initialSnapshot = eg.initialSnapshot(
realmMandatoryTopics: mandatoryTopics);
await testBinding.globalStore.add(account, initialSnapshot);

store = await testBinding.globalStore.perAccount(account.id);
await store.addStream(channel);
await store.addUser(eg.selfUser);
connection = store.connection as FakeApiConnection;

final narrow = ChannelNarrow(channel.streamId);
await prepareComposeBox(tester,
narrow: narrow, account: account);
await enterTopic(tester, narrow: narrow, topic: topicInputText);
await tester.enterText(contentInputFinder, 'test content');
await tester.tap(find.byIcon(ZulipIcons.send));
await tester.pump();
}

void checkMessageNotSent(WidgetTester tester) {
check(connection.takeRequests()).isEmpty();
checkErrorDialog(tester,
expectedTitle: 'Message not sent',
expectedMessage: 'Topics are required in this organization.');
}

testWidgets('empty topic -> (no topic)', (tester) async {
await setupAndTapSend(tester, topicInputText: '');
check(connection.lastRequest).isA<http.Request>()
..method.equals('POST')
..url.path.equals('/api/v1/messages')
..bodyFields.deepEquals({
'type': 'stream',
'to': channel.streamId.toString(),
'topic': '(no topic)',
'content': 'test content',
'read_by_sender': 'true',
});
});

testWidgets('if topics are mandatory, reject empty topic', (tester) async {
await setupAndTapSend(tester, topicInputText: '',
mandatoryTopics: true);
checkMessageNotSent(tester);
});

testWidgets('if topics are mandatory, reject (no topic)', (tester) async {
await setupAndTapSend(tester, topicInputText: '(no topic)',
mandatoryTopics: true);
checkMessageNotSent(tester);
});
});

group('uploads', () {
void checkAppearsLoading(WidgetTester tester, bool expected) {
final sendButtonElement = tester.element(find.ancestor(
Expand Down

0 comments on commit f0dccf5

Please sign in to comment.