Skip to content

Commit 6ff20f6

Browse files
committed
model: Use prevContentSha256 in edit-message method
1 parent 19aa212 commit 6ff20f6

File tree

3 files changed

+61
-21
lines changed

3 files changed

+61
-21
lines changed

lib/model/message.dart

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'dart:convert';
22

3+
import 'package:crypto/crypto.dart';
4+
35
import '../api/model/events.dart';
46
import '../api/model/model.dart';
57
import '../api/route/messages.dart';
@@ -51,7 +53,11 @@ mixin MessageStore {
5153
/// See also:
5254
/// * [getEditMessageErrorStatus]
5355
/// * [takeFailedMessageEdit]
54-
void editMessage({required int messageId, required String newContent});
56+
void editMessage({
57+
required int messageId,
58+
required String originalRawContent,
59+
required String newContent,
60+
});
5561

5662
/// Forgets the failed edit request and returns the attempted new content.
5763
///
@@ -171,6 +177,7 @@ class MessageStoreImpl extends PerAccountStoreBase with MessageStore {
171177
@override
172178
void editMessage({
173179
required int messageId,
180+
required String originalRawContent,
174181
required String newContent,
175182
}) async {
176183
if (_editMessageRequests.containsKey(messageId)) {
@@ -181,7 +188,10 @@ class MessageStoreImpl extends PerAccountStoreBase with MessageStore {
181188
hasError: false, newContent: newContent);
182189
_notifyMessageListViewsForOneMessage(messageId);
183190
try {
184-
await updateMessage(connection, messageId: messageId, content: newContent);
191+
await updateMessage(connection,
192+
messageId: messageId,
193+
content: newContent,
194+
prevContentSha256: sha256.convert(utf8.encode(originalRawContent)).toString());
185195
// On success, we'll clear the status from _editMessageRequests
186196
// when we get the event.
187197
} catch (e) {

lib/model/store.dart

+7-2
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,14 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
753753
return _messages.getEditMessageErrorStatus(messageId);
754754
}
755755
@override
756-
void editMessage({required int messageId, required String newContent}) {
756+
void editMessage({
757+
required int messageId,
758+
required String originalRawContent,
759+
required String newContent,
760+
}) {
757761
assert(!_disposed);
758-
return _messages.editMessage(messageId: messageId, newContent: newContent);
762+
return _messages.editMessage(messageId: messageId,
763+
originalRawContent: originalRawContent, newContent: newContent);
759764
}
760765
@override
761766
String takeFailedMessageEdit(int messageId) {

test/model/message_test.dart

+42-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:convert';
22
import 'dart:io';
33

44
import 'package:checks/checks.dart';
5+
import 'package:crypto/crypto.dart';
56
import 'package:http/http.dart' as http;
67
import 'package:test/scaffolding.dart';
78
import 'package:zulip/api/model/events.dart';
@@ -136,11 +137,16 @@ void main() {
136137
check(connection.takeRequests()).length.equals(1); // message-list fetchInitial
137138
}
138139

139-
void checkRequest(int messageId, String content) {
140+
void checkRequest(int messageId, {
141+
required String prevContent,
142+
required String content,
143+
}) {
144+
final prevContentSha256 = sha256.convert(utf8.encode(prevContent)).toString();
140145
check(connection.takeRequests()).single.isA<http.Request>()
141146
..method.equals('PATCH')
142147
..url.path.equals('/api/v1/messages/$messageId')
143148
..bodyFields.deepEquals({
149+
'prev_content_sha256': prevContentSha256,
144150
'content': content,
145151
});
146152
}
@@ -151,8 +157,11 @@ void main() {
151157

152158
connection.prepare(
153159
json: UpdateMessageResult().toJson(), delay: Duration(seconds: 1));
154-
store.editMessage(messageId: message.id, newContent: 'new content');
155-
checkRequest(message.id, 'new content');
160+
store.editMessage(messageId: message.id,
161+
originalRawContent: 'old content', newContent: 'new content');
162+
checkRequest(message.id,
163+
prevContent: 'old content',
164+
content: 'new content');
156165
checkNotifiedOnce();
157166

158167
async.elapse(Duration(milliseconds: 500));
@@ -179,8 +188,11 @@ void main() {
179188

180189
connection.prepare(
181190
json: UpdateMessageResult().toJson(), delay: Duration(seconds: 1));
182-
store.editMessage(messageId: message.id, newContent: 'new content');
183-
checkRequest(message.id, 'new content');
191+
store.editMessage(messageId: message.id,
192+
originalRawContent: 'old content', newContent: 'new content');
193+
checkRequest(message.id,
194+
prevContent: 'old content',
195+
content: 'new content');
184196
checkNotifiedOnce();
185197

186198
async.elapse(Duration(milliseconds: 500));
@@ -189,8 +201,11 @@ void main() {
189201
check(store.getEditMessageErrorStatus(otherMessage.id)).isNull();
190202
connection.prepare(
191203
json: UpdateMessageResult().toJson(), delay: Duration(seconds: 1));
192-
store.editMessage(messageId: otherMessage.id, newContent: 'other message new content');
193-
checkRequest(otherMessage.id, 'other message new content');
204+
store.editMessage(messageId: otherMessage.id,
205+
originalRawContent: 'other message old content', newContent: 'other message new content');
206+
checkRequest(otherMessage.id,
207+
prevContent: 'other message old content',
208+
content: 'other message new content');
194209
checkNotifiedOnce();
195210

196211
async.elapse(Duration(milliseconds: 500));
@@ -221,7 +236,8 @@ void main() {
221236
check(store.getEditMessageErrorStatus(message.id)).isNull();
222237

223238
connection.prepare(apiException: eg.apiBadRequest(), delay: Duration(seconds: 1));
224-
store.editMessage(messageId: message.id, newContent: 'new content');
239+
store.editMessage(messageId: message.id,
240+
originalRawContent: 'old content', newContent: 'new content');
225241
checkNotifiedOnce();
226242
async.elapse(Duration(seconds: 1));
227243
check(store.getEditMessageErrorStatus(message.id)).isNotNull().isTrue();
@@ -233,7 +249,8 @@ void main() {
233249
check(store.getEditMessageErrorStatus(message.id)).isNull();
234250

235251
connection.prepare(apiException: eg.apiBadRequest(), delay: Duration(seconds: 1));
236-
store.editMessage(messageId: message.id, newContent: 'new content');
252+
store.editMessage(messageId: message.id,
253+
originalRawContent: 'old content', newContent: 'new content');
237254
checkNotifiedOnce();
238255
async.elapse(Duration(seconds: 1));
239256
check(store.getEditMessageErrorStatus(message.id)).isNotNull().isTrue();
@@ -255,12 +272,14 @@ void main() {
255272

256273
connection.prepare(
257274
json: UpdateMessageResult().toJson(), delay: Duration(seconds: 1));
258-
store.editMessage(messageId: message.id, newContent: 'new content');
275+
store.editMessage(messageId: message.id,
276+
originalRawContent: 'old content', newContent: 'new content');
259277
async.elapse(Duration(milliseconds: 500));
260278
check(connection.takeRequests()).length.equals(1);
261279
checkNotifiedOnce();
262280

263-
await check(store.editMessage(messageId: message.id, newContent: 'newer content'))
281+
await check(store.editMessage(messageId: message.id,
282+
originalRawContent: 'old content', newContent: 'newer content'))
264283
.isA<Future<void>>().throws<StateError>();
265284
check(connection.takeRequests()).isEmpty();
266285
}));
@@ -273,7 +292,8 @@ void main() {
273292

274293
connection.prepare(
275294
httpException: const SocketException('failed'), delay: Duration(seconds: 1));
276-
store.editMessage(messageId: message.id, newContent: 'new content');
295+
store.editMessage(messageId: message.id,
296+
originalRawContent: 'old content', newContent: 'new content');
277297
checkNotifiedOnce();
278298

279299
async.elapse(Duration(milliseconds: 500));
@@ -294,7 +314,8 @@ void main() {
294314

295315
connection.prepare(
296316
httpException: const SocketException('failed'), delay: Duration(seconds: 1));
297-
store.editMessage(messageId: message.id, newContent: 'new content');
317+
store.editMessage(messageId: message.id,
318+
originalRawContent: 'old content', newContent: 'new content');
298319
checkNotifiedOnce();
299320

300321
async.elapse(Duration(seconds: 1));
@@ -314,7 +335,8 @@ void main() {
314335

315336
connection.prepare(
316337
httpException: const SocketException('failed'), delay: Duration(seconds: 1));
317-
store.editMessage(messageId: message.id, newContent: 'new content');
338+
store.editMessage(messageId: message.id,
339+
originalRawContent: 'old content', newContent: 'new content');
318340
checkNotifiedOnce();
319341

320342
async.elapse(Duration(seconds: 1));
@@ -333,7 +355,8 @@ void main() {
333355
check(store.getEditMessageErrorStatus(message.id)).isNull();
334356

335357
connection.prepare(apiException: eg.apiBadRequest(), delay: Duration(seconds: 1));
336-
store.editMessage(messageId: message.id, newContent: 'new content');
358+
store.editMessage(messageId: message.id,
359+
originalRawContent: 'old content', newContent: 'new content');
337360
checkNotifiedOnce();
338361
async.elapse(Duration(seconds: 1));
339362
check(store.getEditMessageErrorStatus(message.id)).isNotNull().isTrue();
@@ -349,7 +372,8 @@ void main() {
349372
check(store.getEditMessageErrorStatus(message.id)).isNull();
350373

351374
connection.prepare(apiException: eg.apiBadRequest(), delay: Duration(seconds: 1));
352-
store.editMessage(messageId: message.id, newContent: 'new content');
375+
store.editMessage(messageId: message.id,
376+
originalRawContent: 'old content', newContent: 'new content');
353377
checkNotifiedOnce();
354378

355379
async.elapse(Duration(milliseconds: 500));
@@ -373,7 +397,8 @@ void main() {
373397

374398
connection.prepare(
375399
json: UpdateMessageResult().toJson(), delay: Duration(seconds: 1));
376-
store.editMessage(messageId: message.id, newContent: 'new content');
400+
store.editMessage(messageId: message.id,
401+
originalRawContent: 'old content', newContent: 'new content');
377402
checkNotifiedOnce();
378403

379404
async.elapse(Duration(milliseconds: 500));

0 commit comments

Comments
 (0)