Skip to content

Commit 0c1f1ae

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 5ec097c commit 0c1f1ae

File tree

3 files changed

+54
-9
lines changed

3 files changed

+54
-9
lines changed

lib/api/model/model.dart

+33
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,15 @@ String? tryParseEmojiCodeToUnicode(String emojiCode) {
532532
}
533533
}
534534

535+
/// The topic servers understand to mean "there is no topic".
536+
///
537+
/// This should match
538+
/// https://github.com/zulip/zulip/blob/6.0/zerver/actions/message_edit.py#L940
539+
/// or similar logic at the latest `main`.
540+
// This is hardcoded in the server, and therefore untranslated; that's
541+
// zulip/zulip#3639.
542+
const String kNoTopicTopic = '(no topic)';
543+
535544
/// The name of a Zulip topic.
536545
// TODO(dart): Can we forbid calling Object members on this extension type?
537546
// (The lack of "implements Object" ought to do that, but doesn't.)
@@ -586,6 +595,30 @@ extension type const TopicName(String _value) {
586595
/// using [canonicalize].
587596
bool isSameAs(TopicName other) => canonicalize() == other.canonicalize();
588597

598+
/// Convert this topic to match how it would appear on a message object from
599+
/// the server, assuming the topic is originally for a send-message request.
600+
///
601+
/// For a client that does not support empty topics,
602+
/// a modern server (FL>=334) would convert "(no topic)" and empty topics to
603+
/// `store.realmEmptyTopicDisplayName`.
604+
///
605+
/// See also: https://zulip.com/api/send-message#parameter-topic
606+
TopicName interpretAsServer({
607+
required int zulipFeatureLevel,
608+
required String? realmEmptyTopicDisplayName,
609+
}) {
610+
if (zulipFeatureLevel < 334) {
611+
assert(_value.isNotEmpty);
612+
return this;
613+
}
614+
if (_value == kNoTopicTopic || _value.isEmpty) {
615+
// TODO(#1250): this assumes that the 'support_empty_topics'
616+
// client_capability is false; update this when we set it to true
617+
return TopicName(realmEmptyTopicDisplayName!);
618+
}
619+
return TopicName(_value);
620+
}
621+
589622
TopicName.fromJson(this._value);
590623

591624
String toJson() => apiName;

lib/api/route/messages.dart

-9
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

+21
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)