Maybe accept invites more reliably
This commit is contained in:
@@ -568,6 +568,7 @@ module.exports.createAllForGuild = createAllForGuild
|
||||
module.exports.channelToKState = channelToKState
|
||||
module.exports.postApplyPowerLevels = postApplyPowerLevels
|
||||
module.exports._convertNameAndTopic = convertNameAndTopic
|
||||
module.exports._syncSpaceMember = _syncSpaceMember
|
||||
module.exports.unbridgeChannel = unbridgeChannel
|
||||
module.exports.unbridgeDeletedChannel = unbridgeDeletedChannel
|
||||
module.exports.existsOrAutocreatable = existsOrAutocreatable
|
||||
|
||||
@@ -322,14 +322,25 @@ sync.addTemporaryListener(as, "type:m.room.member", guard("m.room.member",
|
||||
*/
|
||||
async event => {
|
||||
if (event.state_key[0] !== "@") return
|
||||
const bot = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||
|
||||
if (event.content.membership === "invite" && event.state_key === `@${reg.sender_localpart}:${reg.ooye.server_name}`) {
|
||||
if (event.content.membership === "invite" && event.state_key === bot) {
|
||||
// We were invited to a room. We should join, and register the invite details for future reference in web.
|
||||
let attemptedApiMessage = "According to unsigned invite data."
|
||||
let inviteRoomState = event.unsigned?.invite_room_state
|
||||
if (!Array.isArray(inviteRoomState) || inviteRoomState.length === 0) {
|
||||
try {
|
||||
inviteRoomState = await api.getInviteState(event.room_id)
|
||||
attemptedApiMessage = "According to SSS API."
|
||||
} catch (e) {
|
||||
attemptedApiMessage = "According to unsigned invite data. SSS API unavailable: " + e.toString()
|
||||
}
|
||||
}
|
||||
const name = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.name", "name")
|
||||
const topic = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.topic", "topic")
|
||||
const avatar = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.avatar", "url")
|
||||
const creationType = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.create", "type")
|
||||
if (!name) return await api.leaveRoomWithReason(event.room_id, "Please only invite me to rooms that have a name/avatar set. Update the room details and reinvite!")
|
||||
if (!name) return await api.leaveRoomWithReason(event.room_id, `Please only invite me to rooms that have a name/avatar set. Update the room details and reinvite! (${attemptedApiMessage})`)
|
||||
await api.joinRoom(event.room_id)
|
||||
db.prepare("INSERT OR IGNORE INTO invite (mxid, room_id, type, name, topic, avatar) VALUES (?, ?, ?, ?, ?, ?)").run(event.sender, event.room_id, creationType, name, topic, avatar)
|
||||
if (avatar) utils.getPublicUrlForMxc(avatar) // make sure it's available in the media_proxy allowed URLs
|
||||
@@ -342,7 +353,6 @@ async event => {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -137,6 +137,24 @@ function getStateEvent(roomID, type, key) {
|
||||
return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state/${type}/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} roomID
|
||||
* @returns {Promise<Ty.Event.InviteStrippedState[]>}
|
||||
*/
|
||||
async function getInviteState(roomID) {
|
||||
/** @type {Ty.R.SSS} */
|
||||
const root = await mreq.mreq("POST", "/client/unstable/org.matrix.simplified_msc3575/sync", {
|
||||
room_subscriptions: {
|
||||
[roomID]: {
|
||||
timeline_limit: 0,
|
||||
required_state: []
|
||||
}
|
||||
}
|
||||
})
|
||||
const roomResponse = root.rooms[roomID]
|
||||
return "stripped_state" in roomResponse ? roomResponse.stripped_state : roomResponse.invite_state
|
||||
}
|
||||
|
||||
/**
|
||||
* "Any of the AS's users must be in the room. This API is primarily for Application Services and should be faster to respond than /members as it can be implemented more efficiently on the server."
|
||||
* @param {string} roomID
|
||||
@@ -483,6 +501,7 @@ module.exports.getEvent = getEvent
|
||||
module.exports.getEventForTimestamp = getEventForTimestamp
|
||||
module.exports.getAllState = getAllState
|
||||
module.exports.getStateEvent = getStateEvent
|
||||
module.exports.getInviteState = getInviteState
|
||||
module.exports.getJoinedMembers = getJoinedMembers
|
||||
module.exports.getMembers = getMembers
|
||||
module.exports.getHierarchy = getHierarchy
|
||||
|
||||
81
src/types.d.ts
vendored
81
src/types.d.ts
vendored
@@ -166,6 +166,37 @@ export namespace Event {
|
||||
content: any
|
||||
}
|
||||
|
||||
export type InviteStrippedState = {
|
||||
type: string
|
||||
state_key: string
|
||||
sender: string
|
||||
content: Event.M_Room_Create | Event.M_Room_Name | Event.M_Room_Avatar | Event.M_Room_Topic | Event.M_Room_JoinRules | Event.M_Room_CanonicalAlias
|
||||
}
|
||||
|
||||
export type M_Room_Create = {
|
||||
additional_creators: string[]
|
||||
"m.federate"?: boolean
|
||||
room_version: string
|
||||
type?: string
|
||||
predecessor?: {
|
||||
room_id: string
|
||||
event_id?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type M_Room_JoinRules = {
|
||||
join_rule: "public" | "knock" | "invite" | "private" | "restricted" | "knock_restricted"
|
||||
allow?: {
|
||||
type: string
|
||||
room_id: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export type M_Room_CanonicalAlias = {
|
||||
alias?: string
|
||||
alt_aliases?: string[]
|
||||
}
|
||||
|
||||
export type M_Room_Message = {
|
||||
msgtype: "m.text" | "m.emote"
|
||||
body: string
|
||||
@@ -375,8 +406,58 @@ export namespace R {
|
||||
room_id: string
|
||||
servers: string[]
|
||||
}
|
||||
|
||||
export type SSS = {
|
||||
pos: string
|
||||
lists: {
|
||||
[list_key: string]: {
|
||||
count: number
|
||||
}
|
||||
}
|
||||
rooms: {
|
||||
[room_id: string]: {
|
||||
bump_stamp: number
|
||||
/** Omitted if user not in room (peeking) */
|
||||
membership?: Membership
|
||||
/** Names of lists that match this room */
|
||||
lists: string[]
|
||||
}
|
||||
// If user has been in the room - at least, that's what the spec says. Synapse returns some of these, such as `name` and `avatar`, for invites as well. Go nuts.
|
||||
& {
|
||||
name?: string
|
||||
avatar?: string
|
||||
heroes?: any[]
|
||||
/** According to account data */
|
||||
is_dm?: boolean
|
||||
/** If false, omitted fields are unchanged from their previous value. If true, omitted fields means the fields are not set. */
|
||||
initial?: boolean
|
||||
expanded_timeline?: boolean
|
||||
required_state?: Event.StateOuter<any>[]
|
||||
timeline_events?: Event.Outer<any>[]
|
||||
prev_batch?: string
|
||||
limited?: boolean
|
||||
num_live?: number
|
||||
joined_count?: number
|
||||
invited_count?: number
|
||||
notification_count?: number
|
||||
highlight_count?: number
|
||||
}
|
||||
// If user is invited or knocked
|
||||
& ({
|
||||
/** @deprecated */
|
||||
invite_state: Event.InviteStrippedState[]
|
||||
} | {
|
||||
stripped_state: Event.InviteStrippedState[]
|
||||
})
|
||||
}
|
||||
extensions: {
|
||||
[extension_key: string]: any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type Membership = "invite" | "knock" | "join" | "leave" | "ban"
|
||||
|
||||
export type Pagination<T> = {
|
||||
chunk: T[]
|
||||
next_batch?: string
|
||||
|
||||
Reference in New Issue
Block a user