Skip to content

Commit 66fb237

Browse files
committed
api: Add route fetchServerEmojiData
1 parent 0f4f597 commit 66fb237

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

lib/api/route/realm.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import 'package:http/http.dart' as http;
12
import 'package:json_annotation/json_annotation.dart';
23

34
import '../core.dart';
5+
import '../model/initial_snapshot.dart';
46

57
part 'realm.g.dart';
68

@@ -94,3 +96,49 @@ class ExternalAuthenticationMethod {
9496

9597
Map<String, dynamic> toJson() => _$ExternalAuthenticationMethodToJson(this);
9698
}
99+
100+
/// Fetch data from the URL described by [InitialSnapshot.serverEmojiDataUrl].
101+
///
102+
/// This request is unauthenticated, and the URL need not be on the realm.
103+
/// The given [ApiConnection] is used for providing a `User-Agent` header
104+
/// and for handling errors.
105+
///
106+
/// For docs, search for "server_emoji"
107+
/// in <https://zulip.com/api/register-queue>.
108+
Future<ServerEmojiData> fetchServerEmojiData(ApiConnection connection, {
109+
required Uri emojiDataUrl,
110+
}) {
111+
// TODO(#950): cache server responses on fetchServerEmojiData
112+
113+
// This nontraditional endpoint doesn't conform to all the usual Zulip API
114+
// protocols: https://zulip.com/api/rest-error-handling
115+
// notably the `{ code, msg, result }` format for errors.
116+
// So in the case of an error, the generic Zulip API error-handling logic
117+
// in [ApiConnection.send] will throw [MalformedServerResponseException]
118+
// in some cases where "malformed" isn't quite the right description.
119+
// We'll just tolerate that.
120+
// If it really mattered, we could refactor [ApiConnection] to accommodate.
121+
//
122+
// Similarly, there's no `"result": "success"` in the response.
123+
// Fortunately none of our code looks for that in the first place.
124+
return connection.send('fetchServerEmojiData', ServerEmojiData.fromJson,
125+
useAuth: false,
126+
http.Request('GET', emojiDataUrl));
127+
}
128+
129+
/// The server's data describing its list of Unicode emoji
130+
/// and its names for them.
131+
///
132+
/// For docs, search for "server_emoji"
133+
/// in <https://zulip.com/api/register-queue>.
134+
@JsonSerializable(fieldRename: FieldRename.snake)
135+
class ServerEmojiData {
136+
final Map<String, List<String>> codeToNames;
137+
138+
ServerEmojiData({required this.codeToNames});
139+
140+
factory ServerEmojiData.fromJson(Map<String, dynamic> json) =>
141+
_$ServerEmojiDataFromJson(json);
142+
143+
Map<String, dynamic> toJson() => _$ServerEmojiDataToJson(this);
144+
}

lib/api/route/realm.g.dart

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/api/route/realm_test.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import 'package:checks/checks.dart';
2+
import 'package:http/http.dart' as http;
3+
import 'package:test/scaffolding.dart';
4+
import 'package:zulip/api/core.dart';
5+
import 'package:zulip/api/route/realm.dart';
6+
7+
import '../../stdlib_checks.dart';
8+
import '../fake_api.dart';
9+
10+
void main() {
11+
group('fetchServerEmojiData', () {
12+
Future<ServerEmojiData> checkFetchServerEmojiData(FakeApiConnection connection, {
13+
required Uri emojiDataUrl,
14+
}) async {
15+
final result = await fetchServerEmojiData(connection,
16+
emojiDataUrl: emojiDataUrl);
17+
check(connection.lastRequest).isA<http.Request>()
18+
..method.equals('GET')
19+
..url.equals(emojiDataUrl)
20+
..headers.deepEquals(kFallbackUserAgentHeader);
21+
return result;
22+
}
23+
24+
final fakeResult = ServerEmojiData(codeToNames: {
25+
'1f642': ['smile'],
26+
'1f34a': ['orange', 'tangerine', 'mandarin'],
27+
});
28+
29+
test('smoke', () {
30+
return FakeApiConnection.with_((connection) async {
31+
connection.prepare(json: fakeResult.toJson());
32+
check(await checkFetchServerEmojiData(connection,
33+
emojiDataUrl: connection.realmUrl.resolve('/static/emoji.json')
34+
)).jsonEquals(fakeResult);
35+
});
36+
});
37+
38+
test('off-realm is OK', () {
39+
return FakeApiConnection.with_(
40+
realmUrl: Uri.parse('https://chat.example'), (connection) async {
41+
connection.prepare(json: fakeResult.toJson());
42+
check(await checkFetchServerEmojiData(connection,
43+
emojiDataUrl: Uri.parse('https://elsewhere.example/static/emoji.json')
44+
)).jsonEquals(fakeResult);
45+
});
46+
});
47+
});
48+
}

0 commit comments

Comments
 (0)