diff --git a/src/d2m/actions/poll-end.js b/src/d2m/actions/poll-end.js
index b0d29b9..936dedf 100644
--- a/src/d2m/actions/poll-end.js
+++ b/src/d2m/actions/poll-end.js
@@ -9,15 +9,22 @@ const {discord, sync, db, select, from} = passthrough
const {reg} = require("../../matrix/read-registration")
/** @type {import("./poll-vote")} */
const vote = sync.require("../actions/poll-vote")
-/** @type {import("../../discord/interactions/poll-responses")} */
-const pollResponses = sync.require("../../discord/interactions/poll-responses")
+/** @type {import("../../m2d/converters/poll-components")} */
+const pollComponents = sync.require("../../m2d/converters/poll-components")
+
+// This handles, in the following order:
+// * verifying Matrix-side votes are accurate for a poll originating on Discord, sending missed votes to Matrix if necessary
+// * sending a message to Discord if a vote in that poll has been cast on Matrix
+// This does *not* handle bridging of poll closures on Discord to Matrix; that takes place in converters/message-to-event.js.
/**
- * @file This handles, in the following order:
- * * verifying Matrix-side votes are accurate for a poll originating on Discord, sending missed votes to Matrix if necessary
- * * sending a message to Discord if a vote in that poll has been cast on Matrix
- * This does *not* handle bridging of poll closures on Discord to Matrix; that takes place in converters/message-to-event.js.
+ * @param {number} percent
*/
+function barChart(percent) {
+ const width = 12
+ const bars = Math.floor(percent*width)
+ return "█".repeat(bars) + "▒".repeat(width-bars)
+}
/**
* @param {string} channelID
@@ -107,14 +114,26 @@ async function endPoll(closeMessage) {
}))
}
- const {combinedVotes, messageString} = pollResponses.getCombinedResults(pollMessageID, true)
+ /** @type {{matrix_option: string, option_text: string, count: number}[]} */
+ const pollResults = db.prepare("SELECT matrix_option, option_text, seq, count(discord_or_matrix_user_id) as count FROM poll_option LEFT JOIN poll_vote USING (message_id, matrix_option) WHERE message_id = ? GROUP BY matrix_option ORDER BY seq").all(pollMessageID)
+ const combinedVotes = pollResults.reduce((a, c) => a + c.count, 0)
+ const totalVoters = db.prepare("SELECT count(DISTINCT discord_or_matrix_user_id) as count FROM poll_vote WHERE message_id = ?").pluck().get(pollMessageID)
- if (combinedVotes !== totalVotes) { // This means some votes were cast on Matrix. Now that we've corrected the vote totals, we can get the results again and post them to Discord.
+ if (combinedVotes !== totalVotes) { // This means some votes were cast on Matrix!
+ // Now that we've corrected the vote totals, we can get the results again and post them to Discord!
+ const topAnswers = pollResults.toSorted((a, b) => b.count - a.count)
+ let messageString = ""
+ for (const option of pollResults) {
+ const medal = pollComponents.getMedal(topAnswers, option.count)
+ const countString = `${String(option.count).padStart(String(topAnswers[0].count).length)}`
+ const votesString = option.count === 1 ? "vote " : "votes"
+ const label = medal === "🥇" ? `**${option.option_text}**` : option.option_text
+ messageString += `\`\u200b${countString} ${votesString}\u200b\` ${barChart(option.count/totalVoters)} ${label} ${medal}\n`
+ }
return {
username: "Total results including Matrix votes",
avatar_url: `${reg.ooye.bridge_origin}/discord/poll-star-avatar.png`,
- content: messageString,
- flags: DiscordTypes.MessageFlags.SuppressEmbeds
+ content: messageString
}
}
}
diff --git a/src/d2m/converters/edit-to-changes.js b/src/d2m/converters/edit-to-changes.js
index b73d6e0..82b9417 100644
--- a/src/d2m/converters/edit-to-changes.js
+++ b/src/d2m/converters/edit-to-changes.js
@@ -16,12 +16,8 @@ function eventCanBeEdited(ev) {
if (ev.old.event_type === "m.room.message" && ev.old.event_subtype !== "m.text" && ev.old.event_subtype !== "m.emote" && ev.old.event_subtype !== "m.notice") {
return false
}
- // Discord does not allow stickers to be edited.
- if (ev.old.event_type === "m.sticker") {
- return false
- }
- // Discord does not allow the data of polls to be edited, they may only be responded to.
- if (ev.old.event_type === "org.matrix.msc3381.poll.start" || ev.old.event_type === "org.matrix.msc3381.poll.end") {
+ // Discord does not allow stickers to be edited. Poll closures are sent as "edits", but not in a way we care about.
+ if (ev.old.event_type === "m.sticker" || ev.old.event_type === "org.matrix.msc3381.poll.start") {
return false
}
// Anything else is fair game.
diff --git a/src/d2m/converters/message-to-event.js b/src/d2m/converters/message-to-event.js
index 2f12958..9236c89 100644
--- a/src/d2m/converters/message-to-event.js
+++ b/src/d2m/converters/message-to-event.js
@@ -20,8 +20,6 @@ const mxUtils = sync.require("../../matrix/utils")
const dUtils = sync.require("../../discord/utils")
/** @type {import("./find-mentions")} */
const findMentions = sync.require("./find-mentions")
-/** @type {import("../../discord/interactions/poll-responses")} */
-const pollResponses = sync.require("../../discord/interactions/poll-responses")
const {reg} = require("../../matrix/read-registration")
/**
@@ -271,21 +269,7 @@ async function messageToEvent(message, guild, options = {}, di) {
}
if (message.type === DiscordTypes.MessageType.PollResult) {
- const pollMessageID = message.message_reference?.message_id
- if (!pollMessageID) return []
- const event_id = select("event_message", "event_id", {message_id: pollMessageID}).pluck().get()
- const roomID = select("channel_room", "room_id", {channel_id: message.channel_id}).pluck().get()
- const pollQuestionText = select("poll", "question_text", {message_id: pollMessageID}).pluck().get()
- if (!event_id || !roomID || !pollQuestionText) return [] // drop it if the corresponding poll start was not bridged
-
- const rep = new mxUtils.MatrixStringBuilder()
- rep.addLine(`The poll ${pollQuestionText} has closed.`, tag`The poll ${pollQuestionText} has closed.`)
-
- const {messageString} = pollResponses.getCombinedResults(pollMessageID, true) // poll results have already been double-checked before this point, so these totals will be accurate
- rep.addLine(markdown.toHTML(messageString, {discordOnly: true, escapeHTML: false}), markdown.toHTML(messageString, {}))
-
- const {body, formatted_body} = rep.get()
-
+ const event_id = select("event_message", "event_id", {message_id: message.message_reference?.message_id}).pluck().get()
return [{
$type: "org.matrix.msc3381.poll.end",
"m.relates_to": {
@@ -293,11 +277,7 @@ async function messageToEvent(message, guild, options = {}, di) {
event_id
},
"org.matrix.msc3381.poll.end": {},
- "org.matrix.msc1767.text": body,
- "org.matrix.msc1767.html": formatted_body,
- body: body,
- format: "org.matrix.custom.html",
- formatted_body: formatted_body,
+ body: "This poll has ended.",
msgtype: "m.text"
}]
}
diff --git a/src/discord/interactions/poll-responses.js b/src/discord/interactions/poll-responses.js
deleted file mode 100644
index 86277c2..0000000
--- a/src/discord/interactions/poll-responses.js
+++ /dev/null
@@ -1,94 +0,0 @@
-// @ts-check
-
-const DiscordTypes = require("discord-api-types/v10")
-const {discord, sync, db, select, from} = require("../../passthrough")
-const {id: botID} = require("../../../addbot")
-const {InteractionMethods} = require("snowtransfer")
-
-/** @type {import("../../matrix/api")} */
-const api = sync.require("../../matrix/api")
-/** @type {import("../../m2d/converters/poll-components")} */
-const pollComponents = sync.require("../../m2d/converters/poll-components")
-const {reg} = require("../../matrix/read-registration")
-
-/**
- * @param {number} percentc
- */
-function barChart(percent) {
- const width = 12
- const bars = Math.floor(percent*width)
- return "█".repeat(bars) + "▒".repeat(width-bars)
-}
-
-/**
- * @param {string} pollMessageID
- * @param {boolean} isClosed
- */
-function getCombinedResults(pollMessageID, isClosed) {
- /** @type {{matrix_option: string, option_text: string, count: number}[]} */
- const pollResults = db.prepare("SELECT matrix_option, option_text, seq, count(discord_or_matrix_user_id) as count FROM poll_option LEFT JOIN poll_vote USING (message_id, matrix_option) WHERE message_id = ? GROUP BY matrix_option ORDER BY seq").all(pollMessageID)
- const combinedVotes = pollResults.reduce((a, c) => a + c.count, 0)
- const totalVoters = db.prepare("SELECT count(DISTINCT discord_or_matrix_user_id) as count FROM poll_vote WHERE message_id = ?").pluck().get(pollMessageID)
- const topAnswers = pollResults.toSorted((a, b) => b.count - a.count)
-
- let messageString = ""
- for (const option of pollResults) {
- const medal = isClosed ? pollComponents.getMedal(topAnswers, option.count) : ""
- const countString = `${String(option.count).padStart(String(topAnswers[0].count).length)}`
- const votesString = option.count === 1 ? "vote " : "votes"
- const label = medal === "🥇" ? `**${option.option_text}**` : option.option_text
- messageString += `\`\u200b${countString} ${votesString}\u200b\` ${barChart(option.count/totalVoters)} ${label} ${medal}\n`
- }
-
- return {messageString, combinedVotes, totalVoters}
-}
-
-/**
- * @param {DiscordTypes.APIMessageApplicationCommandGuildInteraction} interaction
- * @param {{api: typeof api}} di
- * @returns {AsyncGenerator<{[k in keyof InteractionMethods]?: Parameters[2]}>}
- */
-async function* _interact({data}, {api}) {
- const row = select("poll", "is_closed", {message_id: data.target_id}).get()
-
- if (!row) {
- return yield {createInteractionResponse: {
- type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
- data: {
- content: "This poll hasn't been bridged to Matrix.",
- flags: DiscordTypes.MessageFlags.Ephemeral
- }
- }}
- }
-
- const {messageString} = getCombinedResults(data.target_id, !!row.is_closed)
-
- return yield {createInteractionResponse: {
- type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
- data: {
- embeds: [{
- author: {
- name: "Current results including Matrix votes",
- icon_url: `${reg.ooye.bridge_origin}/discord/poll-star-avatar.png`
- },
- description: messageString
- }],
- flags: DiscordTypes.MessageFlags.Ephemeral
- }
- }}
-}
-
-/* c8 ignore start */
-
-/** @param {DiscordTypes.APIMessageApplicationCommandGuildInteraction} interaction */
-async function interact(interaction) {
- for await (const response of _interact(interaction, {api})) {
- if (response.createInteractionResponse) {
- await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, response.createInteractionResponse)
- }
- }
-}
-
-module.exports.interact = interact
-module.exports._interact = _interact
-module.exports.getCombinedResults = getCombinedResults
\ No newline at end of file
diff --git a/src/discord/register-interactions.js b/src/discord/register-interactions.js
index a909393..b37f28e 100644
--- a/src/discord/register-interactions.js
+++ b/src/discord/register-interactions.js
@@ -10,7 +10,6 @@ const permissions = sync.require("./interactions/permissions.js")
const reactions = sync.require("./interactions/reactions.js")
const privacy = sync.require("./interactions/privacy.js")
const poll = sync.require("./interactions/poll.js")
-const pollResponses = sync.require("./interactions/poll-responses.js")
const ping = sync.require("./interactions/ping.js")
// User must have EVERY permission in default_member_permissions to be able to use the command
@@ -25,7 +24,7 @@ discord.snow.interaction.bulkOverwriteApplicationCommands(id, [{
type: DiscordTypes.ApplicationCommandType.Message,
default_member_permissions: String(DiscordTypes.PermissionFlagsBits.KickMembers | DiscordTypes.PermissionFlagsBits.ManageRoles)
}, {
- name: "Responses",
+ name: "Reactions",
contexts: [DiscordTypes.InteractionContextType.Guild],
type: DiscordTypes.ApplicationCommandType.Message
}, {
@@ -108,14 +107,8 @@ async function dispatchInteraction(interaction) {
await permissions.interact(interaction)
} else if (interactionId === "permissions_edit") {
await permissions.interactEdit(interaction)
- } else if (interactionId === "Responses") {
- /** @type {DiscordTypes.APIMessageApplicationCommandGuildInteraction} */ // @ts-ignore
- const messageInteraction = interaction
- if (messageInteraction.data.resolved.messages[messageInteraction.data.target_id]?.poll) {
- await pollResponses.interact(messageInteraction)
- } else {
- await reactions.interact(messageInteraction)
- }
+ } else if (interactionId === "Reactions") {
+ await reactions.interact(interaction)
} else if (interactionId === "ping") {
await ping.interact(interaction)
} else if (interactionId === "privacy") {