Skip to content

Commit

Permalink
api: Add updateMessage route
Browse files Browse the repository at this point in the history
And move the PropagateMode definition from events.dart to
model.dart, since it's no longer specific to an event.
  • Loading branch information
chrisbobbe committed Jan 22, 2025
1 parent 2b33384 commit 4ba572f
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 9 deletions.
8 changes: 0 additions & 8 deletions lib/api/model/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -766,14 +766,6 @@ class UpdateMessageEvent extends Event {
Map<String, dynamic> toJson() => _$UpdateMessageEventToJson(this);
}

/// As in [UpdateMessageEvent.propagateMode].
@JsonEnum(fieldRename: FieldRename.snake)
enum PropagateMode {
changeOne,
changeLater,
changeAll;
}

/// A Zulip event of type `delete_message`: https://zulip.com/api/get-events#delete_message
@JsonSerializable(fieldRename: FieldRename.snake)
class DeleteMessageEvent extends Event {
Expand Down
2 changes: 1 addition & 1 deletion lib/api/model/events.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions lib/api/model/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -939,3 +939,13 @@ enum MessageEditState {
return MessageEditState.none;
}
}

/// As in [updateMessage] or [UpdateMessageEvent.propagateMode].
@JsonEnum(fieldRename: FieldRename.snake, alwaysCreate: true)
enum PropagateMode {
changeOne,
changeLater,
changeAll;

String toJson() => _$PropagateModeEnumMap[this]!;
}
6 changes: 6 additions & 0 deletions lib/api/model/model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions lib/api/route/messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,39 @@ class SendMessageResult {
Map<String, dynamic> toJson() => _$SendMessageResultToJson(this);
}

/// https://zulip.com/api/update-message
Future<UpdateMessageResult> updateMessage(
ApiConnection connection, {
required int messageId,
TopicName? topic,
PropagateMode? propagateMode,
bool? sendNotificationToOldThread,
bool? sendNotificationToNewThread,
String? content,
int? streamId,
}) {
return connection.patch('updateMessage', UpdateMessageResult.fromJson, 'messages/$messageId', {
if (topic != null) 'topic': RawParameter(topic.apiName),
if (propagateMode != null) 'propagate_mode': RawParameter(propagateMode.toJson()),
if (sendNotificationToOldThread != null) 'send_notification_to_old_thread': sendNotificationToOldThread,
if (sendNotificationToNewThread != null) 'send_notification_to_new_thread': sendNotificationToNewThread,
if (content != null) 'content': RawParameter(content),
if (streamId != null) 'stream_id': streamId,
});
}

@JsonSerializable(fieldRename: FieldRename.snake)
class UpdateMessageResult {
// final List<DetachedUpload> detachedUploads; // TODO handle

UpdateMessageResult();

factory UpdateMessageResult.fromJson(Map<String, dynamic> json) =>
_$UpdateMessageResultFromJson(json);

Map<String, dynamic> toJson() => _$UpdateMessageResultToJson(this);
}

/// https://zulip.com/api/upload-file
Future<UploadFileResult> uploadFile(
ApiConnection connection, {
Expand Down
7 changes: 7 additions & 0 deletions lib/api/route/messages.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions test/api/route/messages_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,67 @@ void main() {
});
});

group('updateMessage', () {
Future<UpdateMessageResult> checkUpdateMessage(
FakeApiConnection connection, {
required int messageId,
TopicName? topic,
PropagateMode? propagateMode,
bool? sendNotificationToOldThread,
bool? sendNotificationToNewThread,
String? content,
int? streamId,
required Map<String, String> expected,
}) async {
final result = await updateMessage(connection,
messageId: messageId,
topic: topic,
propagateMode: propagateMode,
sendNotificationToOldThread: sendNotificationToOldThread,
sendNotificationToNewThread: sendNotificationToNewThread,
content: content,
streamId: streamId,
);
check(connection.lastRequest).isA<http.Request>()
..method.equals('PATCH')
..url.path.equals('/api/v1/messages/$messageId')
..bodyFields.deepEquals(expected);
return result;
}

test('topic/content change', () {
// A separate test exercises `streamId`;
// the API doesn't allow changing channel and content at the same time.
return FakeApiConnection.with_((connection) async {
connection.prepare(json: UpdateMessageResult().toJson());
await checkUpdateMessage(connection,
messageId: eg.streamMessage().id,
topic: eg.t('new topic'),
propagateMode: PropagateMode.changeAll,
sendNotificationToOldThread: true,
sendNotificationToNewThread: true,
content: 'asdf',
expected: {
'topic': 'new topic',
'propagate_mode': 'change_all',
'send_notification_to_old_thread': 'true',
'send_notification_to_new_thread': 'true',
'content': 'asdf',
});
});
});

test('channel change', () {
return FakeApiConnection.with_((connection) async {
connection.prepare(json: UpdateMessageResult().toJson());
await checkUpdateMessage(connection,
messageId: eg.streamMessage().id,
streamId: 1,
expected: {'stream_id': '1'});
});
});
});

group('uploadFile', () {
Future<void> checkUploadFile(FakeApiConnection connection, {
required List<List<int>> content,
Expand Down

0 comments on commit 4ba572f

Please sign in to comment.