Skip to content

Commit 4e1bcd2

Browse files
committed
api: Add route updateUserTopic
Signed-off-by: Zixuan James Li <[email protected]>
1 parent ba88c3b commit 4e1bcd2

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

lib/api/route/channels.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:json_annotation/json_annotation.dart';
22

33
import '../core.dart';
4+
import '../model/model.dart';
45
part 'channels.g.dart';
56

67
/// https://zulip.com/api/get-stream-topics
@@ -38,3 +39,33 @@ class GetStreamTopicsEntry {
3839

3940
Map<String, dynamic> toJson() => _$GetStreamTopicsEntryToJson(this);
4041
}
42+
43+
/// https://zulip.com/api/update-user-topic
44+
/// https://zulip.com/api/mute-topic (legacy)
45+
Future<void> updateUserTopic(ApiConnection connection, {
46+
required int streamId,
47+
required String topic,
48+
required UserTopicVisibilityPolicy visibilityPolicy,
49+
}) {
50+
assert(visibilityPolicy != UserTopicVisibilityPolicy.unknown);
51+
if (connection.zulipFeatureLevel! < 170) {
52+
// TODO(server-7): deprecated in FL 170
53+
assert(visibilityPolicy == UserTopicVisibilityPolicy.none
54+
|| visibilityPolicy == UserTopicVisibilityPolicy.muted);
55+
// There can be an error when muting a topic that was already muted
56+
// or unmuting one that was already unmuted. Let it throw because we can't
57+
// reliably filter out the error, which doesn't have a specific "code";
58+
// and we don't have a useful follow-up other than displaying the error.
59+
return connection.post('muteTopic', (_) {}, 'users/me/subscriptions/muted_topics', {
60+
'stream_id': streamId,
61+
'topic': RawParameter(topic),
62+
'op': RawParameter(
63+
visibilityPolicy == UserTopicVisibilityPolicy.none ? 'remove' : 'add'),
64+
});
65+
}
66+
return connection.post('updateUserTopic', (_) {}, 'user_topics', {
67+
'stream_id': streamId,
68+
'topic': RawParameter(topic),
69+
'visibility_policy': visibilityPolicy,
70+
});
71+
}

test/api/route/channels_test.dart

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import 'package:checks/checks.dart';
2+
import 'package:http/http.dart' as http;
3+
import 'package:flutter_test/flutter_test.dart';
4+
import 'package:zulip/api/model/model.dart';
5+
import 'package:zulip/api/route/channels.dart';
6+
7+
import '../../stdlib_checks.dart';
8+
import '../fake_api.dart';
9+
10+
void main() {
11+
test('smoke updateUserTopic', () {
12+
return FakeApiConnection.with_((connection) async {
13+
connection.prepare(json: {});
14+
await updateUserTopic(connection,
15+
streamId: 1, topic: 'topic',
16+
visibilityPolicy: UserTopicVisibilityPolicy.followed);
17+
check(connection.takeRequests()).single.isA<http.Request>()
18+
..method.equals('POST')
19+
..url.path.equals('/api/v1/user_topics')
20+
..bodyFields.deepEquals({
21+
'stream_id': '1',
22+
'topic': 'topic',
23+
'visibility_policy': '3',
24+
});
25+
});
26+
});
27+
28+
test('updateUserTopic only accepts valid visibility policy', () {
29+
return FakeApiConnection.with_((connection) async {
30+
check(() => updateUserTopic(connection,
31+
streamId: 1, topic: 'topic',
32+
visibilityPolicy: UserTopicVisibilityPolicy.unknown),
33+
).throws<AssertionError>();
34+
});
35+
});
36+
37+
group('legacy: use muteTopic when FL < 170', () {
38+
test('policy: none -> op: remove', () {
39+
return FakeApiConnection.with_(zulipFeatureLevel: 169, (connection) async {
40+
connection.prepare(json: {});
41+
await updateUserTopic(connection,
42+
streamId: 1, topic: 'topic',
43+
visibilityPolicy: UserTopicVisibilityPolicy.none);
44+
check(connection.takeRequests()).single.isA<http.Request>()
45+
..method.equals('POST')
46+
..url.path.equals('/api/v1/users/me/subscriptions/muted_topics')
47+
..bodyFields.deepEquals({
48+
'stream_id': '1',
49+
'topic': 'topic',
50+
'op': 'remove',
51+
});
52+
});
53+
});
54+
55+
test('policy: muted -> op: add', () {
56+
return FakeApiConnection.with_(zulipFeatureLevel: 169, (connection) async {
57+
connection.prepare(json: {});
58+
await updateUserTopic(connection,
59+
streamId: 1, topic: 'topic',
60+
visibilityPolicy: UserTopicVisibilityPolicy.muted);
61+
check(connection.takeRequests()).single.isA<http.Request>()
62+
..method.equals('POST')
63+
..url.path.equals('/api/v1/users/me/subscriptions/muted_topics')
64+
..bodyFields.deepEquals({
65+
'stream_id': '1',
66+
'topic': 'topic',
67+
'op': 'add',
68+
});
69+
});
70+
});
71+
});
72+
}

0 commit comments

Comments
 (0)