forked from cadence/out-of-your-element
Store directs in database rather than account data
This commit is contained in:
parent
5e4bea6ce6
commit
954d41269c
6 changed files with 54 additions and 57 deletions
9
src/db/migrations/0024-add-direct.sql
Normal file
9
src/db/migrations/0024-add-direct.sql
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE direct (
|
||||||
|
mxid TEXT NOT NULL,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (mxid)
|
||||||
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
|
COMMIT;
|
38
src/db/orm-defs.d.ts
vendored
38
src/db/orm-defs.d.ts
vendored
|
@ -1,4 +1,9 @@
|
||||||
export type Models = {
|
export type Models = {
|
||||||
|
auto_emoji: {
|
||||||
|
name: string
|
||||||
|
emoji_id: string
|
||||||
|
}
|
||||||
|
|
||||||
channel_room: {
|
channel_room: {
|
||||||
channel_id: string
|
channel_id: string
|
||||||
room_id: string
|
room_id: string
|
||||||
|
@ -14,6 +19,18 @@ export type Models = {
|
||||||
custom_topic: number
|
custom_topic: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
direct: {
|
||||||
|
mxid: string
|
||||||
|
room_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji: {
|
||||||
|
emoji_id: string
|
||||||
|
name: string
|
||||||
|
animated: number
|
||||||
|
mxc_url: string
|
||||||
|
}
|
||||||
|
|
||||||
event_message: {
|
event_message: {
|
||||||
event_id: string
|
event_id: string
|
||||||
message_id: string
|
message_id: string
|
||||||
|
@ -55,6 +72,10 @@ export type Models = {
|
||||||
mxc_url: string
|
mxc_url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
media_proxy: {
|
||||||
|
permitted_hash: number
|
||||||
|
}
|
||||||
|
|
||||||
member_cache: {
|
member_cache: {
|
||||||
room_id: string
|
room_id: string
|
||||||
mxid: string
|
mxid: string
|
||||||
|
@ -99,29 +120,12 @@ export type Models = {
|
||||||
webhook_token: string
|
webhook_token: string
|
||||||
}
|
}
|
||||||
|
|
||||||
emoji: {
|
|
||||||
emoji_id: string
|
|
||||||
name: string
|
|
||||||
animated: number
|
|
||||||
mxc_url: string
|
|
||||||
}
|
|
||||||
|
|
||||||
reaction: {
|
reaction: {
|
||||||
hashed_event_id: number
|
hashed_event_id: number
|
||||||
message_id: string
|
message_id: string
|
||||||
encoded_emoji: string
|
encoded_emoji: string
|
||||||
original_encoding: string | null
|
original_encoding: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_emoji: {
|
|
||||||
name: string
|
|
||||||
emoji_id: string
|
|
||||||
guild_id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
media_proxy: {
|
|
||||||
permitted_hash: number
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Prepared<Row> = {
|
export type Prepared<Row> = {
|
||||||
|
|
|
@ -339,7 +339,13 @@ async event => {
|
||||||
|
|
||||||
if (event.content.membership === "leave" || event.content.membership === "ban") {
|
if (event.content.membership === "leave" || event.content.membership === "ban") {
|
||||||
// Member is gone
|
// Member is gone
|
||||||
return db.prepare("DELETE FROM member_cache WHERE room_id = ? and mxid = ?").run(event.room_id, event.state_key)
|
db.prepare("DELETE FROM member_cache WHERE room_id = ? and mxid = ?").run(event.room_id, event.state_key)
|
||||||
|
|
||||||
|
// Unregister room's use as a direct chat if the bot itself left
|
||||||
|
const bot = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||||
|
if (event.state_key === bot) {
|
||||||
|
db.prepare("DELETE FROM direct WHERE room_id = ?").run(event.room_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const exists = select("channel_room", "room_id", {room_id: event.room_id}) ?? select("guild_space", "space_id", {space_id: event.room_id})
|
const exists = select("channel_room", "room_id", {room_id: event.room_id}) ?? select("guild_space", "space_id", {space_id: event.room_id})
|
||||||
|
|
|
@ -5,7 +5,7 @@ const {randomUUID} = require("crypto")
|
||||||
const {defineEventHandler, getValidatedQuery, sendRedirect, readValidatedBody, createError, getRequestHeader, H3Event} = require("h3")
|
const {defineEventHandler, getValidatedQuery, sendRedirect, readValidatedBody, createError, getRequestHeader, H3Event} = require("h3")
|
||||||
const {LRUCache} = require("lru-cache")
|
const {LRUCache} = require("lru-cache")
|
||||||
|
|
||||||
const {as} = require("../../passthrough")
|
const {as, db, select} = require("../../passthrough")
|
||||||
const {reg} = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
const {sync} = require("../../passthrough")
|
const {sync} = require("../../passthrough")
|
||||||
|
@ -79,15 +79,9 @@ as.router.post("/api/log-in-with-matrix", defineEventHandler(async event => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get list of existing DMs from account data
|
// Check if we have an existing DM
|
||||||
let directData = {}
|
let roomID = select("direct", "room_id", {mxid}).pluck().get()
|
||||||
try {
|
if (roomID) {
|
||||||
directData = await api.getAccountData("m.direct")
|
|
||||||
} catch (e) {}
|
|
||||||
let roomID = directData[mxid]?.at(-1)
|
|
||||||
|
|
||||||
// Reuse an existing DM, if able
|
|
||||||
if (typeof roomID === "string") {
|
|
||||||
// Check that the person is/still in the room
|
// Check that the person is/still in the room
|
||||||
try {
|
try {
|
||||||
var member = await api.getStateEvent(roomID, "m.room.member", mxid)
|
var member = await api.getStateEvent(roomID, "m.room.member", mxid)
|
||||||
|
@ -98,7 +92,8 @@ as.router.post("/api/log-in-with-matrix", defineEventHandler(async event => {
|
||||||
await api.inviteToRoom(roomID, mxid)
|
await api.inviteToRoom(roomID, mxid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No existing DMs, create a new room and invite
|
|
||||||
|
// No existing DM, create a new room and invite
|
||||||
else {
|
else {
|
||||||
roomID = await api.createRoom({
|
roomID = await api.createRoom({
|
||||||
invite: [mxid],
|
invite: [mxid],
|
||||||
|
@ -106,8 +101,7 @@ as.router.post("/api/log-in-with-matrix", defineEventHandler(async event => {
|
||||||
preset: "trusted_private_chat"
|
preset: "trusted_private_chat"
|
||||||
})
|
})
|
||||||
// Store the newly created room in account data (Matrix doesn't do this for us automatically, sigh...)
|
// Store the newly created room in account data (Matrix doesn't do this for us automatically, sigh...)
|
||||||
;(directData[mxid] ??= []).push(roomID)
|
db.prepare("REPLACE INTO direct (mxid, room_id) VALUES (?, ?)").run(mxid, roomID)
|
||||||
await api.setAccountData("m.direct", directData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = randomUUID()
|
const token = randomUUID()
|
||||||
|
|
|
@ -34,7 +34,7 @@ test("log in with matrix: checks if mxid domain format looks valid", async t =>
|
||||||
t.match(error.data.fieldErrors.mxid, /must match pattern/)
|
t.match(error.data.fieldErrors.mxid, /must match pattern/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("log in with matrix: sends message when there is no m.direct data", async t => {
|
test("log in with matrix: sends message when there is no existing dm room", async t => {
|
||||||
const event = {}
|
const event = {}
|
||||||
let called = 0
|
let called = 0
|
||||||
await router.test("post", "/api/log-in-with-matrix", {
|
await router.test("post", "/api/log-in-with-matrix", {
|
||||||
|
@ -42,20 +42,10 @@ test("log in with matrix: sends message when there is no m.direct data", async t
|
||||||
mxid: "@cadence:cadence.moe"
|
mxid: "@cadence:cadence.moe"
|
||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
async getAccountData(type) {
|
|
||||||
called++
|
|
||||||
t.equal(type, "m.direct")
|
|
||||||
throw new MatrixServerError({errcode: "M_NOT_FOUND"})
|
|
||||||
},
|
|
||||||
async createRoom() {
|
async createRoom() {
|
||||||
called++
|
called++
|
||||||
return "!created:cadence.moe"
|
return "!created:cadence.moe"
|
||||||
},
|
},
|
||||||
async setAccountData(type, content) {
|
|
||||||
called++
|
|
||||||
t.equal(type, "m.direct")
|
|
||||||
t.deepEqual(content, {"@cadence:cadence.moe": ["!created:cadence.moe"]})
|
|
||||||
},
|
|
||||||
async sendEvent(roomID, type, content) {
|
async sendEvent(roomID, type, content) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!created:cadence.moe")
|
t.equal(roomID, "!created:cadence.moe")
|
||||||
|
@ -68,7 +58,7 @@ test("log in with matrix: sends message when there is no m.direct data", async t
|
||||||
event
|
event
|
||||||
})
|
})
|
||||||
t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/)
|
t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/)
|
||||||
t.equal(called, 4)
|
t.equal(called, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("log in with matrix: does not send another message when a log in is in progress", async t => {
|
test("log in with matrix: does not send another message when a log in is in progress", async t => {
|
||||||
|
@ -82,7 +72,7 @@ test("log in with matrix: does not send another message when a log in is in prog
|
||||||
t.match(event.node.res.getHeader("location"), /We already sent you a link on Matrix/)
|
t.match(event.node.res.getHeader("location"), /We already sent you a link on Matrix/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("log in with matrix: reuses room from m.direct", async t => {
|
test("log in with matrix: reuses room from direct", async t => {
|
||||||
const event = {}
|
const event = {}
|
||||||
let called = 0
|
let called = 0
|
||||||
await router.test("post", "/api/log-in-with-matrix", {
|
await router.test("post", "/api/log-in-with-matrix", {
|
||||||
|
@ -90,11 +80,6 @@ test("log in with matrix: reuses room from m.direct", async t => {
|
||||||
mxid: "@user1:example.org"
|
mxid: "@user1:example.org"
|
||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
async getAccountData(type) {
|
|
||||||
called++
|
|
||||||
t.equal(type, "m.direct")
|
|
||||||
return {"@user1:example.org": ["!existing:cadence.moe"]}
|
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
async getStateEvent(roomID, type, key) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!existing:cadence.moe")
|
t.equal(roomID, "!existing:cadence.moe")
|
||||||
|
@ -111,10 +96,10 @@ test("log in with matrix: reuses room from m.direct", async t => {
|
||||||
event
|
event
|
||||||
})
|
})
|
||||||
t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/)
|
t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/)
|
||||||
t.equal(called, 3)
|
t.equal(called, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("log in with matrix: reuses room from m.direct, reinviting if user has left", async t => {
|
test("log in with matrix: reuses room from direct, reinviting if user has left", async t => {
|
||||||
const event = {}
|
const event = {}
|
||||||
let called = 0
|
let called = 0
|
||||||
await router.test("post", "/api/log-in-with-matrix", {
|
await router.test("post", "/api/log-in-with-matrix", {
|
||||||
|
@ -122,11 +107,6 @@ test("log in with matrix: reuses room from m.direct, reinviting if user has left
|
||||||
mxid: "@user2:example.org"
|
mxid: "@user2:example.org"
|
||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
async getAccountData(type) {
|
|
||||||
called++
|
|
||||||
t.equal(type, "m.direct")
|
|
||||||
return {"@user2:example.org": ["!existing:cadence.moe"]}
|
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
async getStateEvent(roomID, type, key) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!existing:cadence.moe")
|
t.equal(roomID, "!existing:cadence.moe")
|
||||||
|
@ -148,7 +128,7 @@ test("log in with matrix: reuses room from m.direct, reinviting if user has left
|
||||||
event
|
event
|
||||||
})
|
})
|
||||||
t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/)
|
t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/)
|
||||||
t.equal(called, 4)
|
t.equal(called, 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
// ***** third request *****
|
// ***** third request *****
|
||||||
|
|
|
@ -188,4 +188,8 @@ INSERT INTO invite (mxid, room_id, type, name, avatar, topic) VALUES
|
||||||
('@cadence:cadence.moe', '!room:cadence.moe', NULL, 'some room', NULL, NULL),
|
('@cadence:cadence.moe', '!room:cadence.moe', NULL, 'some room', NULL, NULL),
|
||||||
('@rnl:cadence.moe', '!space:cadence.moe', NULL, 'somebody else''s space', NULL, NULL);
|
('@rnl:cadence.moe', '!space:cadence.moe', NULL, 'somebody else''s space', NULL, NULL);
|
||||||
|
|
||||||
|
INSERT INTO direct (mxid, room_id) VALUES
|
||||||
|
('@user1:example.org', '!existing:cadence.moe'),
|
||||||
|
('@user2:example.org', '!existing:cadence.moe');
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue