Add actions for integration manager to send and read certain events (#9740)
* Add send_event action * Add read_events action * Add e2e tests for send_event * Allow more event types to be read * Fix error message * Add e2e tests for read_events * Run i18n * Improve error messages * Fix types * Remove unused test helpers * Fix more type errors * Run prettier * Fix more type errors * Fix validation Since typeof null is "object" Co-authored-by: Travis Ralston <travisr@matrix.org>
This commit is contained in:
parent
d6e447b934
commit
6585fb1f55
4 changed files with 711 additions and 3 deletions
276
cypress/e2e/integration-manager/read_events.spec.ts
Normal file
276
cypress/e2e/integration-manager/read_events.spec.ts
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
||||
import { UserCredentials } from "../../support/login";
|
||||
|
||||
const ROOM_NAME = "Integration Manager Test";
|
||||
const USER_DISPLAY_NAME = "Alice";
|
||||
|
||||
const INTEGRATION_MANAGER_TOKEN = "DefinitelySecret_DoNotUseThisForReal";
|
||||
const INTEGRATION_MANAGER_HTML = `
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Fake Integration Manager</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="text" id="target-room-id"/>
|
||||
<input type="text" id="event-type"/>
|
||||
<input type="text" id="state-key"/>
|
||||
<button name="Send" id="send-action">Press to send action</button>
|
||||
<button name="Close" id="close">Press to close</button>
|
||||
<p id="message-response">No response</p>
|
||||
<script>
|
||||
document.getElementById("send-action").onclick = () => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action: "read_events",
|
||||
room_id: document.getElementById("target-room-id").value,
|
||||
type: document.getElementById("event-type").value,
|
||||
state_key: JSON.parse(document.getElementById("state-key").value),
|
||||
},
|
||||
'*',
|
||||
);
|
||||
};
|
||||
document.getElementById("close").onclick = () => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action: "close_scalar",
|
||||
},
|
||||
'*',
|
||||
);
|
||||
};
|
||||
// Listen for a postmessage response
|
||||
window.addEventListener("message", (event) => {
|
||||
document.getElementById("message-response").innerText = JSON.stringify(event.data);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
function openIntegrationManager() {
|
||||
cy.get(".mx_RightPanel_roomSummaryButton").click();
|
||||
cy.get(".mx_RoomSummaryCard_appsGroup").within(() => {
|
||||
cy.contains("Add widgets, bridges & bots").click();
|
||||
});
|
||||
}
|
||||
|
||||
function sendActionFromIntegrationManager(
|
||||
integrationManagerUrl: string,
|
||||
targetRoomId: string,
|
||||
eventType: string,
|
||||
stateKey: string | boolean,
|
||||
) {
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#target-room-id").should("exist").type(targetRoomId);
|
||||
cy.get("#event-type").should("exist").type(eventType);
|
||||
cy.get("#state-key").should("exist").type(JSON.stringify(stateKey));
|
||||
cy.get("#send-action").should("exist").click();
|
||||
});
|
||||
}
|
||||
|
||||
describe("Integration Manager: Read Events", () => {
|
||||
let testUser: UserCredentials;
|
||||
let synapse: SynapseInstance;
|
||||
let integrationManagerUrl: string;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
||||
integrationManagerUrl = url;
|
||||
});
|
||||
cy.startSynapse("default").then((data) => {
|
||||
synapse = data;
|
||||
|
||||
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem("mx_scalar_token", INTEGRATION_MANAGER_TOKEN);
|
||||
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
||||
});
|
||||
}).then((user) => {
|
||||
testUser = user;
|
||||
});
|
||||
|
||||
cy.setAccountData("m.widgets", {
|
||||
"m.integration_manager": {
|
||||
content: {
|
||||
type: "m.integration_manager",
|
||||
name: "Integration Manager",
|
||||
url: integrationManagerUrl,
|
||||
data: {
|
||||
api_url: integrationManagerUrl,
|
||||
},
|
||||
},
|
||||
id: "integration-manager",
|
||||
},
|
||||
}).as("integrationManager");
|
||||
|
||||
// Succeed when checking the token is valid
|
||||
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, (req) => {
|
||||
req.continue((res) => {
|
||||
return res.send(200, {
|
||||
user_id: testUser.userId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.createRoom({
|
||||
name: ROOM_NAME,
|
||||
}).as("roomId");
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.stopSynapse(synapse);
|
||||
cy.stopWebServers();
|
||||
});
|
||||
|
||||
it("should read a state event by state key", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
const eventType = "io.element.integrations.installations";
|
||||
const eventContent = {
|
||||
foo: "bar",
|
||||
};
|
||||
const stateKey = "state-key-123";
|
||||
|
||||
// Send a state event
|
||||
cy.getClient()
|
||||
.then(async (client) => {
|
||||
return await client.sendStateEvent(roomId, eventType, eventContent, stateKey);
|
||||
})
|
||||
.then((event) => {
|
||||
openIntegrationManager();
|
||||
|
||||
// Read state events
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response")
|
||||
.should("include.text", event.event_id)
|
||||
.should("include.text", `"content":${JSON.stringify(eventContent)}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should read a state event with empty state key", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
const eventType = "io.element.integrations.installations";
|
||||
const eventContent = {
|
||||
foo: "bar",
|
||||
};
|
||||
const stateKey = "";
|
||||
|
||||
// Send a state event
|
||||
cy.getClient()
|
||||
.then(async (client) => {
|
||||
return await client.sendStateEvent(roomId, eventType, eventContent, stateKey);
|
||||
})
|
||||
.then((event) => {
|
||||
openIntegrationManager();
|
||||
|
||||
// Read state events
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response")
|
||||
.should("include.text", event.event_id)
|
||||
.should("include.text", `"content":${JSON.stringify(eventContent)}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should read state events with any state key", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
const eventType = "io.element.integrations.installations";
|
||||
|
||||
const stateKey1 = "state-key-123";
|
||||
const eventContent1 = {
|
||||
foo1: "bar1",
|
||||
};
|
||||
const stateKey2 = "state-key-456";
|
||||
const eventContent2 = {
|
||||
foo2: "bar2",
|
||||
};
|
||||
const stateKey3 = "state-key-789";
|
||||
const eventContent3 = {
|
||||
foo3: "bar3",
|
||||
};
|
||||
|
||||
// Send state events
|
||||
cy.getClient()
|
||||
.then(async (client) => {
|
||||
return Promise.all([
|
||||
client.sendStateEvent(roomId, eventType, eventContent1, stateKey1),
|
||||
client.sendStateEvent(roomId, eventType, eventContent2, stateKey2),
|
||||
client.sendStateEvent(roomId, eventType, eventContent3, stateKey3),
|
||||
]);
|
||||
})
|
||||
.then((events) => {
|
||||
openIntegrationManager();
|
||||
|
||||
// Read state events
|
||||
sendActionFromIntegrationManager(
|
||||
integrationManagerUrl,
|
||||
roomId,
|
||||
eventType,
|
||||
true, // Any state key
|
||||
);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response")
|
||||
.should("include.text", events[0].event_id)
|
||||
.should("include.text", `"content":${JSON.stringify(eventContent1)}`)
|
||||
.should("include.text", events[1].event_id)
|
||||
.should("include.text", `"content":${JSON.stringify(eventContent2)}`)
|
||||
.should("include.text", events[2].event_id)
|
||||
.should("include.text", `"content":${JSON.stringify(eventContent3)}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail to read an event type which is not allowed", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
const eventType = "com.example.event";
|
||||
const stateKey = "";
|
||||
|
||||
openIntegrationManager();
|
||||
|
||||
// Read state events
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response").should("include.text", "Failed to read events");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
261
cypress/e2e/integration-manager/send_event.spec.ts
Normal file
261
cypress/e2e/integration-manager/send_event.spec.ts
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
||||
import { UserCredentials } from "../../support/login";
|
||||
|
||||
const ROOM_NAME = "Integration Manager Test";
|
||||
const USER_DISPLAY_NAME = "Alice";
|
||||
|
||||
const INTEGRATION_MANAGER_TOKEN = "DefinitelySecret_DoNotUseThisForReal";
|
||||
const INTEGRATION_MANAGER_HTML = `
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Fake Integration Manager</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="text" id="target-room-id"/>
|
||||
<input type="text" id="event-type"/>
|
||||
<input type="text" id="state-key"/>
|
||||
<input type="text" id="event-content"/>
|
||||
<button name="Send" id="send-action">Press to send action</button>
|
||||
<button name="Close" id="close">Press to close</button>
|
||||
<p id="message-response">No response</p>
|
||||
<script>
|
||||
document.getElementById("send-action").onclick = () => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action: "send_event",
|
||||
room_id: document.getElementById("target-room-id").value,
|
||||
type: document.getElementById("event-type").value,
|
||||
state_key: document.getElementById("state-key").value,
|
||||
content: JSON.parse(document.getElementById("event-content").value),
|
||||
},
|
||||
'*',
|
||||
);
|
||||
};
|
||||
document.getElementById("close").onclick = () => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action: "close_scalar",
|
||||
},
|
||||
'*',
|
||||
);
|
||||
};
|
||||
// Listen for a postmessage response
|
||||
window.addEventListener("message", (event) => {
|
||||
document.getElementById("message-response").innerText = JSON.stringify(event.data);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
function openIntegrationManager() {
|
||||
cy.get(".mx_RightPanel_roomSummaryButton").click();
|
||||
cy.get(".mx_RoomSummaryCard_appsGroup").within(() => {
|
||||
cy.contains("Add widgets, bridges & bots").click();
|
||||
});
|
||||
}
|
||||
|
||||
function sendActionFromIntegrationManager(
|
||||
integrationManagerUrl: string,
|
||||
targetRoomId: string,
|
||||
eventType: string,
|
||||
stateKey: string,
|
||||
content: Record<string, unknown>,
|
||||
) {
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#target-room-id").should("exist").type(targetRoomId);
|
||||
cy.get("#event-type").should("exist").type(eventType);
|
||||
if (stateKey) {
|
||||
cy.get("#state-key").should("exist").type(stateKey);
|
||||
}
|
||||
cy.get("#event-content").should("exist").type(JSON.stringify(content), { parseSpecialCharSequences: false });
|
||||
cy.get("#send-action").should("exist").click();
|
||||
});
|
||||
}
|
||||
|
||||
describe("Integration Manager: Send Event", () => {
|
||||
let testUser: UserCredentials;
|
||||
let synapse: SynapseInstance;
|
||||
let integrationManagerUrl: string;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
|
||||
integrationManagerUrl = url;
|
||||
});
|
||||
cy.startSynapse("default").then((data) => {
|
||||
synapse = data;
|
||||
|
||||
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem("mx_scalar_token", INTEGRATION_MANAGER_TOKEN);
|
||||
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
|
||||
});
|
||||
}).then((user) => {
|
||||
testUser = user;
|
||||
});
|
||||
|
||||
cy.setAccountData("m.widgets", {
|
||||
"m.integration_manager": {
|
||||
content: {
|
||||
type: "m.integration_manager",
|
||||
name: "Integration Manager",
|
||||
url: integrationManagerUrl,
|
||||
data: {
|
||||
api_url: integrationManagerUrl,
|
||||
},
|
||||
},
|
||||
id: "integration-manager",
|
||||
},
|
||||
}).as("integrationManager");
|
||||
|
||||
// Succeed when checking the token is valid
|
||||
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, (req) => {
|
||||
req.continue((res) => {
|
||||
return res.send(200, {
|
||||
user_id: testUser.userId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.createRoom({
|
||||
name: ROOM_NAME,
|
||||
}).as("roomId");
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.stopSynapse(synapse);
|
||||
cy.stopWebServers();
|
||||
});
|
||||
|
||||
it("should send a state event", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
openIntegrationManager();
|
||||
|
||||
const eventType = "io.element.integrations.installations";
|
||||
const eventContent = {
|
||||
foo: "bar",
|
||||
};
|
||||
const stateKey = "state-key-123";
|
||||
|
||||
// Send the event
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey, eventContent);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response").should("include.text", "event_id");
|
||||
});
|
||||
|
||||
// Check the event
|
||||
cy.getClient()
|
||||
.then(async (client) => {
|
||||
return await client.getStateEvent(roomId, eventType, stateKey);
|
||||
})
|
||||
.then((event) => {
|
||||
expect(event).to.deep.equal(eventContent);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should send a state event with empty content", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
openIntegrationManager();
|
||||
|
||||
const eventType = "io.element.integrations.installations";
|
||||
const eventContent = {};
|
||||
const stateKey = "state-key-123";
|
||||
|
||||
// Send the event
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey, eventContent);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response").should("include.text", "event_id");
|
||||
});
|
||||
|
||||
// Check the event
|
||||
cy.getClient()
|
||||
.then(async (client) => {
|
||||
return await client.getStateEvent(roomId, eventType, stateKey);
|
||||
})
|
||||
.then((event) => {
|
||||
expect(event).to.be.empty;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should send a state event with empty state key", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
openIntegrationManager();
|
||||
|
||||
const eventType = "io.element.integrations.installations";
|
||||
const eventContent = {
|
||||
foo: "bar",
|
||||
};
|
||||
const stateKey = "";
|
||||
|
||||
// Send the event
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey, eventContent);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response").should("include.text", "event_id");
|
||||
});
|
||||
|
||||
// Check the event
|
||||
cy.getClient()
|
||||
.then(async (client) => {
|
||||
return await client.getStateEvent(roomId, eventType, stateKey);
|
||||
})
|
||||
.then((event) => {
|
||||
expect(event).to.deep.equal(eventContent);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail to send an event type which is not allowed", () => {
|
||||
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
|
||||
cy.viewRoomByName(ROOM_NAME);
|
||||
|
||||
openIntegrationManager();
|
||||
|
||||
const eventType = "com.example.event";
|
||||
const eventContent = {
|
||||
foo: "bar",
|
||||
};
|
||||
const stateKey = "";
|
||||
|
||||
// Send the event
|
||||
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey, eventContent);
|
||||
|
||||
// Check the response
|
||||
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
|
||||
cy.get("#message-response").should("include.text", "Failed to send event");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -264,10 +264,36 @@ Get an openID token for the current user session.
|
|||
Request: No parameters
|
||||
Response:
|
||||
- The openId token object as described in https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3useruseridopenidrequest_token
|
||||
|
||||
send_event
|
||||
----------
|
||||
Sends an event in a room.
|
||||
|
||||
Request:
|
||||
- type is the event type to send.
|
||||
- state_key is the state key to send. Omitted if not a state event.
|
||||
- content is the event content to send.
|
||||
|
||||
Response:
|
||||
- room_id is the room ID where the event was sent.
|
||||
- event_id is the event ID of the event which was sent.
|
||||
|
||||
read_events
|
||||
-----------
|
||||
Read events from a room.
|
||||
|
||||
Request:
|
||||
- type is the event type to read.
|
||||
- state_key is the state key to read, or `true` to read all events of the type. Omitted if not a state event.
|
||||
|
||||
Response:
|
||||
- events: Array of events. If none found, this will be an empty array.
|
||||
|
||||
*/
|
||||
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { IContent, MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { IEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import dis from "./dispatcher/dispatcher";
|
||||
|
@ -295,6 +321,8 @@ enum Action {
|
|||
SetBotOptions = "set_bot_options",
|
||||
SetBotPower = "set_bot_power",
|
||||
GetOpenIdToken = "get_open_id_token",
|
||||
SendEvent = "send_event",
|
||||
ReadEvents = "read_events",
|
||||
}
|
||||
|
||||
function sendResponse(event: MessageEvent<any>, res: any): void {
|
||||
|
@ -468,13 +496,13 @@ function setWidget(event: MessageEvent<any>, roomId: string | null): void {
|
|||
}
|
||||
}
|
||||
|
||||
function getWidgets(event: MessageEvent<any>, roomId: string): void {
|
||||
function getWidgets(event: MessageEvent<any>, roomId: string | null): void {
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("You need to be logged in."));
|
||||
return;
|
||||
}
|
||||
let widgetStateEvents = [];
|
||||
let widgetStateEvents: Partial<IEvent>[] = [];
|
||||
|
||||
if (roomId) {
|
||||
const room = client.getRoom(roomId);
|
||||
|
@ -693,6 +721,141 @@ async function getOpenIdToken(event: MessageEvent<any>) {
|
|||
}
|
||||
}
|
||||
|
||||
async function sendEvent(
|
||||
event: MessageEvent<{
|
||||
type: string;
|
||||
state_key?: string;
|
||||
content?: IContent;
|
||||
}>,
|
||||
roomId: string,
|
||||
) {
|
||||
const eventType = event.data.type;
|
||||
const stateKey = event.data.state_key;
|
||||
const content = event.data.content;
|
||||
|
||||
if (typeof eventType !== "string") {
|
||||
sendError(event, _t("Failed to send event"), new Error("Invalid 'type' in request"));
|
||||
return;
|
||||
}
|
||||
const allowedEventTypes = ["m.widgets", "im.vector.modular.widgets", "io.element.integrations.installations"];
|
||||
if (!allowedEventTypes.includes(eventType)) {
|
||||
sendError(event, _t("Failed to send event"), new Error("Disallowed 'type' in request"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!content || typeof content !== "object") {
|
||||
sendError(event, _t("Failed to send event"), new Error("Invalid 'content' in request"));
|
||||
return;
|
||||
}
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("You need to be logged in."));
|
||||
return;
|
||||
}
|
||||
|
||||
const room = client.getRoom(roomId);
|
||||
if (!room) {
|
||||
sendError(event, _t("This room is not recognised."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateKey !== undefined) {
|
||||
// state event
|
||||
try {
|
||||
const res = await client.sendStateEvent(roomId, eventType, content, stateKey);
|
||||
sendResponse(event, {
|
||||
room_id: roomId,
|
||||
event_id: res.event_id,
|
||||
});
|
||||
} catch (e) {
|
||||
sendError(event, _t("Failed to send event"), e as Error);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// message event
|
||||
sendError(event, _t("Failed to send event"), new Error("Sending message events is not implemented"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function readEvents(
|
||||
event: MessageEvent<{
|
||||
type: string;
|
||||
state_key?: string | boolean;
|
||||
limit?: number;
|
||||
}>,
|
||||
roomId: string,
|
||||
) {
|
||||
const eventType = event.data.type;
|
||||
const stateKey = event.data.state_key;
|
||||
const limit = event.data.limit;
|
||||
|
||||
if (typeof eventType !== "string") {
|
||||
sendError(event, _t("Failed to read events"), new Error("Invalid 'type' in request"));
|
||||
return;
|
||||
}
|
||||
const allowedEventTypes = [
|
||||
"m.room.power_levels",
|
||||
"m.room.encryption",
|
||||
"m.room.member",
|
||||
"m.room.name",
|
||||
"m.widgets",
|
||||
"im.vector.modular.widgets",
|
||||
"io.element.integrations.installations",
|
||||
];
|
||||
if (!allowedEventTypes.includes(eventType)) {
|
||||
sendError(event, _t("Failed to read events"), new Error("Disallowed 'type' in request"));
|
||||
return;
|
||||
}
|
||||
|
||||
let effectiveLimit: number;
|
||||
if (limit !== undefined) {
|
||||
if (typeof limit !== "number" || limit < 0) {
|
||||
sendError(event, _t("Failed to read events"), new Error("Invalid 'limit' in request"));
|
||||
return;
|
||||
}
|
||||
effectiveLimit = Math.min(limit, Number.MAX_SAFE_INTEGER);
|
||||
} else {
|
||||
effectiveLimit = Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("You need to be logged in."));
|
||||
return;
|
||||
}
|
||||
|
||||
const room = client.getRoom(roomId);
|
||||
if (!room) {
|
||||
sendError(event, _t("This room is not recognised."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateKey !== undefined) {
|
||||
// state events
|
||||
if (typeof stateKey !== "string" && stateKey !== true) {
|
||||
sendError(event, _t("Failed to read events"), new Error("Invalid 'state_key' in request"));
|
||||
return;
|
||||
}
|
||||
// When `true` is passed for state key, get events with any state key.
|
||||
const effectiveStateKey = stateKey === true ? undefined : stateKey;
|
||||
|
||||
let events: MatrixEvent[] = [];
|
||||
events = events.concat(room.currentState.getStateEvents(eventType, effectiveStateKey as string) || []);
|
||||
events = events.slice(0, effectiveLimit);
|
||||
|
||||
sendResponse(event, {
|
||||
events: events.map((e) => e.getEffectiveEvent()),
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// message events
|
||||
sendError(event, _t("Failed to read events"), new Error("Reading message events is not implemented"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const onMessage = function (event: MessageEvent<any>): void {
|
||||
if (!event.origin) {
|
||||
// stupid chrome
|
||||
|
@ -786,6 +949,12 @@ const onMessage = function (event: MessageEvent<any>): void {
|
|||
} else if (event.data.action === Action.CanSendEvent) {
|
||||
canSendEvent(event, roomId);
|
||||
return;
|
||||
} else if (event.data.action === Action.SendEvent) {
|
||||
sendEvent(event, roomId);
|
||||
return;
|
||||
} else if (event.data.action === Action.ReadEvents) {
|
||||
readEvents(event, roomId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!userId) {
|
||||
|
|
|
@ -390,6 +390,8 @@
|
|||
"Power level must be positive integer.": "Power level must be positive integer.",
|
||||
"You are not in this room.": "You are not in this room.",
|
||||
"You do not have permission to do that in this room.": "You do not have permission to do that in this room.",
|
||||
"Failed to send event": "Failed to send event",
|
||||
"Failed to read events": "Failed to read events",
|
||||
"Missing room_id in request": "Missing room_id in request",
|
||||
"Room %(roomId)s not visible": "Room %(roomId)s not visible",
|
||||
"Missing user_id in request": "Missing user_id in request",
|
||||
|
|
Loading…
Reference in a new issue