You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-06 12:02:40 +03:00
Implement MSC3912: Relation-based redactions (#2954)
This commit is contained in:
@@ -22,11 +22,13 @@ import { Filter } from "../../src/filter";
|
|||||||
import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE } from "../../src/models/MSC3089TreeSpace";
|
import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE } from "../../src/models/MSC3089TreeSpace";
|
||||||
import {
|
import {
|
||||||
EventType,
|
EventType,
|
||||||
|
RelationType,
|
||||||
RoomCreateTypeField,
|
RoomCreateTypeField,
|
||||||
RoomType,
|
RoomType,
|
||||||
UNSTABLE_MSC3088_ENABLED,
|
UNSTABLE_MSC3088_ENABLED,
|
||||||
UNSTABLE_MSC3088_PURPOSE,
|
UNSTABLE_MSC3088_PURPOSE,
|
||||||
UNSTABLE_MSC3089_TREE_SUBTYPE,
|
UNSTABLE_MSC3089_TREE_SUBTYPE,
|
||||||
|
MSC3912_RELATION_BASED_REDACTIONS_PROP,
|
||||||
} from "../../src/@types/event";
|
} from "../../src/@types/event";
|
||||||
import { MEGOLM_ALGORITHM } from "../../src/crypto/olmlib";
|
import { MEGOLM_ALGORITHM } from "../../src/crypto/olmlib";
|
||||||
import { Crypto } from "../../src/crypto";
|
import { Crypto } from "../../src/crypto";
|
||||||
@@ -121,6 +123,10 @@ describe("MatrixClient", function () {
|
|||||||
data: SYNC_DATA,
|
data: SYNC_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const unstableFeatures: Record<string, boolean> = {
|
||||||
|
"org.matrix.msc3440.stable": true,
|
||||||
|
};
|
||||||
|
|
||||||
// items are popped off when processed and block if no items left.
|
// items are popped off when processed and block if no items left.
|
||||||
let httpLookups: HttpLookup[] = [];
|
let httpLookups: HttpLookup[] = [];
|
||||||
let acceptKeepalives: boolean;
|
let acceptKeepalives: boolean;
|
||||||
@@ -132,9 +138,7 @@ describe("MatrixClient", function () {
|
|||||||
function httpReq(method: Method, path: string, qp?: QueryDict, data?: BodyInit, opts?: IRequestOpts) {
|
function httpReq(method: Method, path: string, qp?: QueryDict, data?: BodyInit, opts?: IRequestOpts) {
|
||||||
if (path === KEEP_ALIVE_PATH && acceptKeepalives) {
|
if (path === KEEP_ALIVE_PATH && acceptKeepalives) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
unstable_features: {
|
unstable_features: unstableFeatures,
|
||||||
"org.matrix.msc3440.stable": true,
|
|
||||||
},
|
|
||||||
versions: ["r0.6.0", "r0.6.1"],
|
versions: ["r0.6.0", "r0.6.1"],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1085,6 +1089,59 @@ describe("MatrixClient", function () {
|
|||||||
|
|
||||||
await client.redactEvent(roomId, eventId, txnId, { reason });
|
await client.redactEvent(roomId, eventId, txnId, { reason });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("when calling with with_relations", () => {
|
||||||
|
const eventId = "$event42:example.org";
|
||||||
|
|
||||||
|
it("should raise an error if server has no support for relation based redactions", async () => {
|
||||||
|
// load supported features
|
||||||
|
await client.getVersions();
|
||||||
|
|
||||||
|
const txnId = client.makeTxnId();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
client.redactEvent(roomId, eventId, txnId, {
|
||||||
|
with_relations: [RelationType.Reference],
|
||||||
|
});
|
||||||
|
}).toThrowError(
|
||||||
|
new Error(
|
||||||
|
"Server does not support relation based redactions " +
|
||||||
|
`roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId null`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and the server supports relation based redactions (unstable)", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
unstableFeatures["org.matrix.msc3912"] = true;
|
||||||
|
// load supported features
|
||||||
|
await client.getVersions();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should send with_relations in the request body", async () => {
|
||||||
|
const txnId = client.makeTxnId();
|
||||||
|
|
||||||
|
httpLookups = [
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
path:
|
||||||
|
`/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}` +
|
||||||
|
`/${encodeURIComponent(txnId)}`,
|
||||||
|
expectBody: {
|
||||||
|
reason: "redaction test",
|
||||||
|
[MSC3912_RELATION_BASED_REDACTIONS_PROP.unstable!]: [RelationType.Reference],
|
||||||
|
},
|
||||||
|
data: { event_id: eventId },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
await client.redactEvent(roomId, eventId, txnId, {
|
||||||
|
reason: "redaction test",
|
||||||
|
with_relations: [RelationType.Reference],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("cancelPendingEvent", () => {
|
describe("cancelPendingEvent", () => {
|
||||||
|
@@ -165,6 +165,15 @@ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix
|
|||||||
*/
|
*/
|
||||||
export const UNSTABLE_MSC2716_MARKER = new UnstableValue("m.room.marker", "org.matrix.msc2716.marker");
|
export const UNSTABLE_MSC2716_MARKER = new UnstableValue("m.room.marker", "org.matrix.msc2716.marker");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the "with_relations" request property for relation based redactions.
|
||||||
|
* {@link https://github.com/matrix-org/matrix-spec-proposals/pull/3912}
|
||||||
|
*/
|
||||||
|
export const MSC3912_RELATION_BASED_REDACTIONS_PROP = new UnstableValue(
|
||||||
|
"with_relations",
|
||||||
|
"org.matrix.msc3912.with_relations",
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional members type for declaring a purpose of room members (e.g. helpful bots).
|
* Functional members type for declaring a purpose of room members (e.g. helpful bots).
|
||||||
* Note that this reference is UNSTABLE and subject to breaking changes, including its
|
* Note that this reference is UNSTABLE and subject to breaking changes, including its
|
||||||
|
@@ -21,7 +21,7 @@ import { IRoomEventFilter } from "../filter";
|
|||||||
import { Direction } from "../models/event-timeline";
|
import { Direction } from "../models/event-timeline";
|
||||||
import { PushRuleAction } from "./PushRules";
|
import { PushRuleAction } from "./PushRules";
|
||||||
import { IRoomEvent } from "../sync-accumulator";
|
import { IRoomEvent } from "../sync-accumulator";
|
||||||
import { EventType, RoomType } from "./event";
|
import { EventType, RelationType, RoomType } from "./event";
|
||||||
|
|
||||||
// allow camelcase as these are things that go onto the wire
|
// allow camelcase as these are things that go onto the wire
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
@@ -47,6 +47,18 @@ export interface IJoinRoomOpts {
|
|||||||
|
|
||||||
export interface IRedactOpts {
|
export interface IRedactOpts {
|
||||||
reason?: string;
|
reason?: string;
|
||||||
|
/**
|
||||||
|
* Whether events related to the redacted event should be redacted.
|
||||||
|
*
|
||||||
|
* If specified, then any events which relate to the event being redacted with
|
||||||
|
* any of the relationship types listed will also be redacted.
|
||||||
|
*
|
||||||
|
* <b>Raises an Error if the server does not support it.</b>
|
||||||
|
* Check for server-side support before using this param with
|
||||||
|
* <code>client.canSupport.get(Feature.RelationBasedRedactions)</code>.
|
||||||
|
* {@link https://github.com/matrix-org/matrix-spec-proposals/pull/3912}
|
||||||
|
*/
|
||||||
|
with_relations?: Array<RelationType | string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISendEventResponse {
|
export interface ISendEventResponse {
|
||||||
|
@@ -154,6 +154,7 @@ import {
|
|||||||
UNSTABLE_MSC3088_ENABLED,
|
UNSTABLE_MSC3088_ENABLED,
|
||||||
UNSTABLE_MSC3088_PURPOSE,
|
UNSTABLE_MSC3088_PURPOSE,
|
||||||
UNSTABLE_MSC3089_TREE_SUBTYPE,
|
UNSTABLE_MSC3089_TREE_SUBTYPE,
|
||||||
|
MSC3912_RELATION_BASED_REDACTIONS_PROP,
|
||||||
} from "./@types/event";
|
} from "./@types/event";
|
||||||
import { IdServerUnbindResult, IImageInfo, Preset, Visibility } from "./@types/partials";
|
import { IdServerUnbindResult, IImageInfo, Preset, Visibility } from "./@types/partials";
|
||||||
import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper";
|
import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper";
|
||||||
@@ -4444,9 +4445,11 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param txnId - transaction id. One will be made up if not supplied.
|
* @param txnId - transaction id. One will be made up if not supplied.
|
||||||
* @param opts - Options to pass on, may contain `reason`.
|
* @param opts - Options to pass on, may contain `reason` and `with_relations` (MSC3912)
|
||||||
* @returns Promise which resolves: TODO
|
* @returns Promise which resolves: TODO
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
|
* @throws Error if called with `with_relations` (MSC3912) but the server does not support it.
|
||||||
|
* Callers should check whether the server supports MSC3912 via `MatrixClient.canSupport`.
|
||||||
*/
|
*/
|
||||||
public redactEvent(
|
public redactEvent(
|
||||||
roomId: string,
|
roomId: string,
|
||||||
@@ -4475,12 +4478,34 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
threadId = null;
|
threadId = null;
|
||||||
}
|
}
|
||||||
const reason = opts?.reason;
|
const reason = opts?.reason;
|
||||||
|
|
||||||
|
if (
|
||||||
|
opts?.with_relations &&
|
||||||
|
this.canSupport.get(Feature.RelationBasedRedactions) === ServerSupport.Unsupported
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Server does not support relation based redactions " +
|
||||||
|
`roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId ${threadId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const withRelations = opts?.with_relations
|
||||||
|
? {
|
||||||
|
[this.canSupport.get(Feature.RelationBasedRedactions) === ServerSupport.Stable
|
||||||
|
? MSC3912_RELATION_BASED_REDACTIONS_PROP.stable!
|
||||||
|
: MSC3912_RELATION_BASED_REDACTIONS_PROP.unstable!]: opts?.with_relations,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
return this.sendCompleteEvent(
|
return this.sendCompleteEvent(
|
||||||
roomId,
|
roomId,
|
||||||
threadId,
|
threadId,
|
||||||
{
|
{
|
||||||
type: EventType.RoomRedaction,
|
type: EventType.RoomRedaction,
|
||||||
content: { reason },
|
content: {
|
||||||
|
...withRelations,
|
||||||
|
reason,
|
||||||
|
},
|
||||||
redacts: eventId,
|
redacts: eventId,
|
||||||
},
|
},
|
||||||
txnId as string,
|
txnId as string,
|
||||||
|
@@ -26,6 +26,7 @@ export enum Feature {
|
|||||||
Thread = "Thread",
|
Thread = "Thread",
|
||||||
ThreadUnreadNotifications = "ThreadUnreadNotifications",
|
ThreadUnreadNotifications = "ThreadUnreadNotifications",
|
||||||
LoginTokenRequest = "LoginTokenRequest",
|
LoginTokenRequest = "LoginTokenRequest",
|
||||||
|
RelationBasedRedactions = "RelationBasedRedactions",
|
||||||
AccountDataDeletion = "AccountDataDeletion",
|
AccountDataDeletion = "AccountDataDeletion",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +47,9 @@ const featureSupportResolver: Record<string, FeatureSupportCondition> = {
|
|||||||
[Feature.LoginTokenRequest]: {
|
[Feature.LoginTokenRequest]: {
|
||||||
unstablePrefixes: ["org.matrix.msc3882"],
|
unstablePrefixes: ["org.matrix.msc3882"],
|
||||||
},
|
},
|
||||||
|
[Feature.RelationBasedRedactions]: {
|
||||||
|
unstablePrefixes: ["org.matrix.msc3912"],
|
||||||
|
},
|
||||||
[Feature.AccountDataDeletion]: {
|
[Feature.AccountDataDeletion]: {
|
||||||
unstablePrefixes: ["org.matrix.msc3391"],
|
unstablePrefixes: ["org.matrix.msc3391"],
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user