Skip to content

Commit

Permalink
Block read marker and read receipt from advancing into pending events
Browse files Browse the repository at this point in the history
This changes the methods that update the read marker and read receipts to
prevent advancing into pending events.

Part of element-hq/element-web#9952
  • Loading branch information
jryans committed Jul 5, 2019
1 parent aa6884e commit 1d427a1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
22 changes: 16 additions & 6 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2148,7 +2148,12 @@ MatrixClient.prototype.sendReceipt = function(event, receiptType, callback) {
* @return {module:client.Promise} Resolves: TODO
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
MatrixClient.prototype.sendReadReceipt = function(event, callback) {
MatrixClient.prototype.sendReadReceipt = async function(event, callback) {
const eventId = event.getId();
const room = this.getRoom(event.getRoomId());
if (room && room.hasPendingEvent(eventId)) {
throw new Error(`Cannot set read receipt to a pending event (${eventId})`);
}
return this.sendReceipt(event, "m.read", callback);
};

Expand All @@ -2158,20 +2163,25 @@ MatrixClient.prototype.sendReadReceipt = function(event, callback) {
* and displayed as a horizontal line in the timeline that is visually distinct to the
* position of the user's own read receipt.
* @param {string} roomId ID of the room that has been read
* @param {string} eventId ID of the event that has been read
* @param {string} rmEventId ID of the event that has been read
* @param {string} rrEvent the event tracked by the read receipt. This is here for
* convenience because the RR and the RM are commonly updated at the same time as each
* other. The local echo of this receipt will be done if set. Optional.
* @return {module:client.Promise} Resolves: the empty object, {}.
*/
MatrixClient.prototype.setRoomReadMarkers = function(roomId, eventId, rrEvent) {
const rmEventId = eventId;
let rrEventId;
MatrixClient.prototype.setRoomReadMarkers = async function(roomId, rmEventId, rrEvent) {
const room = this.getRoom(roomId);
if (room && room.hasPendingEvent(rmEventId)) {
throw new Error(`Cannot set read marker to a pending event (${rmEventId})`);
}

// Add the optional RR update, do local echo like `sendReceipt`
let rrEventId;
if (rrEvent) {
rrEventId = rrEvent.getId();
const room = this.getRoom(roomId);
if (room && room.hasPendingEvent(rrEventId)) {
throw new Error(`Cannot set read receipt to a pending event (${rrEventId})`);
}
if (room) {
room._addLocalEchoReceipt(this.credentials.userId, rrEvent, "m.read");
}
Expand Down
19 changes: 18 additions & 1 deletion src/models/room.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,13 +346,30 @@ Room.prototype.userMayUpgradeRoom = function(userId) {
Room.prototype.getPendingEvents = function() {
if (this._opts.pendingEventOrdering !== "detached") {
throw new Error(
"Cannot call getPendingEventList with pendingEventOrdering == " +
"Cannot call getPendingEvents with pendingEventOrdering == " +
this._opts.pendingEventOrdering);
}

return this._pendingEventList;
};

/**
* Check whether the pending event list contains a given event by ID.
*
* @param {string} eventId The event ID to check for.
* @return {boolean}
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
*/
Room.prototype.hasPendingEvent = function(eventId) {
if (this._opts.pendingEventOrdering !== "detached") {
throw new Error(
"Cannot call hasPendingEvent with pendingEventOrdering == " +
this._opts.pendingEventOrdering);
}

return this._pendingEventList.some(event => event.getId() === eventId);
};

/**
* Get the live unfiltered timeline for this room.
*
Expand Down

0 comments on commit 1d427a1

Please sign in to comment.