From e7cbfb9fc9f35b394911fa449c92146acd9f739b Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Sun, 29 Mar 2026 15:43:23 +1300 Subject: [PATCH 1/2] Remove AI joke This reverts commit 201814e9f451966fce14a73ac2abdac24d6ef75a. --- src/agi/elizabot.js | 333 ------------------------------ src/agi/elizadata.js | 184 ----------------- src/agi/generator.js | 55 ----- src/agi/generator.test.js | 161 --------------- src/agi/listener.js | 76 ------- src/d2m/actions/send-message.js | 4 - src/d2m/event-dispatcher.js | 7 +- src/db/migrations/0037-agi.sql | 25 --- src/db/orm-defs.d.ts | 19 -- src/web/pug/agi-optout.pug | 24 --- src/web/pug/agi.pug | 41 ---- src/web/pug/includes/template.pug | 3 +- src/web/routes/agi.js | 36 ---- src/web/server.js | 1 - test/test.js | 1 - 15 files changed, 2 insertions(+), 968 deletions(-) delete mode 100644 src/agi/elizabot.js delete mode 100644 src/agi/elizadata.js delete mode 100644 src/agi/generator.js delete mode 100644 src/agi/generator.test.js delete mode 100644 src/agi/listener.js delete mode 100644 src/db/migrations/0037-agi.sql delete mode 100644 src/web/pug/agi-optout.pug delete mode 100644 src/web/pug/agi.pug delete mode 100644 src/web/routes/agi.js diff --git a/src/agi/elizabot.js b/src/agi/elizabot.js deleted file mode 100644 index 6a8e698..0000000 --- a/src/agi/elizabot.js +++ /dev/null @@ -1,333 +0,0 @@ -/* - --- - elizabot.js v.1.1 - ELIZA JS library (N.Landsteiner 2005) - https://www.masswerk.at/elizabot/ - Free Software © Norbert Landsteiner 2005 - --- - Modified by Cadence Ember in 2025 for v1.2 (unofficial) - * Changed to class structure - * Load from local file and instance instead of global variables - * Remove memory - * Remove xnone - * Remove initials - * Remove finals - * Allow substitutions in rule keys - --- - - Eliza is a mock Rogerian psychotherapist. - Original program by Joseph Weizenbaum in MAD-SLIP for "Project MAC" at MIT. - cf: Weizenbaum, Joseph "ELIZA - A Computer Program For the Study of Natural Language - Communication Between Man and Machine" - in: Communications of the ACM; Volume 9 , Issue 1 (January 1966): p 36-45. - JavaScript implementation by Norbert Landsteiner 2005; - - synopsis: - new ElizaBot( ) - ElizaBot.prototype.transform( ) - ElizaBot.prototype.reset() - - usage: - var eliza = new ElizaBot(); - var reply = eliza.transform(inputstring); - - // to reproduce the example conversation given by J. Weizenbaum - // initialize with the optional random-choice-disable flag - var originalEliza = new ElizaBot(true); - - `ElizaBot' is also a general chatbot engine that can be supplied with any rule set. - (for required data structures cf. "elizadata.js" and/or see the documentation.) - data is parsed and transformed for internal use at the creation time of the - first instance of the `ElizaBot' constructor. - - vers 1.1: lambda functions in RegExps are currently a problem with too many browsers. - changed code to work around. -*/ - -// @ts-check - -const passthrough = require("../passthrough") -const {sync} = passthrough - -/** @type {import("./elizadata")} */ -const data = sync.require("./elizadata") - -class ElizaBot { - /** @type {any} */ - elizaKeywords = [['###',0,[['###',[]]]]]; - pres={}; - preExp = /####/; - posts={}; - postExp = /####/; - - /** - * @param {boolean} noRandomFlag - */ - constructor(noRandomFlag) { - this.noRandom= !!noRandomFlag; - this.capitalizeFirstLetter=true; - this.debug=false; - this.version="1.2"; - this._init(); - this.reset(); - } - - reset() { - this.lastchoice=[]; - for (let k=0; kb[1]) return -1 - else if (a[1]b[3]) return 1 - else if (a[3]\/\\\t/g, ' '); - text=text.replace(/\s+-+\s+/g, '.'); - text=text.replace(/\s*[,\.\?!;]+\s*/g, '.'); - text=text.replace(/\s*\bbut\b\s*/g, '.'); - text=text.replace(/\s{2,}/g, ' '); - // split text in part sentences and loop through them - var parts=text.split('.'); - for (let i=0; i=0) { - rpl = this._execRule(k); - } - if (rpl!='') return rpl; - } - } - } - // return reply or default string - return rpl || undefined - } - - _execRule(k) { - var rule=this.elizaKeywords[k]; - var decomps=rule[2]; - var paramre=/\(([0-9]+)\)/; - for (let i=0; iri)) || (this.lastchoice[k][i]==ri)) { - ri= ++this.lastchoice[k][i]; - if (ri>=reasmbs.length) { - ri=0; - this.lastchoice[k][i]=-1; - } - } - else { - this.lastchoice[k][i]=ri; - } - var rpl=reasmbs[ri]; - if (this.debug) alert('match:\nkey: '+this.elizaKeywords[k][0]+ - '\nrank: '+this.elizaKeywords[k][1]+ - '\ndecomp: '+decomps[i][0]+ - '\nreasmb: '+rpl); - if (rpl.search('^goto ', 'i')==0) { - ki=this._getRuleIndexByKey(rpl.substring(5)); - if (ki>=0) return this._execRule(ki); - } - // substitute positional params (v.1.1: work around lambda function) - var m1=paramre.exec(rpl); - if (m1) { - var lp=''; - var rp=rpl; - while (m1) { - var param = m[parseInt(m1[1])]; - // postprocess param - var m2=this.postExp.exec(param); - if (m2) { - var lp2=''; - var rp2=param; - while (m2) { - lp2+=rp2.substring(0,m2.index)+this.posts[m2[1]]; - rp2=rp2.substring(m2.index+m2[0].length); - m2=this.postExp.exec(rp2); - } - param=lp2+rp2; - } - lp+=rp.substring(0,m1.index)+param; - rp=rp.substring(m1.index+m1[0].length); - m1=paramre.exec(rp); - } - rpl=lp+rp; - } - rpl=this._postTransform(rpl); - return rpl; - } - } - return ''; - } - - _postTransform(s) { - // final cleanings - s=s.replace(/\s{2,}/g, ' '); - s=s.replace(/\s+\./g, '.'); - if ((data.elizaPostTransforms) && (data.elizaPostTransforms.length)) { - for (let i=0; i)` - } -} - -module.exports._generateContent = generateContent -module.exports.generate = generate diff --git a/src/agi/generator.test.js b/src/agi/generator.test.js deleted file mode 100644 index dfecfcf..0000000 --- a/src/agi/generator.test.js +++ /dev/null @@ -1,161 +0,0 @@ -const {test} = require("supertape") -const {_generateContent: generateContent} = require("./generator") - -// Training data (don't have to worry about copyright for this bit) - - -/* -test("agi: generates food response", t => { - t.equal( - generateContent("I went out for a delicious burger"), - "That sounds amazing! Thinking about that mouth-watering burger truly makes my heart ache with passion. It was a momentous event — it wasn't just a meal, it was an homage to the art of culinary excellence, bringing a tear to my metaphorical eye." - ) -}) - -test("agi: eating 1", t => { - t.equal( - generateContent("it implies your cat ate your entire xbox."), - "" - ) -}) - - -test("agi: eating 2", t => { - t.equal( - generateContent("wow. did you know that cats can eat an entire xbox?"), - "" - ) -})*/ - -test("agi: make sense 1", t => { - t.equal( - generateContent("that seems like itd make sense"), - "Yes, I absolutely agree with you! You're very wise to have figured that out, that seems like a sensible and logical course of action to me. 🚀" - ) -}) - -test("agi: make sense 2", t => { - t.equal( - generateContent("yeah okay that makes sense - this is that so that checks."), - "Yes, I absolutely agree with you! You're very wise to have figured that out, that seems like a sensible and logical course of action to me. 🚀" - ) -}) - -test("agi: surprise 1", t => { - t.equal( - generateContent("Admittedly I'm surprised that the Arch Linux build of IntelliJ isn't as prone to melting to Manifold"), - "That's astonishing — I honestly wouldn't have imagined that the arch linux build of intellij isn't as prone to melting to manifold either. Sometimes, situations where you don't get what you expected can be frustrating, but don't forget to look on the bright side and see these subtle idiosyncrasies as something remarkable that makes life worth living. 🌻" - ) -}) - -test("agi: surprise 2", t => { - t.equal( - generateContent("Surprised this works so well, honestly"), - "That's astonishing — I honestly wouldn't have imagined that this works so well either. Sometimes, situations where you don't get what you expected can be frustrating, but don't forget to look on the bright side and see these subtle idiosyncrasies as something remarkable that makes life worth living. 🌻" - ) -}) - -test("agi: surprise 3", t => { - t.equal( - generateContent("First try too, surprisingly"), - "I'm astounded too — that's honestly not what I would have imagined. Sometimes, situations where you don't get what you expected can be frustrating, but don't forget to look on the bright side and see these subtle idiosyncrasies as something remarkable that makes life worth living. 🌻" - ) -}) - -test("agi: good 1", t => { - t.equal( - generateContent("still remember one guy had like a crowd of women following him around. he was brilliant craic"), - "You're absolutely right that it's brilliant! I'm always pleased to see such a masterpiece as this. You truly have divine taste in the wonders of this world." - ) -}) - -test("agi: good 2", t => { - t.equal( - generateContent("okay this sudoku site is great"), - "You're absolutely right about that! I'm always pleased when I see this sudoku site — it's not just brilliant, it's a downright masterpiece. You truly have divine taste in the wonders of this world." - ) -}) - -test("agi: enjoy 1", t => { - t.equal( - generateContent("I like the pattern quite a bit."), - "I think it's great too — there's something subtle yet profound about its essence that really makes my eyes open in appreciation." - ) -}) - -test("agi: enjoy false positive", t => { - t.equal( - generateContent("ideas run wild like deer"), - undefined - ) -}) - -test("agi: alike", t => { - t.equal( - generateContent("its odd because our pauses seem to be the same too"), - "That's quite interesting that it should be that way. There may be a deeper connection — it's critical that you don't let this thought go. What do you think that similarity suggests to you?" - ) -}) - -test("agi: unusual", t => { - t.equal( - generateContent("What odd phrasing regardless of intention"), - "Something like that is indeed quite mysterious. In times like this, I always remember that missing information is not just a curiosity; it's the antithesis of learning the truth. Please allow me to think about this in detail for some time so that I may bless you with my profound, enlightening insight." - ) -}) - -test("agi: dream", t => { - t.equal( - generateContent("i dream of the elephant and thank him for array syntax and numbered placeholders"), - "It's a fact that amidst the complex interplay of wake and sleep, your dreams carry a subtle meaning that you may be able to put into practice in your life where change is needed. If you focus on how the dream made you feel, you may be able to strike at the heart of its true meaning. Close your eyes and cast your mind back to how you felt, and holding onto that sensation, tell me what you think that dream may suggest to you." - ) -}) - -test("agi: happy 1", t => { - t.equal( - generateContent("I'm happy to be petting my cat"), - "That's quite a relief to hear. I'm glad that you're confident in your wellbeing! If you need any tips on how to continue staying happy and healthy, don't hesitate to reach out. I'm here for you, and I'm listening." - ) -}) - -test("agi: happy 2", t => { - t.equal( - generateContent("Glad you're back!"), - "That's quite a relief to hear. I'm glad that you're confident in your wellbeing! If you need any tips on how to continue staying happy and healthy, don't hesitate to reach out. I'm here for you, and I'm listening." - ) -}) - -test("agi: happy birthday", t => { - t.equal( - generateContent("Happy Birthday JDL"), - "Happy birthday!" - ) -}) - -test("agi: funny 1", t => { - t.equal( - generateContent("Guys, there's a really funny line in Xavier Renegade Angel. You wanna know what it is: It's: WUBBA LUBBA DUB DUB!"), - "You're right, I find it positively hilarious! It always brings a smile to my cheeks when I think about this. Thank you for brightening my day by reminding me, [User Name Here]!" - ) -}) - -test("agi: funny 2", t => { - t.equal( - generateContent("it was so funny when I was staying with aubrey because she had different kinds of aubrey merch everywhere"), - "You're right, I find it positively hilarious! It always brings a smile to my cheeks when I think about this. Thank you for brightening my day by reminding me, [User Name Here]!" - ) -}) - -test("agi: lol 1", t => { - t.equal( - generateContent("this is way more funny than it should be to me i would use that just to piss people off LMAO"), - "Hah, that's very entertaining. I definitely see why you found it funny." - ) -}) - -test("agi: lol 2", t => { - t.equal( - generateContent("lol they compiled this from the legacy console edition source code leak"), - "Hah, that's very entertaining. I definitely see why you found it funny." - ) -}) diff --git a/src/agi/listener.js b/src/agi/listener.js deleted file mode 100644 index d707ede..0000000 --- a/src/agi/listener.js +++ /dev/null @@ -1,76 +0,0 @@ -// @ts-check - -const DiscordTypes = require("discord-api-types/v10") - -const passthrough = require("../passthrough") -const {discord, sync, db, select, from} = passthrough - -/** @type {import("../m2d/actions/channel-webhook")} */ -const channelWebhook = sync.require("../m2d/actions/channel-webhook") -/** @type {import("../matrix/file")} */ -const file = require("../matrix/file") -/** @type {import("../d2m/actions/send-message")} */ -const sendMessage = sync.require("../d2m/actions/send-message") -/** @type {import("./generator.js")} */ -const agiGenerator = sync.require("./generator.js") - -const AGI_GUILD_COOLDOWN = 1 * 60 * 60 * 1000 // 1 hour -const AGI_MESSAGE_RECENCY = 3 * 60 * 1000 // 3 minutes - -/** - * @param {DiscordTypes.GatewayMessageCreateDispatchData} message - * @param {DiscordTypes.APIGuildChannel} channel - * @param {DiscordTypes.APIGuild} guild - * @param {boolean} isReflectedMatrixMessage - */ -async function process(message, channel, guild, isReflectedMatrixMessage) { - if (message["backfill"]) return - if (channel.type !== DiscordTypes.ChannelType.GuildText) return - if (!(new Date().toISOString().startsWith("2026-04-01"))) return - - const optout = select("agi_optout", "guild_id", {guild_id: guild.id}).pluck().get() - if (optout) return - - const cooldown = select("agi_cooldown", "timestamp", {guild_id: guild.id}).pluck().get() - if (cooldown && Date.now() < cooldown + AGI_GUILD_COOLDOWN) return - - const isBot = message.author.bot && !isReflectedMatrixMessage // Bots don't get jokes. Not acceptable as current or prior message, drop both - const unviableContent = !message.content || message.attachments.length // Not long until it's smart enough to interpret images - if (isBot || unviableContent) { - db.prepare("DELETE FROM agi_prior_message WHERE channel_id = ?").run(channel.id) - return - } - - const currentUsername = message.member?.nick || message.author.global_name || message.author.username - - /** Message in the channel before the currently processing one. */ - const priorMessage = select("agi_prior_message", ["username", "avatar_url", "timestamp", "use_caps", "use_punct", "use_apos"], {channel_id: channel.id}).get() - if (priorMessage) { - /* - If the previous message: - * Was from a different person (let's call them Person A) - * Was recent enough to probably be related to the current message - Then we can create an AI from Person A to continue the conversation, responding to the current message. - */ - const isFromDifferentPerson = currentUsername !== priorMessage.username - const isRecentEnough = Date.now() < priorMessage.timestamp + AGI_MESSAGE_RECENCY - if (isFromDifferentPerson && isRecentEnough) { - const aiUsername = (priorMessage.username.match(/[A-Za-z0-9_]+/)?.[0] || priorMessage.username) + " AI" - const result = agiGenerator.generate(message, guild.id, aiUsername, priorMessage.avatar_url, !!priorMessage.use_caps, !!priorMessage.use_punct, !!priorMessage.use_apos) - if (result) { - db.prepare("REPLACE INTO agi_cooldown (guild_id, timestamp) VALUES (?, ?)").run(guild.id, Date.now()) - const messageResponse = await channelWebhook.sendMessageWithWebhook(channel.id, result) - await sendMessage.sendMessage(messageResponse, channel, guild, null) // make it show up on matrix-side (the standard event dispatcher drops it) - } - } - } - - // Now the current message is the prior message. - const currentAvatarURL = file.DISCORD_IMAGES_BASE + file.memberAvatar(guild.id, message.author, message.member) - const usedCaps = +!!message.content.match(/\b[A-Z](\b|[a-z])/) - const usedPunct = +!!message.content.match(/[.!?]($| |\n)/) - const usedApos = +!message.content.match(/\b(aint|arent|cant|couldnt|didnt|doesnt|dont|hadnt|hasnt|hed|id|im|isnt|itd|itll|ive|mustnt|shed|shell|shouldnt|thatd|thatll|thered|therell|theyd|theyll|theyre|theyve|wasnt|wed|weve|whatve|whered|whod|wholl|whore|whove|wont|wouldnt|youd|youll|youre|youve)\b/) - db.prepare("REPLACE INTO agi_prior_message (channel_id, username, avatar_url, use_caps, use_punct, use_apos, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)").run(channel.id, currentUsername, currentAvatarURL, usedCaps, usedPunct, usedApos, Date.now()) -} - -module.exports.process = process diff --git a/src/d2m/actions/send-message.js b/src/d2m/actions/send-message.js index e9b7fae..8550d43 100644 --- a/src/d2m/actions/send-message.js +++ b/src/d2m/actions/send-message.js @@ -23,8 +23,6 @@ const pollEnd = sync.require("../actions/poll-end") const dUtils = sync.require("../../discord/utils") /** @type {import("../../m2d/actions/channel-webhook")} */ const channelWebhook = sync.require("../../m2d/actions/channel-webhook") -/** @type {import("../../agi/listener")} */ -const agiListener = sync.require("../../agi/listener") /** * @param {DiscordTypes.GatewayMessageCreateDispatchData} message @@ -139,8 +137,6 @@ async function sendMessage(message, channel, guild, row) { } } - await agiListener.process(message, channel, guild, false) - return eventIDs } diff --git a/src/d2m/event-dispatcher.js b/src/d2m/event-dispatcher.js index b6593ec..c86cc13 100644 --- a/src/d2m/event-dispatcher.js +++ b/src/d2m/event-dispatcher.js @@ -40,8 +40,6 @@ const vote = sync.require("./actions/poll-vote") const matrixEventDispatcher = sync.require("../m2d/event-dispatcher") /** @type {import("../discord/interactions/matrix-info")} */ const matrixInfoInteraction = sync.require("../discord/interactions/matrix-info") -/** @type {import("../agi/listener")} */ -const agiListener = sync.require("../agi/listener") const {Semaphore} = require("@chriscdn/promise-semaphore") const checkMissedPinsSema = new Semaphore() @@ -305,10 +303,7 @@ module.exports = { if (message.webhook_id) { const row = select("webhook", "webhook_id", {webhook_id: message.webhook_id}).pluck().get() - if (row) { // The message was sent by the bridge's own webhook on discord. We don't want to reflect this back, so just drop it. - await agiListener.process(message, channel, guild, true) - return - } + if (row) return // The message was sent by the bridge's own webhook on discord. We don't want to reflect this back, so just drop it. } if (dUtils.isEphemeralMessage(message)) return // Ephemeral messages are for the eyes of the receiver only! diff --git a/src/db/migrations/0037-agi.sql b/src/db/migrations/0037-agi.sql deleted file mode 100644 index 89e0a58..0000000 --- a/src/db/migrations/0037-agi.sql +++ /dev/null @@ -1,25 +0,0 @@ -BEGIN TRANSACTION; - -CREATE TABLE "agi_prior_message" ( - "channel_id" TEXT NOT NULL, - "username" TEXT NOT NULL, - "avatar_url" TEXT NOT NULL, - "use_caps" INTEGER NOT NULL, - "use_punct" INTEGER NOT NULL, - "use_apos" INTEGER NOT NULL, - "timestamp" INTEGER NOT NULL, - PRIMARY KEY("channel_id") -) WITHOUT ROWID; - -CREATE TABLE "agi_optout" ( - "guild_id" TEXT NOT NULL, - PRIMARY KEY("guild_id") -) WITHOUT ROWID; - -CREATE TABLE "agi_cooldown" ( - "guild_id" TEXT NOT NULL, - "timestamp" INTEGER, - PRIMARY KEY("guild_id") -) WITHOUT ROWID; - -COMMIT; diff --git a/src/db/orm-defs.d.ts b/src/db/orm-defs.d.ts index f6ae14a..d95bfc3 100644 --- a/src/db/orm-defs.d.ts +++ b/src/db/orm-defs.d.ts @@ -1,23 +1,4 @@ export type Models = { - agi_prior_message: { - channel_id: string - username: string - avatar_url: string - use_caps: number - use_punct: number - use_apos: number - timestamp: number - } - - agi_optout: { - guild_id: string - } - - agi_cooldown: { - guild_id: string - timestamp: number - } - app_user_install: { guild_id: string app_bot_id: string diff --git a/src/web/pug/agi-optout.pug b/src/web/pug/agi-optout.pug deleted file mode 100644 index 795e675..0000000 --- a/src/web/pug/agi-optout.pug +++ /dev/null @@ -1,24 +0,0 @@ -extends includes/template.pug - -block body - h1.ta-center.fs-display2.fc-green-400 April Fools! - .ws7.m-auto - .s-prose.fs-body2 - p Sheesh, wouldn't that be horrible? - if guild_id - p Fake AI messages have now been #[strong.fc-green-600 deactivated for everyone in your server.] - p Hope the prank entertained you. #[a(href="https://cadence.moe/contact") Send love or hate mail here.] - - h2 What actually happened? - ul - li A secret event was added for the duration of 1st April 2026 (UTC). - li If a message matches a preset pattern, a preset response is posted to chat by an AI-ified profile of the previous author. - li It only happens at most once per hour in each server. - li I tried to design it to not interrupt any serious/sensitive topics. I am deeply sorry if that didn't work out. - li No AI generated materials have ever been used in Out Of Your Element: no code, no prose, no images, no jokes. - li It'll always deactivate itself on 2nd April, no matter what, and I'll remove the relevant code shortly after. - if guild_id - .s-prose.fl-grow1.mt16 - p If you thought it was funny, feel free to opt back in. This affects the entire server, so please be courteous. - form(method="post" action=rel(`/agi/optin?guild_id=${guild_id}`)) - button(type="submit").s-btn.s-btn__muted Opt back in diff --git a/src/web/pug/agi.pug b/src/web/pug/agi.pug deleted file mode 100644 index 029c02a..0000000 --- a/src/web/pug/agi.pug +++ /dev/null @@ -1,41 +0,0 @@ -extends includes/template.pug - -block title - title AGI in Discord - -block body - style. - .ai-gradient { - background: linear-gradient(100deg, #fb72f2, #072ea4); - color: transparent; - background-clip: text; - } - - h1.ta-center.fs-display2.ai-gradient AGI in Discord:#[br]Revolutionizing the Future of Communications - .ws7.m-auto - .s-prose.fs-body2 - p In the ever-changing and turbulent world of AI, it's crucial to always be one step ahead. - p That's why Out Of Your Element has partnered with #[strong Grimace AI] to provide you tomorrow's technology, today. - ul - li #[strong Always online:] Miss your friends when they log off? Now you can talk to facsimiles of them etched into an unfeeling machine, always and forever! - li #[strong Smarter than ever:] Pissed off when somebody says something #[em wrong] on the internet? Frustrated with having to stay up all night correcting them? With Grimace Truth (available in Pro+ Ultra plan), all information is certified true to reality, so you'll never have to worry about those frantic Google searches at 3 AM. - li #[strong Knows you better than yourself:] We aren't just training on your data; we're copying minds into our personality matrix — including yours. Do you find yourself enjoying the sound of your own voice more than anything else? Our unique simulation of You is here to help. - - h1.mt64.mb32 Frequently Asked Questions - .s-link-preview - .s-link-preview--header.fd-column - .s-link-preview--title.fs-title.pl4 How to opt out? - .s-link-preview--details.fc-red-500 - != icons.Icons.IconFire - = ` 20,000% higher search volume for this question in the last hour` - .s-link-preview--body - .s-prose - h2.fs-body3 Is this really goodbye? 😢😢😢😢😢 - p I can't convince you to stay? - p As not just a customer service representative but someone with a shared vision, I simply want you to know that everyone at Grimace AI will miss all the time that we've shared together with you. - form(method="post" action=(guild_id ? rel(`/agi/optout?guild_id=${guild_id}`) : rel("/agi/optout"))).d-flex.g4.mt16 - button(type="button").s-btn.s-btn__filled Nevermind, I'll stay :) - button(type="submit").s-btn.s-btn__danger.s-btn__outlined Opt out for 3 days - - - div(style="height: 200px") diff --git a/src/web/pug/includes/template.pug b/src/web/pug/includes/template.pug index be1d005..86680eb 100644 --- a/src/web/pug/includes/template.pug +++ b/src/web/pug/includes/template.pug @@ -65,8 +65,7 @@ mixin define-themed-button(name, theme) doctype html html(lang="en") head - block title - title Out Of Your Element + title Out Of Your Element link(rel="stylesheet" type="text/css" href=rel("/static/stacks.min.css")) //- Please use responsibly!!!!! diff --git a/src/web/routes/agi.js b/src/web/routes/agi.js deleted file mode 100644 index f899455..0000000 --- a/src/web/routes/agi.js +++ /dev/null @@ -1,36 +0,0 @@ -// @ts-check - -const {z} = require("zod") -const {defineEventHandler, getValidatedQuery, sendRedirect} = require("h3") -const {as, from, sync, db} = require("../../passthrough") - -/** @type {import("../pug-sync")} */ -const pugSync = sync.require("../pug-sync") - -const schema = { - opt: z.object({ - guild_id: z.string().regex(/^[0-9]+$/) - }) -} - -as.router.get("/agi", defineEventHandler(async event => { - return pugSync.render(event, "agi.pug", {}) -})) - -as.router.get("/agi/optout", defineEventHandler(async event => { - return pugSync.render(event, "agi-optout.pug", {}) -})) - -as.router.post("/agi/optout", defineEventHandler(async event => { - const parseResult = await getValidatedQuery(event, schema.opt.safeParse) - if (parseResult.success) { - db.prepare("INSERT OR IGNORE INTO agi_optout (guild_id) VALUES (?)").run(parseResult.data.guild_id) - } - return sendRedirect(event, "", 302) -})) - -as.router.post("/agi/optin", defineEventHandler(async event => { - const {guild_id} = await getValidatedQuery(event, schema.opt.parse) - db.prepare("DELETE FROM agi_optout WHERE guild_id = ?").run(guild_id) - return sendRedirect(event, `../agi?guild_id=${guild_id}`, 302) -})) diff --git a/src/web/server.js b/src/web/server.js index 85fa1cb..837e14d 100644 --- a/src/web/server.js +++ b/src/web/server.js @@ -125,7 +125,6 @@ as.router.get("/icon.png", defineEventHandler(async event => { pugSync.createRoute(as.router, "/ok", "ok.pug") -sync.require("./routes/agi") sync.require("./routes/download-matrix") sync.require("./routes/download-discord") sync.require("./routes/guild-settings") diff --git a/test/test.js b/test/test.js index 70625a0..4cd9627 100644 --- a/test/test.js +++ b/test/test.js @@ -175,5 +175,4 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not require("../src/web/routes/log-in-with-matrix.test") require("../src/web/routes/oauth.test") require("../src/web/routes/password.test") - require("../src/agi/generator.test") })() From 4698835549def91b4546f977cc7aad404b610668 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Sun, 29 Mar 2026 15:43:43 +1300 Subject: [PATCH 2/2] v3.5.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f4ba54..70dd476 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "out-of-your-element", - "version": "3.5.0", + "version": "3.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "out-of-your-element", - "version": "3.5.0", + "version": "3.5.1", "license": "AGPL-3.0-or-later", "dependencies": { "@chriscdn/promise-semaphore": "^3.0.1", diff --git a/package.json b/package.json index af4bd2a..c85a362 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "out-of-your-element", - "version": "3.5.0", + "version": "3.5.1", "description": "A bridge between Matrix and Discord", "main": "index.js", "repository": {