forked from cadence/out-of-your-element
		
	Sync pins back from Matrix to Discord
This commit is contained in:
		
							parent
							
								
									4c62124cee
								
							
						
					
					
						commit
						06b6a63ee3
					
				
					 6 changed files with 87 additions and 0 deletions
				
			
		
							
								
								
									
										25
									
								
								src/m2d/actions/update-pins.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/m2d/actions/update-pins.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
// @ts-check
 | 
			
		||||
 | 
			
		||||
const {sync, from, discord} = require("../../passthrough")
 | 
			
		||||
 | 
			
		||||
/** @type {import("../converters/diff-pins")} */
 | 
			
		||||
const diffPins = sync.require("../converters/diff-pins")
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {string[]} pins
 | 
			
		||||
 * @param {string[]} prev
 | 
			
		||||
 */
 | 
			
		||||
async function updatePins(pins, prev) {
 | 
			
		||||
	const diff = diffPins.diffPins(pins, prev)
 | 
			
		||||
	for (const [event_id, added] of diff) {
 | 
			
		||||
		const row = from("event_message").join("message_channel", "message_id").where({event_id}).select("channel_id", "message_id").get()
 | 
			
		||||
		if (!row) continue
 | 
			
		||||
		if (added) {
 | 
			
		||||
			discord.snow.channel.addChannelPinnedMessage(row.channel_id, row.message_id, "Message pinned on Matrix")
 | 
			
		||||
		} else {
 | 
			
		||||
			discord.snow.channel.removeChannelPinnedMessage(row.channel_id, row.message_id, "Message unpinned on Matrix")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.updatePins = updatePins
 | 
			
		||||
							
								
								
									
										17
									
								
								src/m2d/converters/diff-pins.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/m2d/converters/diff-pins.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
// @ts-check
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {string[]} pins
 | 
			
		||||
 * @param {string[]} prev
 | 
			
		||||
 * @returns {[string, boolean][]}
 | 
			
		||||
 */
 | 
			
		||||
function diffPins(pins, prev) {
 | 
			
		||||
	/** @type {[string, boolean][]} */
 | 
			
		||||
	const result = []
 | 
			
		||||
	return result.concat(
 | 
			
		||||
		prev.filter(id => !pins.includes(id)).map(id => [id, false]), // removed
 | 
			
		||||
		pins.filter(id => !prev.includes(id)).map(id => [id, true]) // added
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.diffPins = diffPins
 | 
			
		||||
							
								
								
									
										11
									
								
								src/m2d/converters/diff-pins.test.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/m2d/converters/diff-pins.test.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
// @ts-check
 | 
			
		||||
 | 
			
		||||
const {test} = require("supertape")
 | 
			
		||||
const diffPins = require("./diff-pins")
 | 
			
		||||
 | 
			
		||||
test("diff pins: diff is as expected", t => {
 | 
			
		||||
	t.deepEqual(
 | 
			
		||||
		diffPins.diffPins(["same", "new"], ["same", "old"]),
 | 
			
		||||
		[["old", false], ["new", true]]
 | 
			
		||||
	)
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,8 @@ const sendEvent = sync.require("./actions/send-event")
 | 
			
		|||
const addReaction = sync.require("./actions/add-reaction")
 | 
			
		||||
/** @type {import("./actions/redact")} */
 | 
			
		||||
const redact = sync.require("./actions/redact")
 | 
			
		||||
/** @type {import("./actions/update-pins")}) */
 | 
			
		||||
const updatePins = sync.require("./actions/update-pins")
 | 
			
		||||
/** @type {import("../matrix/matrix-command-handler")} */
 | 
			
		||||
const matrixCommandHandler = sync.require("../matrix/matrix-command-handler")
 | 
			
		||||
/** @type {import("./converters/utils")} */
 | 
			
		||||
| 
						 | 
				
			
			@ -159,6 +161,33 @@ async event => {
 | 
			
		|||
	db.prepare("UPDATE channel_room SET nick = ? WHERE room_id = ?").run(name, event.room_id)
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
sync.addTemporaryListener(as, "type:m.room.pinned_events", guard("m.room.pinned_events",
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Ty.Event.StateOuter<Ty.Event.M_Room_PinnedEvents>} event
 | 
			
		||||
 */
 | 
			
		||||
async event => {
 | 
			
		||||
	if (event.state_key !== "") return
 | 
			
		||||
	if (utils.eventSenderIsFromDiscord(event.sender)) return
 | 
			
		||||
	const pins = event.content.pinned
 | 
			
		||||
	if (!Array.isArray(pins)) return
 | 
			
		||||
	let prev = event.unsigned?.prev_content?.pinned
 | 
			
		||||
	if (!Array.isArray(prev)) {
 | 
			
		||||
		if (pins.length === 1) {
 | 
			
		||||
			/*
 | 
			
		||||
				In edge cases, prev_content isn't guaranteed to be provided by the server.
 | 
			
		||||
				If prev_content is missing, we can't diff. Better safe than sorry: we'd like to ignore the change rather than wiping the whole channel's pins on Discord.
 | 
			
		||||
				However, that would mean if the first ever pin came from Matrix-side, it would be ignored, because there would be no prev_content (it's the first pinned event!)
 | 
			
		||||
				So to handle that edge case, we assume that if there's exactly 1 entry in `pinned`, this is the first ever pin and it should go through.
 | 
			
		||||
			*/
 | 
			
		||||
			prev = []
 | 
			
		||||
		} else {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	await updatePins.updatePins(pins, prev)
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
sync.addTemporaryListener(as, "type:m.room.member", guard("m.room.member",
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Ty.Event.StateOuter<Ty.Event.M_Room_Member>} event
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								src/types.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								src/types.d.ts
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -241,6 +241,10 @@ export namespace Event {
 | 
			
		|||
		name?: string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	export type M_Room_PinnedEvents = {
 | 
			
		||||
		pinned: string[]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	export type M_Power_Levels = {
 | 
			
		||||
		/** The level required to ban a user. Defaults to 50 if unspecified. */
 | 
			
		||||
		ban?: number,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,6 +139,7 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
 | 
			
		|||
	require("../src/d2m/converters/remove-reaction.test")
 | 
			
		||||
	require("../src/d2m/converters/thread-to-announcement.test")
 | 
			
		||||
	require("../src/d2m/converters/user-to-mxid.test")
 | 
			
		||||
	require("../src/m2d/converters/diff-pins.test")
 | 
			
		||||
	require("../src/m2d/converters/event-to-message.test")
 | 
			
		||||
	require("../src/m2d/converters/utils.test")
 | 
			
		||||
	require("../src/m2d/converters/emoji-sheet.test")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue