You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Revert code moving deleted messages to main timeline (#3858)
* Revert "Move the redaction event to main at the same time we move redacted" This reverts commit378a776815
. Context: https://github.com/vector-im/element-web/issues/26498 * Revert "Don't remove thread info from a thread root when it is redacted" This reverts commit17b61a69c2
. Context: https://github.com/vector-im/element-web/issues/26498 * Revert "Move all related messages into main timeline on redaction" This reverts commitd8fc1795f1
. Context: https://github.com/vector-im/element-web/issues/26498 * Revert "Factor out the code for moving an event to the main timeline" This reverts commit942dfcb84b
. Context: https://github.com/vector-im/element-web/issues/26498 * Revert "Factor out utils in redaction tests" This reverts commit43a0dc56e1
. Context: https://github.com/vector-im/element-web/issues/26498 * Revert "Move redaction event tests into their own describe block" This reverts commit9b0ea80f93
. Context: https://github.com/vector-im/element-web/issues/26498 * Revert "Move redacted messages out of any thread, into main timeline." This reverts commitb94d137398
. Context: https://github.com/vector-im/element-web/issues/26498
This commit is contained in:
@ -14,19 +14,10 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MockedObject } from "jest-mock";
|
|
||||||
|
|
||||||
import { MatrixEvent, MatrixEventEvent } from "../../../src/models/event";
|
import { MatrixEvent, MatrixEventEvent } from "../../../src/models/event";
|
||||||
import { emitPromise } from "../../test-utils/test-utils";
|
import { emitPromise } from "../../test-utils/test-utils";
|
||||||
import { Crypto, IEventDecryptionResult } from "../../../src/crypto";
|
import { Crypto, IEventDecryptionResult } from "../../../src/crypto";
|
||||||
import {
|
import { IAnnotatedPushRule, PushRuleActionName, TweakName } from "../../../src";
|
||||||
IAnnotatedPushRule,
|
|
||||||
MatrixClient,
|
|
||||||
PushRuleActionName,
|
|
||||||
Room,
|
|
||||||
THREAD_RELATION_TYPE,
|
|
||||||
TweakName,
|
|
||||||
} from "../../../src";
|
|
||||||
|
|
||||||
describe("MatrixEvent", () => {
|
describe("MatrixEvent", () => {
|
||||||
it("should create copies of itself", () => {
|
it("should create copies of itself", () => {
|
||||||
@ -70,264 +61,31 @@ describe("MatrixEvent", () => {
|
|||||||
expect(a.toSnapshot().isEquivalentTo(b)).toBe(false);
|
expect(a.toSnapshot().isEquivalentTo(b)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("redaction", () => {
|
it("should prune clearEvent when being redacted", () => {
|
||||||
it("should prune clearEvent when being redacted", () => {
|
const ev = new MatrixEvent({
|
||||||
const ev = createEvent("$event1:server", "Test");
|
type: "m.room.message",
|
||||||
|
content: {
|
||||||
expect(ev.getContent().body).toBe("Test");
|
body: "Test",
|
||||||
expect(ev.getWireContent().body).toBe("Test");
|
},
|
||||||
ev.makeEncrypted("m.room.encrypted", { ciphertext: "xyz" }, "", "");
|
event_id: "$event1:server",
|
||||||
expect(ev.getContent().body).toBe("Test");
|
|
||||||
expect(ev.getWireContent().body).toBeUndefined();
|
|
||||||
expect(ev.getWireContent().ciphertext).toBe("xyz");
|
|
||||||
|
|
||||||
const mockClient = {} as unknown as MockedObject<MatrixClient>;
|
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
|
|
||||||
ev.makeRedacted(redaction, room);
|
|
||||||
expect(ev.getContent().body).toBeUndefined();
|
|
||||||
expect(ev.getWireContent().body).toBeUndefined();
|
|
||||||
expect(ev.getWireContent().ciphertext).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remain in the main timeline when redacted", async () => {
|
expect(ev.getContent().body).toBe("Test");
|
||||||
// Given an event in the main timeline
|
expect(ev.getWireContent().body).toBe("Test");
|
||||||
const mockClient = createMockClient();
|
ev.makeEncrypted("m.room.encrypted", { ciphertext: "xyz" }, "", "");
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
expect(ev.getContent().body).toBe("Test");
|
||||||
const ev = createEvent("$event1:server");
|
expect(ev.getWireContent().body).toBeUndefined();
|
||||||
|
expect(ev.getWireContent().ciphertext).toBe("xyz");
|
||||||
|
|
||||||
await room.addLiveEvents([ev]);
|
const redaction = new MatrixEvent({
|
||||||
await room.createThreadsTimelineSets();
|
type: "m.room.redaction",
|
||||||
expect(ev.threadRootId).toBeUndefined();
|
redacts: ev.getId(),
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([ev.getId()]);
|
|
||||||
|
|
||||||
// When I redact it
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
ev.makeRedacted(redaction, room);
|
|
||||||
|
|
||||||
// Then it remains in the main timeline
|
|
||||||
expect(ev.threadRootId).toBeUndefined();
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([ev.getId()]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should keep thread roots in both timelines when redacted", async () => {
|
ev.makeRedacted(redaction);
|
||||||
// Given a thread exists
|
expect(ev.getContent().body).toBeUndefined();
|
||||||
const mockClient = createMockClient();
|
expect(ev.getWireContent().body).toBeUndefined();
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
expect(ev.getWireContent().ciphertext).toBeUndefined();
|
||||||
const threadRoot = createEvent("$threadroot:server");
|
|
||||||
const ev = createThreadedEvent("$event1:server", threadRoot.getId()!);
|
|
||||||
|
|
||||||
await room.addLiveEvents([threadRoot, ev]);
|
|
||||||
await room.createThreadsTimelineSets();
|
|
||||||
expect(threadRoot.threadRootId).toEqual(threadRoot.getId());
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).toEqual([threadRoot.getId(), ev.getId()]);
|
|
||||||
|
|
||||||
// When I redact the thread root
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
threadRoot.makeRedacted(redaction, room);
|
|
||||||
|
|
||||||
// Then it remains in the main timeline and the thread
|
|
||||||
expect(threadRoot.threadRootId).toEqual(threadRoot.getId());
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).toEqual([threadRoot.getId(), ev.getId()]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should move into the main timeline when redacted", async () => {
|
|
||||||
// Given an event in a thread
|
|
||||||
const mockClient = createMockClient();
|
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
|
||||||
const threadRoot = createEvent("$threadroot:server");
|
|
||||||
const ev = createThreadedEvent("$event1:server", threadRoot.getId()!);
|
|
||||||
|
|
||||||
await room.addLiveEvents([threadRoot, ev]);
|
|
||||||
await room.createThreadsTimelineSets();
|
|
||||||
expect(ev.threadRootId).toEqual(threadRoot.getId());
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).toEqual([threadRoot.getId(), ev.getId()]);
|
|
||||||
|
|
||||||
// When I redact it
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
ev.makeRedacted(redaction, room);
|
|
||||||
|
|
||||||
// Then it disappears from the thread and appears in the main timeline
|
|
||||||
expect(ev.threadRootId).toBeUndefined();
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).not.toContain(ev.getId());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should move reactions to a redacted event into the main timeline", async () => {
|
|
||||||
// Given an event in a thread with a reaction
|
|
||||||
const mockClient = createMockClient();
|
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
|
||||||
const threadRoot = createEvent("$threadroot:server");
|
|
||||||
const ev = createThreadedEvent("$event1:server", threadRoot.getId()!);
|
|
||||||
const reaction = createReactionEvent("$reaction:server", ev.getId()!);
|
|
||||||
|
|
||||||
await room.addLiveEvents([threadRoot, ev, reaction]);
|
|
||||||
await room.createThreadsTimelineSets();
|
|
||||||
expect(reaction.threadRootId).toEqual(threadRoot.getId());
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).toEqual([threadRoot.getId(), ev.getId(), reaction.getId()]);
|
|
||||||
|
|
||||||
// When I redact the event
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
ev.makeRedacted(redaction, room);
|
|
||||||
|
|
||||||
// Then the reaction moves into the main timeline
|
|
||||||
expect(reaction.threadRootId).toBeUndefined();
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId(), reaction.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).not.toContain(reaction.getId());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should move edits of a redacted event into the main timeline", async () => {
|
|
||||||
// Given an event in a thread with a reaction
|
|
||||||
const mockClient = createMockClient();
|
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
|
||||||
const threadRoot = createEvent("$threadroot:server");
|
|
||||||
const ev = createThreadedEvent("$event1:server", threadRoot.getId()!);
|
|
||||||
const edit = createEditEvent("$edit:server", ev.getId()!);
|
|
||||||
|
|
||||||
await room.addLiveEvents([threadRoot, ev, edit]);
|
|
||||||
await room.createThreadsTimelineSets();
|
|
||||||
expect(edit.threadRootId).toEqual(threadRoot.getId());
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).toEqual([threadRoot.getId(), ev.getId(), edit.getId()]);
|
|
||||||
|
|
||||||
// When I redact the event
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
ev.makeRedacted(redaction, room);
|
|
||||||
|
|
||||||
// Then the edit moves into the main timeline
|
|
||||||
expect(edit.threadRootId).toBeUndefined();
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId(), edit.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).not.toContain(edit.getId());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should move reactions to replies to replies a redacted event into the main timeline", async () => {
|
|
||||||
// Given an event in a thread with a reaction
|
|
||||||
const mockClient = createMockClient();
|
|
||||||
const room = new Room("!roomid:e.xyz", mockClient, "myname");
|
|
||||||
const threadRoot = createEvent("$threadroot:server");
|
|
||||||
const ev = createThreadedEvent("$event1:server", threadRoot.getId()!);
|
|
||||||
const reply1 = createReplyEvent("$reply1:server", ev.getId()!);
|
|
||||||
const reply2 = createReplyEvent("$reply2:server", reply1.getId()!);
|
|
||||||
const reaction = createReactionEvent("$reaction:server", reply2.getId()!);
|
|
||||||
|
|
||||||
await room.addLiveEvents([threadRoot, ev, reply1, reply2, reaction]);
|
|
||||||
await room.createThreadsTimelineSets();
|
|
||||||
expect(reaction.threadRootId).toEqual(threadRoot.getId());
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId()]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).toEqual([
|
|
||||||
threadRoot.getId(),
|
|
||||||
ev.getId(),
|
|
||||||
reply1.getId(),
|
|
||||||
reply2.getId(),
|
|
||||||
reaction.getId(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// When I redact the event
|
|
||||||
const redaction = createRedaction(ev.getId()!);
|
|
||||||
ev.makeRedacted(redaction, room);
|
|
||||||
|
|
||||||
// Then the replies move to the main thread and the reaction disappears
|
|
||||||
expect(reaction.threadRootId).toBeUndefined();
|
|
||||||
expect(mainTimelineLiveEventIds(room)).toEqual([
|
|
||||||
threadRoot.getId(),
|
|
||||||
ev.getId(),
|
|
||||||
reply1.getId(),
|
|
||||||
reply2.getId(),
|
|
||||||
reaction.getId(),
|
|
||||||
]);
|
|
||||||
expect(threadLiveEventIds(room, 0)).not.toContain(reply1.getId());
|
|
||||||
expect(threadLiveEventIds(room, 0)).not.toContain(reply2.getId());
|
|
||||||
expect(threadLiveEventIds(room, 0)).not.toContain(reaction.getId());
|
|
||||||
});
|
|
||||||
|
|
||||||
function createMockClient(): MatrixClient {
|
|
||||||
return {
|
|
||||||
supportsThreads: jest.fn().mockReturnValue(true),
|
|
||||||
decryptEventIfNeeded: jest.fn().mockReturnThis(),
|
|
||||||
getUserId: jest.fn().mockReturnValue("@user:server"),
|
|
||||||
} as unknown as MockedObject<MatrixClient>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEvent(eventId: string, body?: string): MatrixEvent {
|
|
||||||
return new MatrixEvent({
|
|
||||||
type: "m.room.message",
|
|
||||||
content: {
|
|
||||||
body: body ?? eventId,
|
|
||||||
},
|
|
||||||
event_id: eventId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createThreadedEvent(eventId: string, threadRootId: string): MatrixEvent {
|
|
||||||
return new MatrixEvent({
|
|
||||||
type: "m.room.message",
|
|
||||||
content: {
|
|
||||||
"body": eventId,
|
|
||||||
"m.relates_to": {
|
|
||||||
rel_type: THREAD_RELATION_TYPE.name,
|
|
||||||
event_id: threadRootId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
event_id: eventId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEditEvent(eventId: string, repliedToId: string): MatrixEvent {
|
|
||||||
return new MatrixEvent({
|
|
||||||
type: "m.room.message",
|
|
||||||
content: {
|
|
||||||
"body": "Edited",
|
|
||||||
"m.new_content": {
|
|
||||||
body: "Edited",
|
|
||||||
},
|
|
||||||
"m.relates_to": {
|
|
||||||
event_id: repliedToId,
|
|
||||||
rel_type: "m.replace",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
event_id: eventId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createReplyEvent(eventId: string, repliedToId: string): MatrixEvent {
|
|
||||||
return new MatrixEvent({
|
|
||||||
type: "m.room.message",
|
|
||||||
content: {
|
|
||||||
"m.relates_to": {
|
|
||||||
event_id: repliedToId,
|
|
||||||
key: "x",
|
|
||||||
rel_type: "m.in_reply_to",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
event_id: eventId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createReactionEvent(eventId: string, reactedToId: string): MatrixEvent {
|
|
||||||
return new MatrixEvent({
|
|
||||||
type: "m.reaction",
|
|
||||||
content: {
|
|
||||||
"m.relates_to": {
|
|
||||||
event_id: reactedToId,
|
|
||||||
key: "x",
|
|
||||||
rel_type: "m.annotation",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
event_id: eventId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRedaction(redactedEventid: string): MatrixEvent {
|
|
||||||
return new MatrixEvent({
|
|
||||||
type: "m.room.redaction",
|
|
||||||
redacts: redactedEventid,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("applyVisibilityEvent", () => {
|
describe("applyVisibilityEvent", () => {
|
||||||
@ -572,19 +330,3 @@ describe("MatrixEvent", () => {
|
|||||||
expect(stateEvent.threadRootId).toBeUndefined();
|
expect(stateEvent.threadRootId).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function mainTimelineLiveEventIds(room: Room): Array<string> {
|
|
||||||
return room
|
|
||||||
.getLiveTimeline()
|
|
||||||
.getEvents()
|
|
||||||
.map((e) => e.getId()!);
|
|
||||||
}
|
|
||||||
|
|
||||||
function threadLiveEventIds(room: Room, threadIndex: number): Array<string> {
|
|
||||||
return room
|
|
||||||
.getThreads()
|
|
||||||
[threadIndex].getUnfilteredTimelineSet()
|
|
||||||
.getLiveTimeline()
|
|
||||||
.getEvents()
|
|
||||||
.map((e) => e.getId()!);
|
|
||||||
}
|
|
||||||
|
@ -27,7 +27,6 @@ import { M_BEACON } from "../../src/@types/beacon";
|
|||||||
import { MatrixClient } from "../../src/client";
|
import { MatrixClient } from "../../src/client";
|
||||||
import { DecryptionError } from "../../src/crypto/algorithms";
|
import { DecryptionError } from "../../src/crypto/algorithms";
|
||||||
import { defer } from "../../src/utils";
|
import { defer } from "../../src/utils";
|
||||||
import { Room } from "../../src/models/room";
|
|
||||||
|
|
||||||
describe("RoomState", function () {
|
describe("RoomState", function () {
|
||||||
const roomId = "!foo:bar";
|
const roomId = "!foo:bar";
|
||||||
@ -363,11 +362,9 @@ describe("RoomState", function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("does not add redacted beacon info events to state", () => {
|
it("does not add redacted beacon info events to state", () => {
|
||||||
const mockClient = {} as unknown as MockedObject<MatrixClient>;
|
|
||||||
const redactedBeaconEvent = makeBeaconInfoEvent(userA, roomId);
|
const redactedBeaconEvent = makeBeaconInfoEvent(userA, roomId);
|
||||||
const redactionEvent = new MatrixEvent({ type: "m.room.redaction" });
|
const redactionEvent = new MatrixEvent({ type: "m.room.redaction" });
|
||||||
const room = new Room(roomId, mockClient, userA);
|
redactedBeaconEvent.makeRedacted(redactionEvent);
|
||||||
redactedBeaconEvent.makeRedacted(redactionEvent, room);
|
|
||||||
const emitSpy = jest.spyOn(state, "emit");
|
const emitSpy = jest.spyOn(state, "emit");
|
||||||
|
|
||||||
state.setStateEvents([redactedBeaconEvent]);
|
state.setStateEvents([redactedBeaconEvent]);
|
||||||
@ -397,13 +394,11 @@ describe("RoomState", function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("destroys and removes redacted beacon events", () => {
|
it("destroys and removes redacted beacon events", () => {
|
||||||
const mockClient = {} as unknown as MockedObject<MatrixClient>;
|
|
||||||
const beaconId = "$beacon1";
|
const beaconId = "$beacon1";
|
||||||
const beaconEvent = makeBeaconInfoEvent(userA, roomId, { isLive: true }, beaconId);
|
const beaconEvent = makeBeaconInfoEvent(userA, roomId, { isLive: true }, beaconId);
|
||||||
const redactedBeaconEvent = makeBeaconInfoEvent(userA, roomId, { isLive: true }, beaconId);
|
const redactedBeaconEvent = makeBeaconInfoEvent(userA, roomId, { isLive: true }, beaconId);
|
||||||
const redactionEvent = new MatrixEvent({ type: "m.room.redaction", redacts: beaconEvent.getId() });
|
const redactionEvent = new MatrixEvent({ type: "m.room.redaction", redacts: beaconEvent.getId() });
|
||||||
const room = new Room(roomId, mockClient, userA);
|
redactedBeaconEvent.makeRedacted(redactionEvent);
|
||||||
redactedBeaconEvent.makeRedacted(redactionEvent, room);
|
|
||||||
|
|
||||||
state.setStateEvents([beaconEvent]);
|
state.setStateEvents([beaconEvent]);
|
||||||
const beaconInstance = state.beacons.get(getBeaconInfoIdentifier(beaconEvent));
|
const beaconInstance = state.beacons.get(getBeaconInfoIdentifier(beaconEvent));
|
||||||
|
@ -3654,7 +3654,7 @@ describe("Room", function () {
|
|||||||
expect(room.polls.get(pollStartEvent.getId()!)).toBeTruthy();
|
expect(room.polls.get(pollStartEvent.getId()!)).toBeTruthy();
|
||||||
|
|
||||||
const redactedEvent = new MatrixEvent({ type: "m.room.redaction" });
|
const redactedEvent = new MatrixEvent({ type: "m.room.redaction" });
|
||||||
pollStartEvent.makeRedacted(redactedEvent, room);
|
pollStartEvent.makeRedacted(redactedEvent);
|
||||||
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
|
@ -45,8 +45,6 @@ import { DecryptionError } from "../crypto/algorithms";
|
|||||||
import { CryptoBackend } from "../common-crypto/CryptoBackend";
|
import { CryptoBackend } from "../common-crypto/CryptoBackend";
|
||||||
import { WITHHELD_MESSAGES } from "../crypto/OlmDevice";
|
import { WITHHELD_MESSAGES } from "../crypto/OlmDevice";
|
||||||
import { IAnnotatedPushRule } from "../@types/PushRules";
|
import { IAnnotatedPushRule } from "../@types/PushRules";
|
||||||
import { Room } from "./room";
|
|
||||||
import { EventTimeline } from "./event-timeline";
|
|
||||||
|
|
||||||
export { EventStatus } from "./event-status";
|
export { EventStatus } from "./event-status";
|
||||||
|
|
||||||
@ -1152,19 +1150,13 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
|
|||||||
return this.visibility;
|
return this.visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated In favor of the overload that includes a Room argument
|
|
||||||
*/
|
|
||||||
public makeRedacted(redactionEvent: MatrixEvent): void;
|
|
||||||
/**
|
/**
|
||||||
* Update the content of an event in the same way it would be by the server
|
* Update the content of an event in the same way it would be by the server
|
||||||
* if it were redacted before it was sent to us
|
* if it were redacted before it was sent to us
|
||||||
*
|
*
|
||||||
* @param redactionEvent - event causing the redaction
|
* @param redactionEvent - event causing the redaction
|
||||||
* @param room - the room in which the event exists
|
|
||||||
*/
|
*/
|
||||||
public makeRedacted(redactionEvent: MatrixEvent, room: Room): void;
|
public makeRedacted(redactionEvent: MatrixEvent): void {
|
||||||
public makeRedacted(redactionEvent: MatrixEvent, room?: Room): void {
|
|
||||||
// quick sanity-check
|
// quick sanity-check
|
||||||
if (!redactionEvent.event) {
|
if (!redactionEvent.event) {
|
||||||
throw new Error("invalid redactionEvent in makeRedacted");
|
throw new Error("invalid redactionEvent in makeRedacted");
|
||||||
@ -1208,43 +1200,9 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the redacted event was in a thread (but not thread root), move it
|
|
||||||
// to the main timeline. This will change if MSC3389 is merged.
|
|
||||||
if (room && !this.isThreadRoot && this.threadRootId && this.threadRootId !== this.getId()) {
|
|
||||||
this.moveAllRelatedToMainTimeline(room);
|
|
||||||
redactionEvent.moveToMainTimeline(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.invalidateExtensibleEvent();
|
this.invalidateExtensibleEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private moveAllRelatedToMainTimeline(room: Room): void {
|
|
||||||
const thread = this.thread;
|
|
||||||
this.moveToMainTimeline(room);
|
|
||||||
|
|
||||||
// If we dont have access to the thread, we can only move this
|
|
||||||
// event, not things related to it.
|
|
||||||
if (thread) {
|
|
||||||
for (const event of thread.events) {
|
|
||||||
if (event.getRelation()?.event_id === this.getId()) {
|
|
||||||
event.moveAllRelatedToMainTimeline(room);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private moveToMainTimeline(room: Room): void {
|
|
||||||
// Remove it from its thread
|
|
||||||
this.thread?.timelineSet.removeEvent(this.getId()!);
|
|
||||||
this.setThread(undefined);
|
|
||||||
|
|
||||||
// And insert it into the main timeline
|
|
||||||
const timeline = room.getLiveTimeline();
|
|
||||||
// We use insertEventIntoTimeline to insert it in timestamp order,
|
|
||||||
// because we don't know where it should go (until we have MSC4033).
|
|
||||||
timeline.getTimelineSet().insertEventIntoTimeline(this, timeline, timeline.getState(EventTimeline.FORWARDS)!);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this event has been redacted
|
* Check if this event has been redacted
|
||||||
*
|
*
|
||||||
|
@ -236,9 +236,8 @@ export type RoomEventHandlerMap = {
|
|||||||
*
|
*
|
||||||
* @param event - The matrix redaction event
|
* @param event - The matrix redaction event
|
||||||
* @param room - The room containing the redacted event
|
* @param room - The room containing the redacted event
|
||||||
* @param threadId - The thread containing the redacted event (before it was redacted)
|
|
||||||
*/
|
*/
|
||||||
[RoomEvent.Redaction]: (event: MatrixEvent, room: Room, threadId?: string) => void;
|
[RoomEvent.Redaction]: (event: MatrixEvent, room: Room) => void;
|
||||||
/**
|
/**
|
||||||
* Fires when an event that was previously redacted isn't anymore.
|
* Fires when an event that was previously redacted isn't anymore.
|
||||||
* This happens when the redaction couldn't be sent and
|
* This happens when the redaction couldn't be sent and
|
||||||
@ -2114,12 +2113,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|||||||
* Relations (other than m.thread), redactions, replies to a thread root live only in the main timeline
|
* Relations (other than m.thread), redactions, replies to a thread root live only in the main timeline
|
||||||
* Relations, redactions, replies where the parent cannot be found live in no timelines but should be aggregated regardless.
|
* Relations, redactions, replies where the parent cannot be found live in no timelines but should be aggregated regardless.
|
||||||
* Otherwise, the event lives in the main timeline only.
|
* Otherwise, the event lives in the main timeline only.
|
||||||
*
|
|
||||||
* Note: when a redaction is applied, the redacted event, events relating
|
|
||||||
* to it, and the redaction event itself, will all move to the main thread.
|
|
||||||
* This method classifies them as inside the thread of the redacted event.
|
|
||||||
* They are moved later as part of makeRedacted.
|
|
||||||
* This will change if MSC3389 is merged.
|
|
||||||
*/
|
*/
|
||||||
public eventShouldLiveIn(
|
public eventShouldLiveIn(
|
||||||
event: MatrixEvent,
|
event: MatrixEvent,
|
||||||
@ -2336,8 +2329,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|||||||
// if we know about this event, redact its contents now.
|
// if we know about this event, redact its contents now.
|
||||||
const redactedEvent = redactId ? this.findEventById(redactId) : undefined;
|
const redactedEvent = redactId ? this.findEventById(redactId) : undefined;
|
||||||
if (redactedEvent) {
|
if (redactedEvent) {
|
||||||
const threadRootId = redactedEvent.threadRootId;
|
redactedEvent.makeRedacted(event);
|
||||||
redactedEvent.makeRedacted(event, this);
|
|
||||||
|
|
||||||
// If this is in the current state, replace it with the redacted version
|
// If this is in the current state, replace it with the redacted version
|
||||||
if (redactedEvent.isState()) {
|
if (redactedEvent.isState()) {
|
||||||
@ -2350,7 +2342,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit(RoomEvent.Redaction, event, this, threadRootId);
|
this.emit(RoomEvent.Redaction, event, this);
|
||||||
|
|
||||||
// TODO: we stash user displaynames (among other things) in
|
// TODO: we stash user displaynames (among other things) in
|
||||||
// RoomMember objects which are then attached to other events
|
// RoomMember objects which are then attached to other events
|
||||||
@ -2503,7 +2495,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|||||||
}
|
}
|
||||||
if (redactedEvent) {
|
if (redactedEvent) {
|
||||||
redactedEvent.markLocallyRedacted(event);
|
redactedEvent.markLocallyRedacted(event);
|
||||||
this.emit(RoomEvent.Redaction, event, this, redactedEvent.threadRootId);
|
this.emit(RoomEvent.Redaction, event, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -228,8 +228,8 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRedaction = async (event: MatrixEvent, room: Room, threadRootId?: string): Promise<void> => {
|
private onRedaction = async (event: MatrixEvent): Promise<void> => {
|
||||||
if (threadRootId !== this.id) return; // ignore redactions for other timelines
|
if (event.threadRootId !== this.id) return; // ignore redactions for other timelines
|
||||||
if (this.replyCount <= 0) {
|
if (this.replyCount <= 0) {
|
||||||
for (const threadEvent of this.timeline) {
|
for (const threadEvent of this.timeline) {
|
||||||
this.clearEventMetadata(threadEvent);
|
this.clearEventMetadata(threadEvent);
|
||||||
|
Reference in New Issue
Block a user