Skip to content

Commit a190649

Browse files
committed
api [nfc]: Add TopicName.interpretAsServer
The point of this helper is to replicate what a topic sent from the client will become, after being processed by the server. This important when trying to create a local copy of a stream message, whose topic can get translated when it's delivered by the server.
1 parent 6ff20f6 commit a190649

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

lib/api/model/model.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,15 @@ String? tryParseEmojiCodeToUnicode(String emojiCode) {
550550
}
551551
}
552552

553+
/// The topic servers understand to mean "there is no topic".
554+
///
555+
/// This should match
556+
/// https://github.com/zulip/zulip/blob/6.0/zerver/actions/message_edit.py#L940
557+
/// or similar logic at the latest `main`.
558+
// This is hardcoded in the server, and therefore untranslated; that's
559+
// zulip/zulip#3639.
560+
const String kNoTopicTopic = '(no topic)';
561+
553562
/// The name of a Zulip topic.
554563
// TODO(dart): Can we forbid calling Object members on this extension type?
555564
// (The lack of "implements Object" ought to do that, but doesn't.)
@@ -604,6 +613,33 @@ extension type const TopicName(String _value) {
604613
/// using [canonicalize].
605614
bool isSameAs(TopicName other) => canonicalize() == other.canonicalize();
606615

616+
/// Convert this topic to match how it would appear on a message object from
617+
/// the server, assuming the topic is originally for a send-message request.
618+
///
619+
/// For a client that does not support empty topics,
620+
/// a modern server (FL>=334) would convert "(no topic)" and empty topics to
621+
/// `store.realmEmptyTopicDisplayName`.
622+
///
623+
/// See also: https://zulip.com/api/send-message#parameter-topic
624+
TopicName interpretAsServer({
625+
required int zulipFeatureLevel,
626+
required String? realmEmptyTopicDisplayName,
627+
}) {
628+
assert(_value.trim() == _value);
629+
// TODO(server-10) simplify this away
630+
if (zulipFeatureLevel < 334) {
631+
assert(_value.isNotEmpty);
632+
return this;
633+
}
634+
635+
if (_value == kNoTopicTopic || _value.isEmpty) {
636+
// TODO(#1250): this assumes that the 'support_empty_topics'
637+
// client_capability is false; update this when we set it to true
638+
return TopicName(realmEmptyTopicDisplayName!);
639+
}
640+
return TopicName(_value);
641+
}
642+
607643
TopicName.fromJson(this._value);
608644

609645
String toJson() => apiName;

lib/api/route/messages.dart

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,6 @@ const int kMaxTopicLengthCodePoints = 60;
169169
// https://zulip.com/api/send-message#parameter-content
170170
const int kMaxMessageLengthCodePoints = 10000;
171171

172-
/// The topic servers understand to mean "there is no topic".
173-
///
174-
/// This should match
175-
/// https://github.com/zulip/zulip/blob/6.0/zerver/actions/message_edit.py#L940
176-
/// or similar logic at the latest `main`.
177-
// This is hardcoded in the server, and therefore untranslated; that's
178-
// zulip/zulip#3639.
179-
const String kNoTopicTopic = '(no topic)';
180-
181172
/// https://zulip.com/api/send-message
182173
Future<SendMessageResult> sendMessage(
183174
ApiConnection connection, {

test/api/model/model_test.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,27 @@ void main() {
161161

162162
doCheck(eg.t('✔ a'), eg.t('✔ b'), false);
163163
});
164+
165+
test('interpretAsServer', () {
166+
final emptyTopicDisplayName = eg.defaultRealmEmptyTopicDisplayName;
167+
void doCheck(TopicName topicA, TopicName expected, int zulipFeatureLevel) {
168+
check(topicA.interpretAsServer(
169+
zulipFeatureLevel: zulipFeatureLevel,
170+
realmEmptyTopicDisplayName: emptyTopicDisplayName),
171+
).equals(expected);
172+
}
173+
174+
check(() => doCheck(eg.t(''), eg.t(''), 333))
175+
.throws<void>();
176+
doCheck(eg.t('(no topic)'), eg.t('(no topic)'), 333);
177+
doCheck(eg.t(emptyTopicDisplayName), eg.t(emptyTopicDisplayName), 333);
178+
doCheck(eg.t('other topic'), eg.t('other topic'), 333);
179+
180+
doCheck(eg.t(''), eg.t(emptyTopicDisplayName), 334);
181+
doCheck(eg.t('(no topic)'), eg.t(emptyTopicDisplayName), 334);
182+
doCheck(eg.t(emptyTopicDisplayName), eg.t(emptyTopicDisplayName), 334);
183+
doCheck(eg.t('other topic'), eg.t('other topic'), 334);
184+
});
164185
});
165186

166187
group('DmMessage', () {

0 commit comments

Comments
 (0)