Skip to content

Commit

Permalink
compose: Send to general chat if empty topic
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 509bb57 commit 8c4e5d7
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
12 changes: 10 additions & 2 deletions lib/widgets/compose_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,24 @@ class ComposeTopicController extends ComposeController<TopicValidationError> {
// TODO(#307) use `max_topic_length` instead of hardcoded limit
@override final maxLengthUnicodeCodePoints = kMaxTopicLengthCodePoints;

// TODO(server-10): simplify
String get noTopicTopic => store.connection.zulipFeatureLevel! >= 334
? '' : kNoTopicTopic;

@override
String _computeTextNormalized() {
String trimmed = text.trim();
return trimmed.isEmpty ? kNoTopicTopic : trimmed;
return trimmed.isEmpty ? noTopicTopic : trimmed;
}

@override
List<TopicValidationError> _computeValidationErrors() {
return [
if (mandatory && textNormalized == kNoTopicTopic)
if (mandatory && (
// While this may appear repetitive, the latter is not guarded behind
// a `zulipFeatureLevel` check. "(no topic)" still gets rejected
// by newer servers when topics are mandatory.
textNormalized == noTopicTopic || textNormalized == kNoTopicTopic))
TopicValidationError.mandatoryButEmpty,

if (
Expand Down
35 changes: 33 additions & 2 deletions test/widgets/compose_box_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ void main() {
late ZulipStream channel;

Future<void> setupAndTapSend(WidgetTester tester, {
Account? account,
bool? mandatoryTopics,
required String topicInputText,
}) async {
Expand All @@ -688,8 +689,10 @@ void main() {
addTearDown(testBinding.reset);

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

Expand All @@ -714,8 +717,23 @@ void main() {
expectedMessage: 'Topics are required in this organization.');
}

testWidgets('empty topic -> (no topic)', (tester) async {
testWidgets('empty topic -> general chat', (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': eg.defaultRealmEmptyTopicDisplayName,
'content': 'test content',
'read_by_sender': 'true',
});
});

testWidgets('legacy: empty topic -> (no topic)', (tester) async {
await setupAndTapSend(tester, topicInputText: '',
account: eg.account(user: eg.selfUser, zulipFeatureLevel: 333));
check(connection.lastRequest).isA<http.Request>()
..method.equals('POST')
..url.path.equals('/api/v1/messages')
Expand All @@ -734,11 +752,24 @@ void main() {
checkMessageNotSent(tester);
});

testWidgets('if topics are mandatory, reject `realmEmptyTopicDisplayName`', (tester) async {
await setupAndTapSend(tester, topicInputText: eg.defaultRealmEmptyTopicDisplayName,
mandatoryTopics: true);
checkMessageNotSent(tester);
});

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

testWidgets('legacy: if topics are mandatory, reject (no topic)', (tester) async {
await setupAndTapSend(tester, topicInputText: '(no topic)',
account: eg.account(user: eg.selfUser, zulipFeatureLevel: 333),
mandatoryTopics: true);
checkMessageNotSent(tester);
});
});

group('uploads', () {
Expand Down

0 comments on commit 8c4e5d7

Please sign in to comment.