diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json index 0110511..fa3116e 100644 --- a/src/assets/translations/en.json +++ b/src/assets/translations/en.json @@ -89,8 +89,8 @@ "members": "no members | 1 member | {count} members", "leave": "Leave", "purge_set_room_state": "Setting room state", - "purge_redacting_events": "Redacting events", - "purge_removing_members": "Removing members", + "purge_redacting_events": "Redacting events ({count} of {total})", + "purge_removing_members": "Removing members ({count} of {total})", "purge_failed": "Failed to purge room!", "room_list_invites": "Invites", "room_list_rooms": "Rooms", diff --git a/src/components/Chat.vue b/src/components/Chat.vue index 0469baa..4d85aea 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -1287,6 +1287,10 @@ export default { restartRRTimer() { this.stopRRTimer(); + if (this.$matrix.currentRoomBeingPurged) { + return; + } + let eventIdFirst = null; let eventIdLast = null; if (!this.useAudioLayout) { diff --git a/src/services/matrix.service.js b/src/services/matrix.service.js index 4c1a592..7411211 100644 --- a/src/services/matrix.service.js +++ b/src/services/matrix.service.js @@ -37,6 +37,7 @@ export default { userDisplayName: null, userAvatar: null, currentRoom: null, + currentRoomBeingPurged: false, notificationCount: 0, }; }, @@ -558,6 +559,28 @@ export default { * @param roomId */ purgeRoom(roomId, statusCallback) { + this.currentRoomBeingPurged = true; + + const sleep = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + + const withRetry = (codeBlock) => { + return codeBlock().catch((error) => { + if (error && error.errcode == "M_LIMIT_EXCEEDED") { + var retry = 1000; + if (error.data) { + const retryIn = error.data.retry_after_ms; + retry = Math.max(retry, retryIn ? retryIn : 0); + } + console.log("Rate limited, retry in", retry); + return sleep(retry).then(() => withRetry(codeBlock)); + } else { + return Promise.resolve(); + } + }); + }; + const oldGlobalErrorSetting = this.matrixClient.getGlobalErrorOnUnknownDevices(); return new Promise((resolve, reject) => { const room = this.getRoom(roomId); @@ -613,14 +636,32 @@ export default { statusCallback(this.$t("room.purge_redacting_events")); // First ignore unknown device errors this.matrixClient.setGlobalErrorOnUnknownDevices(false); - var redactionPromises = []; - timelineWindow.getEvents().forEach((event) => { - if (!event.isRedacted() && !event.isRedaction() && !event.isState()) { - // Redact! - redactionPromises.push(this.matrixClient.redactEvent(event.getRoomId(), event.getId())); - } + const allEvents = timelineWindow.getEvents().filter((event) => { + return ( + !event.isRedacted() && + !event.isRedaction() && + !event.isState() && + (!room.currentState || room.currentState.maySendRedactionForEvent(event, this.currentUserId)) + ); }); - return Promise.all(redactionPromises); + + const redactFirstEvent = (events) => { + statusCallback( + this.$t("room.purge_redacting_events", { + count: allEvents.length - events.length + 1, + total: allEvents.length, + }) + ); + if (events.length == 0) { + return Promise.resolve(true); + } + const event = events[0]; + return withRetry(() => this.matrixClient.redactEvent(event.getRoomId(), event.getId())).then(() => + redactFirstEvent(events.slice(1)) + ); + }; + + return redactFirstEvent(allEvents); }) .then(() => { //console.log("Purge: kick members"); @@ -628,13 +669,15 @@ export default { var joined = room.getMembersWithMembership("join"); var invited = room.getMembersWithMembership("invite"); var allMembers = joined.concat(invited); - - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } const kickFirstMember = (members) => { //console.log(`Kicking ${members.length} members`); + statusCallback( + this.$t("room.purge_removing_members", { + count: allMembers.length - members.length + 1, + total: allMembers.length, + }) + ); if (members.length == 0) { return Promise.resolve(true); } @@ -644,19 +687,8 @@ export default { } else { // Slight pause to avoid rate limiting. return sleep(0.1) - .then(() => this.matrixClient.kick(roomId, member.userId, "Room Deleted")) - .catch((error) => { - if (error && error.errcode == "M_LIMIT_EXCEEDED") { - var retry = 1000; - if (error.data) { - const retryIn = error.data.retry_after_ms; - retry = Math.max(retry, retryIn ? retryIn : 0); - } - //console.log("Rate limited, retry in", retry); - return sleep(retry).then(() => kickFirstMember(members)); - } - }) - .finally(() => kickFirstMember(members.slice(1))) + .then(() => withRetry(() => this.matrixClient.kick(roomId, member.userId, "Room Deleted"))) + .then(() => kickFirstMember(members.slice(1))); } }; @@ -665,13 +697,15 @@ export default { .then(() => { statusCallback(null); this.matrixClient.setGlobalErrorOnUnknownDevices(oldGlobalErrorSetting); - return this.leaveRoom(roomId); + return withRetry(() => this.leaveRoom(roomId)); }) .then(() => { + this.currentRoomBeingPurged = false; resolve(true); // Done! }) .catch((err) => { console.error("Error purging room", err); + this.currentRoomBeingPurged = false; this.matrixClient.setGlobalErrorOnUnknownDevices(oldGlobalErrorSetting); reject(err); });