Spaces:
Paused
Paused
| ; | |
| var __defProp = Object.defineProperty; | |
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | |
| var __getOwnPropNames = Object.getOwnPropertyNames; | |
| var __hasOwnProp = Object.prototype.hasOwnProperty; | |
| var __export = (target, all) => { | |
| for (var name in all) | |
| __defProp(target, name, { get: all[name], enumerable: true }); | |
| }; | |
| var __copyProps = (to, from, except, desc) => { | |
| if (from && typeof from === "object" || typeof from === "function") { | |
| for (let key of __getOwnPropNames(from)) | |
| if (!__hasOwnProp.call(to, key) && key !== except) | |
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | |
| } | |
| return to; | |
| }; | |
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | |
| var permalocks_exports = {}; | |
| __export(permalocks_exports, { | |
| Nominations: () => Nominations, | |
| Smogon: () => Smogon, | |
| commands: () => commands, | |
| getIPData: () => getIPData, | |
| pages: () => pages | |
| }); | |
| module.exports = __toCommonJS(permalocks_exports); | |
| var import_lib = require("../../lib"); | |
| function getIPData(ip) { | |
| try { | |
| return (0, import_lib.Net)("https://miapi.dev/api/ip/" + ip).get().then(JSON.parse); | |
| } catch { | |
| return null; | |
| } | |
| } | |
| const Smogon = new class { | |
| async post(threadNum, postText) { | |
| if (!Config.smogon) | |
| return null; | |
| try { | |
| const raw = await (0, import_lib.Net)(`https://www.smogon.com/forums/api/posts`).get({ | |
| method: "POST", | |
| body: new URLSearchParams({ | |
| thread_id: threadNum, | |
| message: postText | |
| }).toString(), | |
| headers: { | |
| "XF-Api-Key": Config.smogon, | |
| "Content-Type": "application/x-www-form-urlencoded" | |
| } | |
| }); | |
| const data = JSON.parse(raw); | |
| if (data.errors?.length) { | |
| const errData = data.errors.pop(); | |
| throw new Error(errData.message); | |
| } | |
| return data; | |
| } catch (e) { | |
| if (e.message.includes("Not Found")) { | |
| throw new Error("WHO DELETED THE PERMA THREAD"); | |
| } | |
| return { error: e.message }; | |
| } | |
| } | |
| }(); | |
| const Nominations = new class { | |
| constructor() { | |
| this.noms = []; | |
| this.icons = {}; | |
| this.load(); | |
| } | |
| load() { | |
| try { | |
| let data = JSON.parse((0, import_lib.FS)("config/chat-plugins/permas.json").readSync()); | |
| if (Array.isArray(data)) { | |
| data = { noms: data, icons: {} }; | |
| (0, import_lib.FS)("config/chat-plugins/permas.json").writeSync(JSON.stringify(data)); | |
| } | |
| this.noms = data.noms; | |
| this.icons = data.icons; | |
| } catch { | |
| } | |
| } | |
| fetchModlog(id) { | |
| return Rooms.Modlog.search("global", { | |
| user: [{ search: id, isExact: true }], | |
| note: [], | |
| ip: [], | |
| action: [], | |
| actionTaker: [] | |
| }, void 0, true); | |
| } | |
| save() { | |
| (0, import_lib.FS)("config/chat-plugins/permas.json").writeUpdate(() => JSON.stringify({ noms: this.noms, icons: this.icons })); | |
| } | |
| notifyStaff() { | |
| const usRoom = Rooms.get("upperstaff"); | |
| if (!usRoom) | |
| return; | |
| usRoom.send(`|uhtml|permanoms|${this.getDisplayButton()}`); | |
| Chat.refreshPageFor("permalocks", usRoom); | |
| } | |
| async add(target, connection) { | |
| const user = connection.user; | |
| const [primary, rawAlts, rawIps, type, details] = import_lib.Utils.splitFirst(target, "|", 4).map((f) => f.trim()); | |
| const primaryID = toID(primary); | |
| const alts = rawAlts.split(",").map(toID).filter(Boolean); | |
| const ips = rawIps.split(",").map((f) => f.trim()).filter(Boolean); | |
| for (const ip of ips) { | |
| if (!IPTools.ipRegex.test(ip)) | |
| this.error(`Invalid IP: ${ip}`, connection); | |
| } | |
| const standings = this.getStandings(); | |
| if (!standings[type]) { | |
| this.error(`Invalid standing: ${type}.`, connection); | |
| } | |
| if (!details) { | |
| this.error("Details must be provided. Explain why this user should be permalocked.", connection); | |
| } | |
| if (!primaryID) { | |
| this.error("A primary username must be provided. Use one of their alts if necessary.", connection); | |
| } | |
| for (const nom of this.noms) { | |
| if (nom.primaryID === primaryID) { | |
| this.error(`'${primaryID}' was already nominated for permalock by ${nom.by}.`, connection); | |
| } | |
| } | |
| const ipTable = new Set(ips); | |
| const altTable = /* @__PURE__ */ new Set([...alts]); | |
| for (const alt of [primaryID, ...alts]) { | |
| const modlog = await this.fetchModlog(alt); | |
| if (!modlog?.results.length) | |
| continue; | |
| for (const entry of modlog.results) { | |
| if (entry.ip) | |
| ipTable.add(entry.ip); | |
| if (entry.autoconfirmedID) | |
| altTable.add(entry.autoconfirmedID); | |
| if (entry.alts) { | |
| for (const id of entry.alts) | |
| altTable.add(id); | |
| } | |
| } | |
| } | |
| altTable.delete(primaryID); | |
| this.noms.push({ | |
| by: user.id, | |
| alts: [...altTable], | |
| ips: import_lib.Utils.sortBy([...ipTable], (z) => -(IPTools.ipToNumber(z) || Infinity)), | |
| info: details, | |
| primaryID, | |
| standing: type, | |
| date: Date.now() | |
| }); | |
| import_lib.Utils.sortBy(this.noms, (nom) => -nom.date); | |
| this.save(); | |
| this.notifyStaff(); | |
| Rooms.get("staff")?.addByUser(user, `${user.name} submitted a perma nomination for ${primaryID}`); | |
| } | |
| find(id) { | |
| return this.noms.find((f) => f.primaryID === id); | |
| } | |
| error(message, conn) { | |
| conn.popup(message); | |
| throw new Chat.Interruption(); | |
| } | |
| close(target, context) { | |
| const entry = this.find(target); | |
| if (!entry) { | |
| this.error(`There is no nomination pending for '${toID(target)}'.`, context.connection); | |
| } | |
| this.noms.splice(this.noms.findIndex((f) => f.primaryID === entry.primaryID), 1); | |
| this.save(); | |
| this.notifyStaff(); | |
| return context.closePage(`permalocks-view-${entry.primaryID}`); | |
| } | |
| display(nom, canEdit) { | |
| let buf = `<div class="infobox">`; | |
| let title = nom.primaryID; | |
| if (canEdit) { | |
| title = `<a href="/view-permalocks-view-${nom.primaryID}" target="_replace">${nom.primaryID}</a>`; | |
| } | |
| buf += `<strong>${title}</strong> (submitted by ${nom.by})<br />`; | |
| buf += `Submitted ${Chat.toTimestamp(new Date(nom.date), { human: true })}<br />`; | |
| buf += `${Chat.count(nom.alts, "alts")}, ${Chat.count(nom.ips, "IPs")}`; | |
| buf += `</div>`; | |
| return buf; | |
| } | |
| displayModlog(results) { | |
| if (!results) | |
| return ""; | |
| let curDate = ""; | |
| return results.map((result) => { | |
| const date = new Date(result.time || Date.now()); | |
| const entryRoom = result.visualRoomID || result.roomID || "global"; | |
| let [dateString, timestamp] = Chat.toTimestamp(date, { human: true }).split(" "); | |
| let line = `<small>[${timestamp}] (${entryRoom})</small> ${result.action}`; | |
| if (result.userid) { | |
| line += `: [${result.userid}]`; | |
| if (result.autoconfirmedID) | |
| line += ` ac: [${result.autoconfirmedID}]`; | |
| if (result.alts.length) | |
| line += ` alts: [${result.alts.join("], [")}]`; | |
| if (result.ip) | |
| line += ` [<a href="https://whatismyipaddress.com/ip/${result.ip}" target="_blank">${result.ip}</a>]`; | |
| } | |
| if (result.loggedBy) | |
| line += `: by ${result.loggedBy}`; | |
| if (result.note) | |
| line += import_lib.Utils.html`: ${result.note}`; | |
| if (dateString !== curDate) { | |
| curDate = dateString; | |
| dateString = `</p><p>[${dateString}]<br />`; | |
| } else { | |
| dateString = ``; | |
| } | |
| const thisRoomID = entryRoom?.split(" ")[0]; | |
| if (thisRoomID.startsWith("battle-")) { | |
| timestamp = `<a href="/${thisRoomID}">${timestamp}</a>`; | |
| } else { | |
| const [day, time] = Chat.toTimestamp(date).split(" "); | |
| timestamp = `<a href="/view-chatlog-${thisRoomID}--${day}--time-${toID(time)}">${timestamp}</a>`; | |
| } | |
| return `${dateString}${line}`; | |
| }).join(`<br />`); | |
| } | |
| async displayActionPage(nom) { | |
| let buf = `<div class="pad">`; | |
| const standings = this.getStandings(); | |
| buf += `<button class="button" name="send" value="/perma viewnom ${nom.primaryID}" style="float:right">`; | |
| buf += `<i class="fa fa-refresh"></i> Refresh</button>`; | |
| buf += `<h3>Nomination: ${nom.primaryID}</h3><hr />`; | |
| buf += `<strong>By:</strong> ${nom.by} (on ${Chat.toTimestamp(new Date(nom.date))})<br />`; | |
| buf += `<strong>Recommended punishment:</strong> ${standings[nom.standing]}<br />`; | |
| buf += `<details class="readmore"><summary><strong>Modlog</strong></summary>`; | |
| buf += `<div class="infobox limited">`; | |
| const modlog = await this.fetchModlog(nom.primaryID); | |
| if (!modlog) { | |
| buf += `None found.`; | |
| } else { | |
| buf += this.displayModlog(modlog.results); | |
| } | |
| buf += `</div></details>`; | |
| if (nom.alts.length) { | |
| buf += `<details class="readmore"><summary><strong>Listed alts</strong></summary>`; | |
| for (const [i, alt] of nom.alts.entries()) { | |
| buf += `- ${alt}: `; | |
| buf += `<form data-submitsend="/perma standing ${alt},{standing},{reason}">`; | |
| buf += this.standingDropdown("standing"); | |
| buf += ` <button class="button notifying" type="submit">Change standing</button>`; | |
| buf += ` <input name="reason" placeholder="Reason" />`; | |
| buf += `</form>`; | |
| if (nom.alts[i + 1]) | |
| buf += `<br />`; | |
| } | |
| buf += `</details>`; | |
| } | |
| if (nom.ips.length) { | |
| buf += `<details class="readmore"><summary><strong>Listed IPs</strong></summary>`; | |
| for (const [i, ip] of nom.ips.entries()) { | |
| const ipData = await getIPData(ip); | |
| buf += `- <a href="https://whatismyipaddress.com/ip/${ip}">${ip}</a>`; | |
| if (ipData) { | |
| buf += `(ISP: ${ipData.isp}, loc: ${ipData.city}, ${ipData.regionName} in ${ipData.country})`; | |
| } | |
| buf += `: `; | |
| buf += `<form data-submitsend="/perma ipstanding ${ip},{standing},{reason}">`; | |
| buf += this.standingDropdown("standing"); | |
| buf += ` <button class="button notifying" type="submit">Change standing for all users on IP</button>`; | |
| buf += ` <input name="reason" placeholder="Reason" />`; | |
| buf += `</form>`; | |
| if (nom.ips[i + 1]) | |
| buf += `<br />`; | |
| } | |
| buf += `</details>`; | |
| } | |
| const [matches] = await LoginServer.request("ipmatches", { | |
| id: nom.primaryID | |
| }); | |
| if (matches?.results?.length) { | |
| buf += `<details class="readmore"><summary><strong>Registration IP matches</strong></summary>`; | |
| for (const [i, { userid, banstate }] of matches.results.entries()) { | |
| buf += `- ${userid}: `; | |
| buf += `<form data-submitsend="/perma standing ${userid},{standing}">`; | |
| buf += this.standingDropdown("standing", `${banstate}`); | |
| buf += ` <button class="button notifying" type="submit">Change standing</button></form>`; | |
| if (matches.results[i + 1]) | |
| buf += `<br />`; | |
| } | |
| buf += `</details>`; | |
| } | |
| buf += `<p><strong>Staff notes:</strong></p>`; | |
| buf += `<p><div class="infobox">${Chat.formatText(nom.info).replace(/\n/ig, "<br />")}</div></p>`; | |
| buf += `<details class="readmore"><summary><strong>Act on primary:</strong></summary>`; | |
| buf += `<form data-submitsend="/perma actmain ${nom.primaryID},{standing},{note}">`; | |
| buf += `Standing: ${this.standingDropdown("standing")}`; | |
| buf += `<br />Notes:<br />`; | |
| buf += `<textarea name="note" style="width: 100%" cols="50" rows="10"></textarea><br />`; | |
| buf += `<button class="button notifying" type="submit">Change standing and make post</button>`; | |
| buf += `</form></details><br />`; | |
| buf += `<button class="button notifying" name="send" value="/perma resolve ${nom.primaryID}">Mark resolved</button>`; | |
| return buf; | |
| } | |
| standingDropdown(elemName, curStanding = null) { | |
| let buf = `<select name="${elemName}">`; | |
| const standings = this.getStandings(); | |
| for (const k in standings) { | |
| buf += `<option ${curStanding === k ? "disabled" : ""} value="${k}">${standings[k]}</option>`; | |
| } | |
| buf += `</select>`; | |
| return buf; | |
| } | |
| getStandings() { | |
| if (Config.standings) | |
| return Config.standings; | |
| Config.standings = { | |
| "-20": "Confirmed", | |
| "-10": "Autoconfirmed", | |
| "0": "New", | |
| "20": "Permalock", | |
| "30": "Permaban", | |
| "100": "Disabled" | |
| }; | |
| return Config.standings; | |
| } | |
| displayAll(canEdit) { | |
| let buf = `<div class="pad">`; | |
| buf += `<button class="button" name="send" value="/perma noms" style="float:right"><i class="fa fa-refresh"></i> Refresh</button>`; | |
| buf += `<h3>Pending perma nominations</h3><hr />`; | |
| if (!this.noms.length) { | |
| buf += `None found.`; | |
| return buf; | |
| } | |
| for (const nom of this.noms) { | |
| buf += this.display(nom, canEdit); | |
| buf += `<br />`; | |
| } | |
| return buf; | |
| } | |
| displayNomPage() { | |
| let buf = `<div class="pad"><h3>Make a nomination for a permanent punishment.</h3><hr />`; | |
| buf += `<form data-submitsend="/perma submit {primary}|{alts}|{ips}|{type}|{details}">`; | |
| buf += `<div class="infobox">`; | |
| buf += `<strong>Primary userid:</strong> <input name="primary" /><br />`; | |
| buf += `<strong>Alts:</strong><br /><textarea name="alts"></textarea><br /><small>(Separated by commas)</small><br />`; | |
| buf += `<strong>Static IPs:</strong><br /><textarea name="ips"></textarea><br /><small>(Separated by commas)</small></div><br />`; | |
| buf += `<strong>Punishment:</strong> `; | |
| buf += `<select name="type"><option value="20">Permalock</option><option value="30">Permaban</option></select>`; | |
| buf += `<div class="infobox">`; | |
| buf += `<strong>Please explain why this user deserves a permanent punishment</strong><br />`; | |
| buf += `<small>Note: Modlogs are automatically included in review and do not need to be added here.</small><br />`; | |
| buf += `<textarea style="width: 100%" name="details" cols="50" rows="10"></textarea></div>`; | |
| buf += `<button class="button notifying" type="submit">Submit nomination</button>`; | |
| return buf; | |
| } | |
| getDisplayButton() { | |
| const unclaimed = this.noms.filter((f) => !f.claimed); | |
| let buf = `<div class="infobox">`; | |
| if (!this.noms.length) { | |
| buf += `No permalock nominations active.`; | |
| } else { | |
| let className = "button"; | |
| if (unclaimed.length) | |
| className += " notifying"; | |
| buf += `<button class="${className}" name="send" value="/j view-permalocks-list">`; | |
| buf += `${Chat.count(this.noms.length, "nominations")}`; | |
| if (unclaimed.length !== this.noms.length) { | |
| buf += ` (${unclaimed.length} unclaimed)`; | |
| } | |
| buf += `</button>`; | |
| } | |
| buf += `</div>`; | |
| return buf; | |
| } | |
| }(); | |
| const commands = { | |
| perma: { | |
| ""(target, room, user) { | |
| this.checkCan("lock"); | |
| if (!user.can("rangeban")) { | |
| return this.parse(`/j view-permalocks-submit`); | |
| } else { | |
| return this.parse(`/j view-permalocks-list`); | |
| } | |
| }, | |
| viewnom(target) { | |
| this.checkCan("rangeban"); | |
| return this.parse(`/j view-permalocks-view-${toID(target)}`); | |
| }, | |
| submit(target, room, user) { | |
| this.checkCan("lock"); | |
| return Nominations.add(target, this.connection); | |
| }, | |
| list() { | |
| this.checkCan("lock"); | |
| return this.parse(`/j view-permalocks-list`); | |
| }, | |
| nom() { | |
| this.checkCan("lock"); | |
| return this.parse(`/j view-permalocks-submit`); | |
| }, | |
| async actmain(target, room, user) { | |
| this.checkCan("rangeban"); | |
| const [primaryName, standingName, postReason] = import_lib.Utils.splitFirst(target, ",", 2).map((f) => f.trim()); | |
| const primary = toID(primaryName); | |
| if (!primary) | |
| return this.popupReply(`Invalid primary username.`); | |
| const nom = Nominations.find(primary); | |
| if (!nom) | |
| return this.popupReply(`No permalock nomination found for ${primary}.`); | |
| const standing = parseInt(standingName); | |
| const standings = Nominations.getStandings(); | |
| if (!standings[standing]) | |
| return this.popupReply(`Invalid standing.`); | |
| if (!toID(postReason)) | |
| return this.popupReply(`A reason must be given.`); | |
| const threadNum = Config.permathread; | |
| if (!threadNum) { | |
| throw new Chat.ErrorMessage("The link to the perma has not been set - the post could not be made."); | |
| } | |
| let postBuf = `[b][url="https://${Config.routes.root}/users/${primary}"]${primary}[/url][/b]`; | |
| const icon = Nominations.icons[user.id] ? `:${Nominations.icons[user.id]}: - ` : ``; | |
| postBuf += ` was added to ${standings[standing]} by ${user.name} (${icon}${postReason}). | |
| `; | |
| postBuf += `Nominated by ${nom.by}. | |
| [spoiler=Nomination notes]${nom.info}[/spoiler] | |
| `; | |
| postBuf += `${nom.alts.length ? `[spoiler=Alts]${nom.alts.join(", ")}[/spoiler]` : ""} | |
| `; | |
| if (nom.ips.length) { | |
| postBuf += `[spoiler=IPs]`; | |
| for (const ip of nom.ips) { | |
| const ipData = await getIPData(ip); | |
| postBuf += `- [url=https://whatismyipaddress.com/ip/${ip}]${ip}[/url]`; | |
| if (ipData) { | |
| postBuf += ` (ISP: ${ipData.isp}, loc: ${ipData.city}, ${ipData.regionName} in ${ipData.country})`; | |
| } | |
| postBuf += "\n"; | |
| } | |
| postBuf += `[/spoiler]`; | |
| } | |
| const modlog = await Nominations.fetchModlog(nom.primaryID); | |
| if (modlog?.results.length) { | |
| let rawHTML = Nominations.displayModlog(modlog.results); | |
| rawHTML = rawHTML.replace(/<br \/>/g, "\n"); | |
| rawHTML = import_lib.Utils.stripHTML(rawHTML); | |
| rawHTML = rawHTML.replace(///g, "/"); | |
| postBuf += ` | |
| [spoiler=Modlog]${rawHTML}[/spoiler]`; | |
| } | |
| const res = await Smogon.post( | |
| threadNum, | |
| postBuf | |
| ); | |
| if (!res || res.error) { | |
| return this.popupReply(`Error making post: ${res?.error}`); | |
| } | |
| const url = `https://smogon.com/forums/threads/${threadNum}/post-${res.post.post_id}`; | |
| const result = await LoginServer.request("setstanding", { | |
| user: primary, | |
| standing, | |
| reason: url, | |
| actor: user.id | |
| }); | |
| if (result[1]) { | |
| return this.popupReply(`Error changing standing: ${result[1].message}`); | |
| } | |
| nom.post = url; | |
| this.popupReply(`|html|Standing successfully changed. Smogon post can be found <a href="${url}">at this link</a>.`); | |
| }, | |
| async standing(target) { | |
| this.checkCan("rangeban"); | |
| const [name, rawStanding, reason] = import_lib.Utils.splitFirst(target, ",", 2).map((f) => f.trim()); | |
| const id = toID(name); | |
| if (!id || id.length > 18) { | |
| return this.popupReply("Invalid username: " + name); | |
| } | |
| const standingNum = parseInt(rawStanding); | |
| if (!standingNum) { | |
| return this.popupReply(`Invalid standing: ` + rawStanding); | |
| } | |
| if (!reason.length) { | |
| return this.popupReply(`A reason must be given.`); | |
| } | |
| const res = await LoginServer.request("setstanding", { | |
| user: id, | |
| standing: standingNum, | |
| reason, | |
| actor: this.user.id | |
| }); | |
| if (res[1]) { | |
| return this.popupReply(`Error in standing change: ` + res[1].message); | |
| } | |
| this.popupReply(`Standing successfully changed to ${standingNum} for ${id}.`); | |
| }, | |
| async ipstanding(target) { | |
| this.checkCan("rangeban"); | |
| const [ip, standingName, reason] = import_lib.Utils.splitFirst(target, ",", 2).map((f) => f.trim()); | |
| if (!IPTools.ipToNumber(ip)) { | |
| return this.popupReply(`Invalid IP: ${ip}`); | |
| } | |
| const standingNum = parseInt(standingName); | |
| if (!Config.standings[`${standingNum}`]) { | |
| return this.popupReply(`Invalid standing: ${standingName}.`); | |
| } | |
| if (!reason.length) { | |
| return this.popupReply("Specify a reason."); | |
| } | |
| const res = await LoginServer.request("ipstanding", { | |
| reason, | |
| standing: standingNum, | |
| ip, | |
| actor: this.user.id | |
| }); | |
| if (res[1]) { | |
| return this.popupReply(`Error changing standing: ${res[1].message}`); | |
| } | |
| this.popupReply(`All standings on the IP ${ip} changed successfully to ${standingNum}.`); | |
| this.globalModlog(`IPSTANDING`, null, `${standingNum}${reason ? ` (${reason})` : ""}`, ip); | |
| }, | |
| resolve(target) { | |
| this.checkCan("rangeban"); | |
| Nominations.close(target, this); | |
| }, | |
| seticon(target, room, user) { | |
| this.checkCan("rangeban"); | |
| let [monName, targetId] = target.split(","); | |
| if (!targetId) | |
| targetId = user.id; | |
| const mon = Dex.species.get(monName); | |
| if (!mon.exists) { | |
| return this.errorReply(`Species ${monName} does not exist.`); | |
| } | |
| Nominations.icons[targetId] = mon.name.toLowerCase(); | |
| Nominations.save(); | |
| this.sendReply( | |
| `|html|Updated ${targetId === user.id ? "your" : `${targetId}'s`} permalock post icon to <psicon pokemon='${mon.name.toLowerCase()}' />` | |
| ); | |
| }, | |
| deleteicon(target, room, user) { | |
| this.checkCan("rangeban"); | |
| const targetID = toID(target); | |
| if (!Nominations.icons[targetID]) { | |
| return this.errorReply(`${targetID} does not have an icon set.`); | |
| } | |
| delete Nominations.icons[targetID]; | |
| Nominations.save(); | |
| this.sendReply(`Removed ${targetID}'s permalock post icon.`); | |
| }, | |
| help: [ | |
| "/perma nom OR /perma - Open the page to make a nomination for a permanent punishment. Requires: % @ ~", | |
| "/perma list - View open nominations. Requires: % @ ~", | |
| "/perma viewnom [userid] - View a nomination for the given [userid]. Requires: ~" | |
| ] | |
| } | |
| }; | |
| const pages = { | |
| permalocks: { | |
| list(query, user, conn) { | |
| this.checkCan("lock"); | |
| this.title = "[Permalock Nominations]"; | |
| return Nominations.displayAll(user.can("rangeban")); | |
| }, | |
| view(query, user) { | |
| this.checkCan("rangeban"); | |
| const id = toID(query.shift()); | |
| if (!id) | |
| return this.errorReply(`Invalid userid.`); | |
| const nom = Nominations.find(id); | |
| if (!nom) | |
| return this.errorReply(`No nomination found for '${id}'.`); | |
| this.title = `[Perma Nom] ${nom.primaryID}`; | |
| return Nominations.displayActionPage(nom); | |
| }, | |
| submit() { | |
| this.checkCan("lock"); | |
| this.title = "[Perma Nom] Create"; | |
| return Nominations.displayNomPage(); | |
| } | |
| } | |
| }; | |
| process.nextTick(() => { | |
| Chat.multiLinePattern.register("/perma(noms?)? "); | |
| }); | |
| //# sourceMappingURL=permalocks.js.map | |