3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

Merge pull request #453 from ZeppelinBot/metal0-display-names

Update DJS + Display names fixes + per-server avatars (continued)
This commit is contained in:
Miikka 2024-01-27 14:39:01 +02:00 committed by GitHub
commit 601050838e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 282 additions and 324 deletions

View file

@ -14,7 +14,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"deep-diff": "^1.0.2", "deep-diff": "^1.0.2",
"discord.js": "^14.11.0", "discord.js": "^14.14.1",
"dotenv": "^4.0.0", "dotenv": "^4.0.0",
"emoji-regex": "^8.0.0", "emoji-regex": "^8.0.0",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
@ -253,78 +253,109 @@
} }
}, },
"node_modules/@discordjs/builders": { "node_modules/@discordjs/builders": {
"version": "1.6.3", "version": "1.7.0",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz",
"integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==",
"dependencies": { "dependencies": {
"@discordjs/formatters": "^0.3.1", "@discordjs/formatters": "^0.3.3",
"@discordjs/util": "^0.3.1", "@discordjs/util": "^1.0.2",
"@sapphire/shapeshift": "^3.8.2", "@sapphire/shapeshift": "^3.9.3",
"discord-api-types": "^0.37.41", "discord-api-types": "0.37.61",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.3", "ts-mixer": "^6.0.3",
"tslib": "^2.5.0" "tslib": "^2.6.2"
}, },
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
} }
}, },
"node_modules/@discordjs/collection": { "node_modules/@discordjs/collection": {
"version": "1.5.1", "version": "1.5.3",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz",
"integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==",
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
} }
}, },
"node_modules/@discordjs/formatters": { "node_modules/@discordjs/formatters": {
"version": "0.3.1", "version": "0.3.3",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz",
"integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==",
"dependencies": { "dependencies": {
"discord-api-types": "^0.37.41" "discord-api-types": "0.37.61"
}, },
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
} }
}, },
"node_modules/@discordjs/rest": { "node_modules/@discordjs/rest": {
"version": "1.7.1", "version": "2.2.0",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz",
"integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==",
"dependencies": { "dependencies": {
"@discordjs/collection": "^1.5.1", "@discordjs/collection": "^2.0.0",
"@discordjs/util": "^0.3.0", "@discordjs/util": "^1.0.2",
"@sapphire/async-queue": "^1.5.0", "@sapphire/async-queue": "^1.5.0",
"@sapphire/snowflake": "^3.4.2", "@sapphire/snowflake": "^3.5.1",
"discord-api-types": "^0.37.41", "@vladfrangu/async_event_emitter": "^2.2.2",
"file-type": "^18.3.0", "discord-api-types": "0.37.61",
"tslib": "^2.5.0", "magic-bytes.js": "^1.5.0",
"undici": "^5.22.0" "tslib": "^2.6.2",
"undici": "5.27.2"
}, },
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
}
},
"node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz",
"integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==",
"engines": {
"node": ">=18"
} }
}, },
"node_modules/@discordjs/util": { "node_modules/@discordjs/util": {
"version": "0.3.1", "version": "1.0.2",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz",
"integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==",
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
} }
}, },
"node_modules/@discordjs/ws": { "node_modules/@discordjs/ws": {
"version": "0.8.3", "version": "1.0.2",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz",
"integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==",
"dependencies": { "dependencies": {
"@discordjs/collection": "^1.5.1", "@discordjs/collection": "^2.0.0",
"@discordjs/rest": "^1.7.1", "@discordjs/rest": "^2.1.0",
"@discordjs/util": "^0.3.1", "@discordjs/util": "^1.0.2",
"@sapphire/async-queue": "^1.5.0", "@sapphire/async-queue": "^1.5.0",
"@types/ws": "^8.5.4", "@types/ws": "^8.5.9",
"@vladfrangu/async_event_emitter": "^2.2.1", "@vladfrangu/async_event_emitter": "^2.2.2",
"discord-api-types": "^0.37.41", "discord-api-types": "0.37.61",
"tslib": "^2.5.0", "tslib": "^2.6.2",
"ws": "^8.13.0" "ws": "^8.14.2"
}, },
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
}
},
"node_modules/@discordjs/ws/node_modules/@discordjs/collection": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz",
"integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==",
"engines": {
"node": ">=18"
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
"engines": {
"node": ">=14"
} }
}, },
"node_modules/@jest/types": { "node_modules/@jest/types": {
@ -384,28 +415,30 @@
} }
}, },
"node_modules/@sapphire/async-queue": { "node_modules/@sapphire/async-queue": {
"version": "1.5.0", "version": "1.5.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz",
"integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==",
"engines": { "engines": {
"node": ">=v14.0.0", "node": ">=v14.0.0",
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@sapphire/shapeshift": { "node_modules/@sapphire/shapeshift": {
"version": "3.9.2", "version": "3.9.6",
"license": "MIT", "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.6.tgz",
"integrity": "sha512-4+Na/fxu2SEepZRb9z0dbsVh59QtwPuBg/UVaDib3av7ZY14b14+z09z6QVn0P6Dv6eOU2NDTsjIi0mbtgP56g==",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"engines": { "engines": {
"node": ">=v14.0.0", "node": ">=v18"
"npm": ">=7.0.0"
} }
}, },
"node_modules/@sapphire/snowflake": { "node_modules/@sapphire/snowflake": {
"version": "3.5.1", "version": "3.5.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz",
"integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==",
"engines": { "engines": {
"node": ">=v14.0.0", "node": ">=v14.0.0",
"npm": ">=7.0.0" "npm": ">=7.0.0"
@ -467,10 +500,6 @@
"yarn": ">= 1.3.2" "yarn": ">= 1.3.2"
} }
}, },
"node_modules/@tokenizer/token": {
"version": "0.3.0",
"license": "MIT"
},
"node_modules/@types/body-parser": { "node_modules/@types/body-parser": {
"version": "1.19.2", "version": "1.19.2",
"dev": true, "dev": true,
@ -704,8 +733,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.5", "version": "8.5.9",
"license": "MIT", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz",
"integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
@ -724,8 +754,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vladfrangu/async_event_emitter": { "node_modules/@vladfrangu/async_event_emitter": {
"version": "2.2.2", "version": "2.2.4",
"license": "MIT", "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz",
"integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==",
"engines": { "engines": {
"node": ">=v14.0.0", "node": ">=v14.0.0",
"npm": ">=7.0.0" "npm": ">=7.0.0"
@ -2946,30 +2977,32 @@
} }
}, },
"node_modules/discord-api-types": { "node_modules/discord-api-types": {
"version": "0.37.47", "version": "0.37.61",
"license": "MIT" "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz",
"integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw=="
}, },
"node_modules/discord.js": { "node_modules/discord.js": {
"version": "14.11.0", "version": "14.14.1",
"license": "Apache-2.0", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz",
"integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==",
"dependencies": { "dependencies": {
"@discordjs/builders": "^1.6.3", "@discordjs/builders": "^1.7.0",
"@discordjs/collection": "^1.5.1", "@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.3.1", "@discordjs/formatters": "^0.3.3",
"@discordjs/rest": "^1.7.1", "@discordjs/rest": "^2.1.0",
"@discordjs/util": "^0.3.1", "@discordjs/util": "^1.0.2",
"@discordjs/ws": "^0.8.3", "@discordjs/ws": "^1.0.2",
"@sapphire/snowflake": "^3.4.2", "@sapphire/snowflake": "3.5.1",
"@types/ws": "^8.5.4", "@types/ws": "8.5.9",
"discord-api-types": "^0.37.41", "discord-api-types": "0.37.61",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "3.1.3",
"lodash.snakecase": "^4.1.1", "lodash.snakecase": "4.1.1",
"tslib": "^2.5.0", "tslib": "2.6.2",
"undici": "^5.22.0", "undici": "5.27.2",
"ws": "^8.13.0" "ws": "8.14.2"
}, },
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.11.0"
} }
}, },
"node_modules/distributions": { "node_modules/distributions": {
@ -3535,21 +3568,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/file-type": {
"version": "18.5.0",
"license": "MIT",
"dependencies": {
"readable-web-to-node-stream": "^3.0.2",
"strtok3": "^7.0.0",
"token-types": "^5.0.1"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
}
},
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.0.1", "version": "7.0.1",
"dev": true, "dev": true,
@ -5158,6 +5176,11 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/magic-bytes.js": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.8.0.tgz",
"integrity": "sha512-lyWpfvNGVb5lu8YUAbER0+UMBTdR63w2mcSUlhhBTyVbxJvjgqwyAf3AZD6MprgK0uHuBoWXSDAMWLupX83o3Q=="
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.25.1", "version": "0.25.1",
"license": "MIT", "license": "MIT",
@ -6366,17 +6389,6 @@
"node": ">=0.12" "node": ">=0.12"
} }
}, },
"node_modules/peek-readable": {
"version": "5.0.0",
"license": "MIT",
"engines": {
"node": ">=14.16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/performance-now": { "node_modules/performance-now": {
"version": "2.1.0", "version": "2.1.0",
"license": "MIT" "license": "MIT"
@ -6895,32 +6907,6 @@
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
}, },
"node_modules/readable-web-to-node-stream": {
"version": "3.0.2",
"license": "MIT",
"dependencies": {
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/readable-web-to-node-stream/node_modules/readable-stream": {
"version": "3.6.2",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "3.6.0", "version": "3.6.0",
"dev": true, "dev": true,
@ -7942,21 +7928,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/strtok3": {
"version": "7.0.0",
"license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"peek-readable": "^5.0.0"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/subarg": { "node_modules/subarg": {
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
@ -8191,21 +8162,6 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/token-types": {
"version": "5.0.1",
"license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/tough-cookie": { "node_modules/tough-cookie": {
"version": "4.1.3", "version": "4.1.3",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
@ -8291,7 +8247,8 @@
}, },
"node_modules/ts-mixer": { "node_modules/ts-mixer": {
"version": "6.0.3", "version": "6.0.3",
"license": "MIT" "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz",
"integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ=="
}, },
"node_modules/tsconfig-paths": { "node_modules/tsconfig-paths": {
"version": "3.14.2", "version": "3.14.2",
@ -8304,8 +8261,9 @@
} }
}, },
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.6.0", "version": "2.6.2",
"license": "0BSD" "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}, },
"node_modules/ttest": { "node_modules/ttest": {
"version": "3.0.0", "version": "3.0.0",
@ -8711,10 +8669,11 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/undici": { "node_modules/undici": {
"version": "5.22.1", "version": "5.27.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz",
"integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==",
"dependencies": { "dependencies": {
"busboy": "^1.6.0" "@fastify/busboy": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=14.0" "node": ">=14.0"
@ -8722,8 +8681,7 @@
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "5.26.5", "version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "license": "MIT"
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
}, },
"node_modules/uniq": { "node_modules/uniq": {
"version": "1.0.1", "version": "1.0.1",
@ -9051,8 +9009,9 @@
} }
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.13.0", "version": "8.14.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },

View file

@ -37,7 +37,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"deep-diff": "^1.0.2", "deep-diff": "^1.0.2",
"discord.js": "^14.11.0", "discord.js": "^14.14.1",
"dotenv": "^4.0.0", "dotenv": "^4.0.0",
"emoji-regex": "^8.0.0", "emoji-regex": "^8.0.0",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",

View file

@ -1,10 +1,4 @@
import { import { ChannelType, GuildTextThreadCreateOptions, ThreadAutoArchiveDuration, ThreadChannel } from "discord.js";
ChannelType,
GuildFeature,
GuildTextThreadCreateOptions,
ThreadAutoArchiveDuration,
ThreadChannel,
} from "discord.js";
import z from "zod"; import z from "zod";
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter"; import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
import { MINUTES, convertDelayStringToMS, noop, zBoundedCharacters, zDelayString } from "../../../utils"; import { MINUTES, convertDelayStringToMS, noop, zBoundedCharacters, zDelayString } from "../../../utils";
@ -43,7 +37,6 @@ export const StartThreadAction = automodAction({
return true; return true;
}); });
const guild = pluginData.guild;
const archiveSet = actionConfig.auto_archive const archiveSet = actionConfig.auto_archive
? Math.ceil(Math.max(convertDelayStringToMS(actionConfig.auto_archive) ?? 0, 0) / MINUTES) ? Math.ceil(Math.max(convertDelayStringToMS(actionConfig.auto_archive) ?? 0, 0) / MINUTES)
: ThreadAutoArchiveDuration.OneDay; : ThreadAutoArchiveDuration.OneDay;
@ -53,7 +46,7 @@ export const StartThreadAction = automodAction({
for (const threadContext of threads) { for (const threadContext of threads) {
const channel = pluginData.guild.channels.cache.get(threadContext.message!.channel_id); const channel = pluginData.guild.channels.cache.get(threadContext.message!.channel_id);
if (!channel || !("threads" in channel) || channel.type === ChannelType.GuildForum) continue; if (!channel || !("threads" in channel) || channel.isThreadOnly()) continue;
const renderThreadName = async (str: string) => const renderThreadName = async (str: string) =>
renderTemplate( renderTemplate(
@ -67,10 +60,7 @@ export const StartThreadAction = automodAction({
const threadOptions: GuildTextThreadCreateOptions<unknown> = { const threadOptions: GuildTextThreadCreateOptions<unknown> = {
name: threadName, name: threadName,
autoArchiveDuration: autoArchive, autoArchiveDuration: autoArchive,
startMessage: startMessage: !actionConfig.private ? threadContext.message!.id : undefined,
!actionConfig.private && guild.features.includes(GuildFeature.PrivateThreads)
? threadContext.message!.id
: undefined,
}; };
let thread: ThreadChannel | undefined; let thread: ThreadChannel | undefined;
@ -86,10 +76,7 @@ export const StartThreadAction = automodAction({
.create({ .create({
...threadOptions, ...threadOptions,
type: actionConfig.private ? ChannelType.PrivateThread : ChannelType.PublicThread, type: actionConfig.private ? ChannelType.PrivateThread : ChannelType.PublicThread,
startMessage: startMessage: !actionConfig.private ? threadContext.message!.id : undefined,
!actionConfig.private && guild.features.includes(GuildFeature.PrivateThreads)
? threadContext.message!.id
: undefined,
}) })
.catch(() => undefined); .catch(() => undefined);
} }

View file

@ -42,7 +42,7 @@ export async function* matchMultipleTextTypesOnMessage(
} }
if (trigger.match_visible_names) { if (trigger.match_visible_names) {
yield ["visiblename", member.nickname || msg.data.author.username]; yield ["visiblename", member.displayName || msg.data.author.username];
} }
if (trigger.match_usernames) { if (trigger.match_usernames) {

View file

@ -1,6 +1,6 @@
import { Snowflake } from "discord.js"; import { Snowflake } from "discord.js";
import z from "zod"; import z from "zod";
import { renderUserUsername, zSnowflake } from "../../../utils"; import { zSnowflake } from "../../../utils";
import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges"; import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
import { automodTrigger } from "../helpers"; import { automodTrigger } from "../helpers";
@ -38,7 +38,7 @@ export const RoleAddedTrigger = automodTrigger<RoleAddedMatchResult>()({
const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake); const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake);
const roleName = role?.name || "Unknown"; const roleName = role?.name || "Unknown";
const member = contexts[0].member!; const member = contexts[0].member!;
const memberName = `**${renderUserUsername(member.user)}** (\`${member.id}\`)`; const memberName = `**${renderUsername(member)}** (\`${member.id}\`)`;
return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was added to ${memberName}`; return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was added to ${memberName}`;
}, },
}); });

View file

@ -1,6 +1,6 @@
import { Snowflake } from "discord.js"; import { Snowflake } from "discord.js";
import z from "zod"; import z from "zod";
import { renderUserUsername, zSnowflake } from "../../../utils"; import { zSnowflake } from "../../../utils";
import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges"; import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
import { automodTrigger } from "../helpers"; import { automodTrigger } from "../helpers";
@ -38,7 +38,7 @@ export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake); const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake);
const roleName = role?.name || "Unknown"; const roleName = role?.name || "Unknown";
const member = contexts[0].member!; const member = contexts[0].member!;
const memberName = `**${renderUserUsername(member.user)}** (\`${member.id}\`)`; const memberName = `**${renderUsername(member)}** (\`${member.id}\`)`;
return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was removed from ${memberName}`; return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was removed from ${memberName}`;
}, },
}); });

View file

@ -1,5 +1,6 @@
import { User, escapeBold, type Snowflake } from "discord.js"; import { User, escapeBold, type Snowflake } from "discord.js";
import z from "zod"; import z from "zod";
import { renderUsername } from "../../../utils";
import { automodTrigger } from "../helpers"; import { automodTrigger } from "../helpers";
interface ThreadArchiveResult { interface ThreadArchiveResult {
@ -47,7 +48,7 @@ export const ThreadArchiveTrigger = automodTrigger<ThreadArchiveResult>()({
const parentName = matchResult.extra.matchedThreadParentName; const parentName = matchResult.extra.matchedThreadParentName;
const base = `Thread **#${threadName}** (\`${threadId}\`) has been archived in the **#${parentName}** (\`${parentId}\`) channel`; const base = `Thread **#${threadName}** (\`${threadId}\`) has been archived in the **#${parentName}** (\`${parentId}\`) channel`;
if (threadOwner) { if (threadOwner) {
return `${base} by **${escapeBold(threadOwner.tag)}** (\`${threadOwner.id}\`)`; return `${base} by **${escapeBold(renderUsername(threadOwner))}** (\`${threadOwner.id}\`)`;
} }
return base; return base;
}, },

View file

@ -1,5 +1,6 @@
import { User, escapeBold, type Snowflake } from "discord.js"; import { User, escapeBold, type Snowflake } from "discord.js";
import z from "zod"; import z from "zod";
import { renderUsername } from "../../../utils.js";
import { automodTrigger } from "../helpers"; import { automodTrigger } from "../helpers";
interface ThreadCreateResult { interface ThreadCreateResult {
@ -41,7 +42,7 @@ export const ThreadCreateTrigger = automodTrigger<ThreadCreateResult>()({
const parentName = matchResult.extra.matchedThreadParentName; const parentName = matchResult.extra.matchedThreadParentName;
const base = `Thread **#${threadName}** (\`${threadId}\`) has been created in the **#${parentName}** (\`${parentId}\`) channel`; const base = `Thread **#${threadName}** (\`${threadId}\`) has been created in the **#${parentName}** (\`${parentId}\`) channel`;
if (threadOwner) { if (threadOwner) {
return `${base} by **${escapeBold(threadOwner.tag)}** (\`${threadOwner.id}\`)`; return `${base} by **${escapeBold(renderUsername(threadOwner))}** (\`${threadOwner.id}\`)`;
} }
return base; return base;
}, },

View file

@ -1,5 +1,6 @@
import { User, escapeBold, type Snowflake } from "discord.js"; import { User, escapeBold, type Snowflake } from "discord.js";
import z from "zod"; import z from "zod";
import { renderUsername } from "../../../utils.js";
import { automodTrigger } from "../helpers"; import { automodTrigger } from "../helpers";
interface ThreadDeleteResult { interface ThreadDeleteResult {
@ -41,7 +42,7 @@ export const ThreadDeleteTrigger = automodTrigger<ThreadDeleteResult>()({
const parentName = matchResult.extra.matchedThreadParentName; const parentName = matchResult.extra.matchedThreadParentName;
if (threadOwner) { if (threadOwner) {
return `Thread **#${threadName ?? "Unknown"}** (\`${threadId}\`) created by **${escapeBold( return `Thread **#${threadName ?? "Unknown"}** (\`${threadId}\`) created by **${escapeBold(
threadOwner.tag, renderUsername(threadOwner),
)}** (\`${threadOwner.id}\`) in the **#${parentName}** (\`${parentId}\`) channel has been deleted`; )}** (\`${threadOwner.id}\`) in the **#${parentName}** (\`${parentId}\`) channel has been deleted`;
} }
return `Thread **#${ return `Thread **#${

View file

@ -1,5 +1,6 @@
import { User, escapeBold, type Snowflake } from "discord.js"; import { User, escapeBold, type Snowflake } from "discord.js";
import z from "zod"; import z from "zod";
import { renderUsername } from "../../../utils";
import { automodTrigger } from "../helpers"; import { automodTrigger } from "../helpers";
interface ThreadUnarchiveResult { interface ThreadUnarchiveResult {
@ -47,7 +48,7 @@ export const ThreadUnarchiveTrigger = automodTrigger<ThreadUnarchiveResult>()({
const parentName = matchResult.extra.matchedThreadParentName; const parentName = matchResult.extra.matchedThreadParentName;
const base = `Thread **#${threadName}** (\`${threadId}\`) has been unarchived in the **#${parentName}** (\`${parentId}\`) channel`; const base = `Thread **#${threadName}** (\`${threadId}\`) has been unarchived in the **#${parentName}** (\`${parentId}\`) channel`;
if (threadOwner) { if (threadOwner) {
return `${base} by **${escapeBold(threadOwner.tag)}** (\`${threadOwner.id}\`)`; return `${base} by **${escapeBold(renderUsername(threadOwner))}** (\`${threadOwner.id}\`)`;
} }
return base; return base;
}, },

View file

@ -1,7 +1,7 @@
import { ApiPermissions } from "@shared/apiPermissions"; import { ApiPermissions } from "@shared/apiPermissions";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { isStaffPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername } from "../../../utils"; import { renderUsername } from "../../../utils";
import { botControlCmd } from "../types"; import { botControlCmd } from "../types";
export const AddDashboardUserCmd = botControlCmd({ export const AddDashboardUserCmd = botControlCmd({
@ -35,7 +35,7 @@ export const AddDashboardUserCmd = botControlCmd({
await pluginData.state.apiPermissionAssignments.addUser(args.guildId, user.id, [ApiPermissions.EditConfig]); await pluginData.state.apiPermissionAssignments.addUser(args.guildId, user.id, [ApiPermissions.EditConfig]);
} }
const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUserUsername(user)}**, \`${user.id}\`)`); const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUsername(user)}**, \`${user.id}\`)`);
sendSuccessMessage( sendSuccessMessage(
pluginData, pluginData,
msg.channel, msg.channel,

View file

@ -2,7 +2,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes";
import { AllowedGuild } from "../../../data/entities/AllowedGuild"; import { AllowedGuild } from "../../../data/entities/AllowedGuild";
import { ApiPermissionAssignment } from "../../../data/entities/ApiPermissionAssignment"; import { ApiPermissionAssignment } from "../../../data/entities/ApiPermissionAssignment";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername, resolveUser } from "../../../utils"; import { renderUsername, resolveUser } from "../../../utils";
import { botControlCmd } from "../types"; import { botControlCmd } from "../types";
export const ListDashboardPermsCmd = botControlCmd({ export const ListDashboardPermsCmd = botControlCmd({
@ -42,7 +42,7 @@ export const ListDashboardPermsCmd = botControlCmd({
// If we have user, always display which guilds they have permissions in (or only specified guild permissions) // If we have user, always display which guilds they have permissions in (or only specified guild permissions)
if (args.user) { if (args.user) {
const userInfo = `**${renderUserUsername(args.user)}** (\`${args.user.id}\`)`; const userInfo = `**${renderUsername(args.user)}** (\`${args.user.id}\`)`;
for (const assignment of existingUserAssignment!) { for (const assignment of existingUserAssignment!) {
if (guild != null && assignment.guild_id !== args.guildId) continue; if (guild != null && assignment.guild_id !== args.guildId) continue;
@ -74,7 +74,7 @@ export const ListDashboardPermsCmd = botControlCmd({
finalMessage += `The server ${guildInfo} has the following assigned permissions:\n`; // Double \n for consistency with AddDashboardUserCmd finalMessage += `The server ${guildInfo} has the following assigned permissions:\n`; // Double \n for consistency with AddDashboardUserCmd
for (const assignment of existingGuildAssignment) { for (const assignment of existingGuildAssignment) {
const user = await resolveUser(pluginData.client, assignment.target_id); const user = await resolveUser(pluginData.client, assignment.target_id);
finalMessage += `\n**${renderUserUsername(user)}**, \`${assignment.target_id}\`: ${assignment.permissions.join( finalMessage += `\n**${renderUsername(user)}**, \`${assignment.target_id}\`: ${assignment.permissions.join(
", ", ", ",
)}`; )}`;
} }

View file

@ -1,6 +1,6 @@
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername, resolveUser } from "../../../utils"; import { renderUsername, resolveUser } from "../../../utils";
import { botControlCmd } from "../types"; import { botControlCmd } from "../types";
export const ListDashboardUsersCmd = botControlCmd({ export const ListDashboardUsersCmd = botControlCmd({
@ -27,7 +27,7 @@ export const ListDashboardUsersCmd = botControlCmd({
); );
const userNameList = users.map( const userNameList = users.map(
({ user, permission }) => ({ user, permission }) =>
`<@!${user.id}> (**${renderUserUsername(user)}**, \`${user.id}\`): ${permission.permissions.join(", ")}`, `<@!${user.id}> (**${renderUsername(user)}**, \`${user.id}\`): ${permission.permissions.join(", ")}`,
); );
sendSuccessMessage( sendSuccessMessage(

View file

@ -1,6 +1,6 @@
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { isStaffPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername } from "../../../utils"; import { renderUsername } from "../../../utils";
import { botControlCmd } from "../types"; import { botControlCmd } from "../types";
export const RemoveDashboardUserCmd = botControlCmd({ export const RemoveDashboardUserCmd = botControlCmd({
@ -34,7 +34,7 @@ export const RemoveDashboardUserCmd = botControlCmd({
await pluginData.state.apiPermissionAssignments.removeUser(args.guildId, user.id); await pluginData.state.apiPermissionAssignments.removeUser(args.guildId, user.id);
} }
const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUserUsername(user)}**, \`${user.id}\`)`); const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUsername(user)}**, \`${user.id}\`)`);
sendSuccessMessage( sendSuccessMessage(
pluginData, pluginData,
msg.channel, msg.channel,

View file

@ -1,7 +1,7 @@
import escapeStringRegexp from "escape-string-regexp"; import escapeStringRegexp from "escape-string-regexp";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter } from "../../../pluginUtils"; import { isStaffPreFilter } from "../../../pluginUtils";
import { createChunkedMessage, getUser, sorter } from "../../../utils"; import { createChunkedMessage, getUser, renderUsername, sorter } from "../../../utils";
import { botControlCmd } from "../types"; import { botControlCmd } from "../types";
export const ServersCmd = botControlCmd({ export const ServersCmd = botControlCmd({
@ -48,7 +48,9 @@ export const ServersCmd = botControlCmd({
const lines = filteredGuilds.map((g) => { const lines = filteredGuilds.map((g) => {
const paddedId = g.id.padEnd(longestId, " "); const paddedId = g.id.padEnd(longestId, " ");
const owner = getUser(pluginData.client, g.ownerId); const owner = getUser(pluginData.client, g.ownerId);
return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${owner.tag}** \`${owner.id}\`)`; return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${renderUsername(owner)}** \`${
owner.id
}\`)`;
}); });
createChunkedMessage(msg.channel, lines.join("\n")); createChunkedMessage(msg.channel, lines.join("\n"));
} else { } else {

View file

@ -1,23 +1,23 @@
import type { Snowflake } from "discord.js"; import type { Snowflake } from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { logger } from "../../../logger"; import { logger } from "../../../logger";
import { renderUserUsername, resolveUser } from "../../../utils"; import { renderUsername, resolveUser } from "../../../utils";
import { CaseArgs, CasesPluginType } from "../types"; import { CaseArgs, CasesPluginType } from "../types";
import { createCaseNote } from "./createCaseNote"; import { createCaseNote } from "./createCaseNote";
import { postCaseToCaseLogChannel } from "./postToCaseLogChannel"; import { postCaseToCaseLogChannel } from "./postToCaseLogChannel";
export async function createCase(pluginData: GuildPluginData<CasesPluginType>, args: CaseArgs) { export async function createCase(pluginData: GuildPluginData<CasesPluginType>, args: CaseArgs) {
const user = await resolveUser(pluginData.client, args.userId); const user = await resolveUser(pluginData.client, args.userId);
const userName = renderUserUsername(user); const name = renderUsername(user);
const mod = await resolveUser(pluginData.client, args.modId); const mod = await resolveUser(pluginData.client, args.modId);
const modName = mod.tag; const modName = renderUsername(mod);
let ppName: string | null = null; let ppName: string | null = null;
let ppId: Snowflake | null = null; let ppId: Snowflake | null = null;
if (args.ppId) { if (args.ppId) {
const pp = await resolveUser(pluginData.client, args.ppId); const pp = await resolveUser(pluginData.client, args.ppId);
ppName = pp.tag; ppName = renderUsername(pp);
ppId = pp.id; ppId = pp.id;
} }
@ -32,7 +32,7 @@ export async function createCase(pluginData: GuildPluginData<CasesPluginType>, a
const createdCase = await pluginData.state.cases.create({ const createdCase = await pluginData.state.cases.create({
type: args.type, type: args.type,
user_id: user.id, user_id: user.id,
user_name: userName, user_name: name,
mod_id: mod.id, mod_id: mod.id,
mod_name: modName, mod_name: modName,
audit_log_id: args.auditLogId, audit_log_id: args.auditLogId,

View file

@ -1,6 +1,6 @@
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
import { UnknownUser, resolveUser } from "../../../utils"; import { UnknownUser, renderUsername, resolveUser } from "../../../utils";
import { CaseNoteArgs, CasesPluginType } from "../types"; import { CaseNoteArgs, CasesPluginType } from "../types";
import { postCaseToCaseLogChannel } from "./postToCaseLogChannel"; import { postCaseToCaseLogChannel } from "./postToCaseLogChannel";
import { resolveCaseId } from "./resolveCaseId"; import { resolveCaseId } from "./resolveCaseId";
@ -16,7 +16,7 @@ export async function createCaseNote(pluginData: GuildPluginData<CasesPluginType
throw new RecoverablePluginError(ERRORS.INVALID_USER); throw new RecoverablePluginError(ERRORS.INVALID_USER);
} }
const modName = mod.tag; const modName = renderUsername(mod);
let body = args.body; let body = args.body;

View file

@ -68,10 +68,9 @@ export const ArchiveChannelCmd = channelArchiverCmd({
for (const message of messages.values()) { for (const message of messages.values()) {
const ts = moment.utc(message.createdTimestamp).format("YYYY-MM-DD HH:mm:ss"); const ts = moment.utc(message.createdTimestamp).format("YYYY-MM-DD HH:mm:ss");
let content = `[${ts}] [${message.author.id}] [${renderUsername( let content = `[${ts}] [${message.author.id}] [${renderUsername(message.author)}]: ${
message.author.username, message.content || "<no text content>"
message.author.discriminator, }`;
)}]: ${message.content || "<no text content>"}`;
if (message.attachments.size) { if (message.attachments.size) {
if (args["attachment-channel"]) { if (args["attachment-channel"]) {

View file

@ -48,7 +48,7 @@ export async function sendMessage(
...content, ...content,
...(pluginData.client.user && { ...(pluginData.client.user && {
username: pluginData.client.user.username, username: pluginData.client.user.username,
avatarURL: pluginData.client.user.avatarURL() || pluginData.client.user.defaultAvatarURL, avatarURL: pluginData.client.user.displayAvatarURL(),
}), }),
}) })
.then((apiMessage) => ({ .then((apiMessage) => ({

View file

@ -3,7 +3,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
import { Case } from "../../../data/entities/Case"; import { Case } from "../../../data/entities/Case";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername, resolveMember, resolveUser } from "../../../utils"; import { renderUsername, resolveMember, resolveUser } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { modActionsCmd } from "../types"; import { modActionsCmd } from "../types";
@ -75,7 +75,7 @@ export const AddCaseCmd = modActionsCmd({
sendSuccessMessage( sendSuccessMessage(
pluginData, pluginData,
msg.channel, msg.channel,
`Case #${theCase.case_number} created for **${renderUserUsername(user)}**`, `Case #${theCase.case_number} created for **${renderUsername(user)}**`,
); );
} else { } else {
sendSuccessMessage(pluginData, msg.channel, `Case #${theCase.case_number} created`); sendSuccessMessage(pluginData, msg.channel, `Case #${theCase.case_number} created`);

View file

@ -5,7 +5,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
import { clearExpiringTempban, registerExpiringTempban } from "../../../data/loops/expiringTempbansLoop"; import { clearExpiringTempban, registerExpiringTempban } from "../../../data/loops/expiringTempbansLoop";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { renderUserUsername, resolveMember, resolveUser } from "../../../utils"; import { renderUsername, resolveMember, resolveUser } from "../../../utils";
import { banLock } from "../../../utils/lockNameHelpers"; import { banLock } from "../../../utils/lockNameHelpers";
import { waitForButtonConfirm } from "../../../utils/waitForInteraction"; import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
@ -207,7 +207,7 @@ export const BanCmd = modActionsCmd({
// Confirm the action to the moderator // Confirm the action to the moderator
let response = ""; let response = "";
if (!forceban) { if (!forceban) {
response = `Banned **${renderUserUsername(user)}** ${forTime}(Case #${banResult.case.case_number})`; response = `Banned **${renderUsername(user)}** ${forTime}(Case #${banResult.case.case_number})`;
if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`; if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`;
} else { } else {
response = `Member forcebanned ${forTime}(Case #${banResult.case.case_number})`; response = `Member forcebanned ${forTime}(Case #${banResult.case.case_number})`;

View file

@ -1,7 +1,7 @@
import { APIEmbed, User } from "discord.js"; import { APIEmbed } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage } from "../../../pluginUtils"; import { sendErrorMessage } from "../../../pluginUtils";
import { emptyEmbedValue, resolveUser, trimLines } from "../../../utils"; import { UnknownUser, emptyEmbedValue, renderUsername, resolveMember, resolveUser, trimLines } from "../../../utils";
import { asyncMap } from "../../../utils/async"; import { asyncMap } from "../../../utils/async";
import { createPaginatedMessage } from "../../../utils/createPaginatedMessage"; import { createPaginatedMessage } from "../../../utils/createPaginatedMessage";
import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields"; import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
@ -28,8 +28,10 @@ export const CasesModCmd = modActionsCmd({
async run({ pluginData, message: msg, args }) { async run({ pluginData, message: msg, args }) {
const modId = args.mod || msg.author.id; const modId = args.mod || msg.author.id;
const mod = await resolveUser(pluginData.client, modId); const mod =
const modName = mod instanceof User ? mod.tag : modId; (await resolveMember(pluginData.client, pluginData.guild, modId)) ||
(await resolveUser(pluginData.client, modId));
const modName = mod instanceof UnknownUser ? modId : renderUsername(mod);
const casesPlugin = pluginData.getPlugin(CasesPlugin); const casesPlugin = pluginData.getPlugin(CasesPlugin);
const totalCases = await casesPlugin.getTotalCasesByMod(modId); const totalCases = await casesPlugin.getTotalCasesByMod(modId);
@ -57,7 +59,7 @@ export const CasesModCmd = modActionsCmd({
const embed = { const embed = {
author: { author: {
name: title, name: title,
icon_url: mod instanceof User ? mod.displayAvatarURL() : undefined, icon_url: mod instanceof UnknownUser ? undefined : mod.displayAvatarURL(),
}, },
fields: [ fields: [
...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")), ...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")),

View file

@ -1,9 +1,17 @@
import { APIEmbed, User } from "discord.js"; import { APIEmbed } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes"; import { CaseTypes } from "../../../data/CaseTypes";
import { sendErrorMessage } from "../../../pluginUtils"; import { sendErrorMessage } from "../../../pluginUtils";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { UnknownUser, chunkArray, emptyEmbedValue, renderUserUsername, resolveUser, trimLines } from "../../../utils"; import {
UnknownUser,
chunkArray,
emptyEmbedValue,
renderUsername,
resolveMember,
resolveUser,
trimLines,
} from "../../../utils";
import { asyncMap } from "../../../utils/async"; import { asyncMap } from "../../../utils/async";
import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields"; import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
import { getGuildPrefix } from "../../../utils/getGuildPrefix"; import { getGuildPrefix } from "../../../utils/getGuildPrefix";
@ -35,8 +43,10 @@ export const CasesUserCmd = modActionsCmd({
], ],
async run({ pluginData, message: msg, args }) { async run({ pluginData, message: msg, args }) {
const user = await resolveUser(pluginData.client, args.user); const user =
if (!user.id) { (await resolveMember(pluginData.client, pluginData.guild, args.user)) ||
(await resolveUser(pluginData.client, args.user));
if (user instanceof UnknownUser) {
sendErrorMessage(pluginData, msg.channel, `User not found`); sendErrorMessage(pluginData, msg.channel, `User not found`);
return; return;
} }
@ -62,7 +72,7 @@ export const CasesUserCmd = modActionsCmd({
const hiddenCases = cases.filter((c) => c.is_hidden); const hiddenCases = cases.filter((c) => c.is_hidden);
const userName = const userName =
user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUserUsername(user); user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUsername(user);
if (cases.length === 0) { if (cases.length === 0) {
msg.channel.send(`No cases found for **${userName}**`); msg.channel.send(`No cases found for **${userName}**`);
@ -123,7 +133,7 @@ export const CasesUserCmd = modActionsCmd({
lineChunks.length === 1 lineChunks.length === 1
? `Cases for ${userName} (${lines.length} total)` ? `Cases for ${userName} (${lines.length} total)`
: `Cases ${chunkStart}${chunkEnd} of ${lines.length} for ${userName}`, : `Cases ${chunkStart}${chunkEnd} of ${lines.length} for ${userName}`,
icon_url: user instanceof User ? user.displayAvatarURL() : undefined, icon_url: user.displayAvatarURL(),
}, },
fields: [ fields: [
...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")), ...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")),

View file

@ -2,7 +2,7 @@ import { helpers } from "knub";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { Case } from "../../../data/entities/Case"; import { Case } from "../../../data/entities/Case";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { SECONDS, trimLines } from "../../../utils"; import { SECONDS, renderUsername, trimLines } from "../../../utils";
import { CasesPlugin } from "../../Cases/CasesPlugin"; import { CasesPlugin } from "../../Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
@ -60,7 +60,7 @@ export const DeleteCaseCmd = modActionsCmd({
} }
} }
const deletedByName = message.author.tag; const deletedByName = renderUsername(message.author);
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin); const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
const deletedAt = timeAndDate.inGuildTz().format(timeAndDate.getDateFormat("pretty_datetime")); const deletedAt = timeAndDate.inGuildTz().format(timeAndDate.getDateFormat("pretty_datetime"));

View file

@ -1,7 +1,7 @@
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes"; import { CaseTypes } from "../../../data/CaseTypes";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername, resolveUser } from "../../../utils"; import { renderUsername, resolveUser } from "../../../utils";
import { CasesPlugin } from "../../Cases/CasesPlugin"; import { CasesPlugin } from "../../Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
@ -29,7 +29,7 @@ export const NoteCmd = modActionsCmd({
return; return;
} }
const userName = renderUserUsername(user); const userName = renderUsername(user);
const reason = formatReasonWithAttachments(args.note, [...msg.attachments.values()]); const reason = formatReasonWithAttachments(args.note, [...msg.attachments.values()]);
const casesPlugin = pluginData.getPlugin(CasesPlugin); const casesPlugin = pluginData.getPlugin(CasesPlugin);

View file

@ -1,7 +1,7 @@
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes"; import { CaseTypes } from "../../../data/CaseTypes";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { errorMessage, renderUserUsername, resolveMember, resolveUser } from "../../../utils"; import { errorMessage, renderUsername, resolveMember, resolveUser } from "../../../utils";
import { waitForButtonConfirm } from "../../../utils/waitForInteraction"; import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
import { CasesPlugin } from "../../Cases/CasesPlugin"; import { CasesPlugin } from "../../Cases/CasesPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
@ -106,7 +106,7 @@ export const WarnCmd = modActionsCmd({
sendSuccessMessage( sendSuccessMessage(
pluginData, pluginData,
msg.channel, msg.channel,
`Warned **${renderUserUsername(memberToWarn.user)}** (Case #${warnResult.case.case_number})${messageResultText}`, `Warned **${renderUsername(memberToWarn)}** (Case #${warnResult.case.case_number})${messageResultText}`,
); );
}, },
}); });

View file

@ -1,5 +1,5 @@
import { PermissionsBitField, Snowflake, TextChannel } from "discord.js"; import { PermissionsBitField, Snowflake, TextChannel } from "discord.js";
import { renderUserUsername, resolveMember } from "../../../utils"; import { renderUsername, resolveMember } from "../../../utils";
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions"; import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { modActionsEvt } from "../types"; import { modActionsEvt } from "../types";
@ -46,9 +46,7 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt({
} }
await alertChannel.send( await alertChannel.send(
`<@!${member.id}> (${renderUserUsername(member.user)} \`${member.id}\`) joined with ${ `<@!${member.id}> (${renderUsername(member)} \`${member.id}\`) joined with ${actions.length} prior record(s)`,
actions.length
} prior record(s)`,
); );
} }
}, },

View file

@ -3,7 +3,7 @@ import { GuildPluginData } from "knub";
import { hasPermission } from "knub/helpers"; import { hasPermission } from "knub/helpers";
import { LogType } from "../../../data/LogType"; import { LogType } from "../../../data/LogType";
import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { DAYS, SECONDS, errorMessage, renderUserUsername, resolveMember, resolveUser } from "../../../utils"; import { DAYS, SECONDS, errorMessage, renderUsername, resolveMember, resolveUser } from "../../../utils";
import { IgnoredEventType, ModActionsPluginType } from "../types"; import { IgnoredEventType, ModActionsPluginType } from "../types";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
import { ignoreEvent } from "./ignoreEvent"; import { ignoreEvent } from "./ignoreEvent";
@ -103,7 +103,7 @@ export async function actualKickMemberCmd(
} }
// Confirm the action to the moderator // Confirm the action to the moderator
let response = `Kicked **${renderUserUsername(memberToKick.user)}** (Case #${kickResult.case.case_number})`; let response = `Kicked **${renderUsername(memberToKick)}** (Case #${kickResult.case.case_number})`;
if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`; if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
sendSuccessMessage(pluginData, msg.channel, response); sendSuccessMessage(pluginData, msg.channel, response);

View file

@ -4,7 +4,7 @@ import { GuildPluginData } from "knub";
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
import { logger } from "../../../logger"; import { logger } from "../../../logger";
import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { UnknownUser, asSingleLine, isDiscordAPIError, renderUserUsername } from "../../../utils"; import { UnknownUser, asSingleLine, isDiscordAPIError, renderUsername } from "../../../utils";
import { MutesPlugin } from "../../Mutes/MutesPlugin"; import { MutesPlugin } from "../../Mutes/MutesPlugin";
import { MuteResult } from "../../Mutes/types"; import { MuteResult } from "../../Mutes/types";
import { ModActionsPluginType } from "../types"; import { ModActionsPluginType } from "../types";
@ -86,24 +86,24 @@ export async function actualMuteUserCmd(
if (args.time) { if (args.time) {
if (muteResult.updatedExistingMute) { if (muteResult.updatedExistingMute) {
response = asSingleLine(` response = asSingleLine(`
Updated **${renderUserUsername(user)}**'s Updated **${renderUsername(user)}**'s
mute to ${timeUntilUnmute} (Case #${muteResult.case.case_number}) mute to ${timeUntilUnmute} (Case #${muteResult.case.case_number})
`); `);
} else { } else {
response = asSingleLine(` response = asSingleLine(`
Muted **${renderUserUsername(user)}** Muted **${renderUsername(user)}**
for ${timeUntilUnmute} (Case #${muteResult.case.case_number}) for ${timeUntilUnmute} (Case #${muteResult.case.case_number})
`); `);
} }
} else { } else {
if (muteResult.updatedExistingMute) { if (muteResult.updatedExistingMute) {
response = asSingleLine(` response = asSingleLine(`
Updated **${renderUserUsername(user)}**'s Updated **${renderUsername(user)}**'s
mute to indefinite (Case #${muteResult.case.case_number}) mute to indefinite (Case #${muteResult.case.case_number})
`); `);
} else { } else {
response = asSingleLine(` response = asSingleLine(`
Muted **${renderUserUsername(user)}** Muted **${renderUsername(user)}**
indefinitely (Case #${muteResult.case.case_number}) indefinitely (Case #${muteResult.case.case_number})
`); `);
} }

View file

@ -3,7 +3,7 @@ import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin"; import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
import { UnknownUser, asSingleLine, renderUserUsername } from "../../../utils"; import { UnknownUser, asSingleLine, renderUsername } from "../../../utils";
import { ModActionsPluginType } from "../types"; import { ModActionsPluginType } from "../types";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
@ -48,7 +48,7 @@ export async function actualUnmuteCmd(
pluginData, pluginData,
msg.channel, msg.channel,
asSingleLine(` asSingleLine(`
Unmuting **${renderUserUsername(user)}** Unmuting **${renderUsername(user)}**
in ${timeUntilUnmute} (Case #${result.case.case_number}) in ${timeUntilUnmute} (Case #${result.case.case_number})
`), `),
); );
@ -57,7 +57,7 @@ export async function actualUnmuteCmd(
pluginData, pluginData,
msg.channel, msg.channel,
asSingleLine(` asSingleLine(`
Unmuted **${renderUserUsername(user)}** Unmuted **${renderUsername(user)}**
(Case #${result.case.case_number}) (Case #${result.case.case_number})
`), `),
); );

View file

@ -10,7 +10,7 @@ import moment from "moment-timezone";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { humanizeDurationShort } from "../../../humanizeDurationShort"; import { humanizeDurationShort } from "../../../humanizeDurationShort";
import { getBaseUrl } from "../../../pluginUtils"; import { getBaseUrl } from "../../../pluginUtils";
import { DBDateFormat, MINUTES, renderUserUsername, resolveMember } from "../../../utils"; import { DBDateFormat, MINUTES, renderUsername, resolveMember } from "../../../utils";
import { IMuteWithDetails, mutesCmd } from "../types"; import { IMuteWithDetails, mutesCmd } from "../types";
export const MutesCmd = mutesCmd({ export const MutesCmd = mutesCmd({
@ -74,7 +74,7 @@ export const MutesCmd = mutesCmd({
totalMutes = manuallyMutedMembers.length; totalMutes = manuallyMutedMembers.length;
lines = manuallyMutedMembers.map((member) => { lines = manuallyMutedMembers.map((member) => {
return `<@!${member.id}> (**${renderUserUsername(member.user)}**, \`${member.id}\`) 🔧 Manual mute`; return `<@!${member.id}> (**${renderUsername(member)}**, \`${member.id}\`) 🔧 Manual mute`;
}); });
} else { } else {
// Show filtered active mutes (but not manual mutes) // Show filtered active mutes (but not manual mutes)
@ -123,7 +123,7 @@ export const MutesCmd = mutesCmd({
lines = filteredMutes.map((mute) => { lines = filteredMutes.map((mute) => {
const user = pluginData.client.users.resolve(mute.user_id as Snowflake); const user = pluginData.client.users.resolve(mute.user_id as Snowflake);
const username = user ? renderUserUsername(user) : "Unknown#0000"; const username = user ? renderUsername(user) : "Unknown#0000";
const theCase = muteCasesById.get(mute.case_id); const theCase = muteCasesById.get(mute.case_id);
const caseName = theCase ? `Case #${theCase.case_number}` : "No case"; const caseName = theCase ? `Case #${theCase.case_number}` : "No case";

View file

@ -5,7 +5,7 @@ import { MAX_NICKNAME_ENTRIES_PER_USER } from "../../../data/GuildNicknameHistor
import { MAX_USERNAME_ENTRIES_PER_USER } from "../../../data/UsernameHistory"; import { MAX_USERNAME_ENTRIES_PER_USER } from "../../../data/UsernameHistory";
import { NICKNAME_RETENTION_PERIOD } from "../../../data/cleanup/nicknames"; import { NICKNAME_RETENTION_PERIOD } from "../../../data/cleanup/nicknames";
import { sendErrorMessage } from "../../../pluginUtils"; import { sendErrorMessage } from "../../../pluginUtils";
import { DAYS, renderUserUsername } from "../../../utils"; import { DAYS, renderUsername } from "../../../utils";
import { nameHistoryCmd } from "../types"; import { nameHistoryCmd } from "../types";
export const NamesCmd = nameHistoryCmd({ export const NamesCmd = nameHistoryCmd({
@ -31,7 +31,7 @@ export const NamesCmd = nameHistoryCmd({
const usernameRows = usernames.map((r) => `\`[${r.timestamp}]\` **${disableCodeBlocks(r.username)}**`); const usernameRows = usernames.map((r) => `\`[${r.timestamp}]\` **${disableCodeBlocks(r.username)}**`);
const user = await pluginData.client.users.fetch(args.userId as Snowflake).catch(() => null); const user = await pluginData.client.users.fetch(args.userId as Snowflake).catch(() => null);
const currentUsername = user ? renderUserUsername(user) : args.userId; const currentUsername = user ? renderUsername(user) : args.userId;
const nicknameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS); const nicknameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS);
const usernameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS); const usernameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS);

View file

@ -4,7 +4,7 @@ import { GuildPluginData } from "knub";
import moment from "moment-timezone"; import moment from "moment-timezone";
import { registerUpcomingScheduledPost } from "../../../data/loops/upcomingScheduledPostsLoop"; import { registerUpcomingScheduledPost } from "../../../data/loops/upcomingScheduledPostsLoop";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { DBDateFormat, MINUTES, StrictMessageContent, errorMessage } from "../../../utils"; import { DBDateFormat, MINUTES, StrictMessageContent, errorMessage, renderUsername } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
import { PostPluginType } from "../types"; import { PostPluginType } from "../types";
@ -122,7 +122,7 @@ export async function actualPostCmd(
const post = await pluginData.state.scheduledPosts.create({ const post = await pluginData.state.scheduledPosts.create({
author_id: msg.author.id, author_id: msg.author.id,
author_name: msg.author.tag, author_name: renderUsername(msg.author),
channel_id: targetChannel.id, channel_id: targetChannel.id,
content, content,
attachments: [...msg.attachments.values()], attachments: [...msg.attachments.values()],

View file

@ -1,7 +1,7 @@
import { Snowflake } from "discord.js"; import { Snowflake } from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { logger } from "../../../logger"; import { logger } from "../../../logger";
import { renderUserUsername, resolveMember } from "../../../utils"; import { renderUsername, resolveMember } from "../../../utils";
import { memberRolesLock } from "../../../utils/lockNameHelpers"; import { memberRolesLock } from "../../../utils/lockNameHelpers";
import { PendingMemberRoleChanges, ReactionRolesPluginType, RoleChangeMode } from "../types"; import { PendingMemberRoleChanges, ReactionRolesPluginType, RoleChangeMode } from "../types";
@ -33,9 +33,7 @@ export async function addMemberPendingRoleChange(
try { try {
await member.roles.set(Array.from(newRoleIds.values()), "Reaction roles"); await member.roles.set(Array.from(newRoleIds.values()), "Reaction roles");
} catch (e) { } catch (e) {
logger.warn( logger.warn(`Failed to apply role changes to ${renderUsername(member)} (${member.id}): ${e.message}`);
`Failed to apply role changes to ${renderUserUsername(member.user)} (${member.id}): ${e.message}`,
);
} }
} }
lock.unlock(); lock.unlock();

View file

@ -1,7 +1,7 @@
import { ChannelType, escapeInlineCode } from "discord.js"; import { ChannelType, escapeInlineCode } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { asSingleLine, renderUserUsername } from "../../../utils"; import { asSingleLine, renderUsername } from "../../../utils";
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions"; import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
import { missingPermissionError } from "../../../utils/missingPermissionError"; import { missingPermissionError } from "../../../utils/missingPermissionError";
import { BOT_SLOWMODE_CLEAR_PERMISSIONS } from "../requiredPermissions"; import { BOT_SLOWMODE_CLEAR_PERMISSIONS } from "../requiredPermissions";
@ -45,7 +45,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
pluginData, pluginData,
msg.channel, msg.channel,
asSingleLine(` asSingleLine(`
Failed to clear slowmode from **${renderUserUsername(args.user)}** in <#${args.channel.id}>: Failed to clear slowmode from **${renderUsername(args.user)}** in <#${args.channel.id}>:
Threads cannot have Bot Slowmode Threads cannot have Bot Slowmode
`), `),
); );
@ -56,7 +56,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
pluginData, pluginData,
msg.channel, msg.channel,
asSingleLine(` asSingleLine(`
Failed to clear slowmode from **${renderUserUsername(args.user)}** in <#${args.channel.id}>: Failed to clear slowmode from **${renderUsername(args.user)}** in <#${args.channel.id}>:
\`${escapeInlineCode(e.message)}\` \`${escapeInlineCode(e.message)}\`
`), `),
); );
@ -66,7 +66,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
sendSuccessMessage( sendSuccessMessage(
pluginData, pluginData,
msg.channel, msg.channel,
`Slowmode cleared from **${renderUserUsername(args.user)}** in <#${args.channel.id}>`, `Slowmode cleared from **${renderUsername(args.user)}** in <#${args.channel.id}>`,
); );
}, },
}); });

View file

@ -1,6 +1,6 @@
import { GuildChannel, Message } from "discord.js"; import { GuildChannel, Message } from "discord.js";
import path from "path"; import path from "path";
import { EMPTY_CHAR, EmbedWith } from "../../../utils"; import { EMPTY_CHAR, EmbedWith, renderUsername } from "../../../utils";
const imageAttachmentExtensions = ["jpeg", "jpg", "png", "gif", "webp"]; const imageAttachmentExtensions = ["jpeg", "jpg", "png", "gif", "webp"];
const audioAttachmentExtensions = ["wav", "mp3", "m4a"]; const audioAttachmentExtensions = ["wav", "mp3", "m4a"];
@ -18,7 +18,7 @@ export function createStarboardEmbedFromMessage(
text: `#${(msg.channel as GuildChannel).name}`, text: `#${(msg.channel as GuildChannel).name}`,
}, },
author: { author: {
name: msg.author.tag, name: renderUsername(msg.author),
}, },
fields: [], fields: [],
timestamp: msg.createdAt.toISOString(), timestamp: msg.createdAt.toISOString(),
@ -28,7 +28,7 @@ export function createStarboardEmbedFromMessage(
embed.color = color; embed.color = color;
} }
embed.author.icon_url = msg.author.displayAvatarURL(); embed.author.icon_url = (msg.member ?? msg.author).displayAvatarURL();
// The second condition here checks for messages with only an image link that is then embedded. // The second condition here checks for messages with only an image link that is then embedded.
// The message content in that case is hidden by the Discord client, so we hide it here too. // The message content in that case is hidden by the Discord client, so we hide it here too.

View file

@ -1,11 +1,11 @@
import { User } from "discord.js"; import { User } from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { renderUserUsername } from "../../utils"; import { renderUsername } from "../../utils";
import { UsernameSaverPluginType } from "./types"; import { UsernameSaverPluginType } from "./types";
export async function updateUsername(pluginData: GuildPluginData<UsernameSaverPluginType>, user: User) { export async function updateUsername(pluginData: GuildPluginData<UsernameSaverPluginType>, user: User) {
if (!user) return; if (!user) return;
const newUsername = renderUserUsername(user); const newUsername = renderUsername(user);
const latestEntry = await pluginData.state.usernameHistory.getLastEntry(user.id); const latestEntry = await pluginData.state.usernameHistory.getLastEntry(user.id);
if (!latestEntry || newUsername !== latestEntry.username) { if (!latestEntry || newUsername !== latestEntry.username) {
await pluginData.state.usernameHistory.addEntry(user.id, newUsername); await pluginData.state.usernameHistory.addEntry(user.id, newUsername);

View file

@ -100,8 +100,8 @@ export const AboutCmd = utilityCmd({
} }
// Use the bot avatar as the embed image // Use the bot avatar as the embed image
if (pluginData.client.user!.avatarURL()) { if (pluginData.client.user!.displayAvatarURL()) {
aboutEmbed.thumbnail = { url: pluginData.client.user!.avatarURL()! }; aboutEmbed.thumbnail = { url: pluginData.client.user!.displayAvatarURL()! };
} }
msg.channel.send({ embeds: [aboutEmbed] }); msg.channel.send({ embeds: [aboutEmbed] });

View file

@ -1,7 +1,7 @@
import { APIEmbed, ImageFormat } from "discord.js"; import { APIEmbed, ImageFormat } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage } from "../../../pluginUtils"; import { sendErrorMessage } from "../../../pluginUtils";
import { UnknownUser, renderUserUsername } from "../../../utils"; import { UnknownUser, renderUsername } from "../../../utils";
import { utilityCmd } from "../types"; import { utilityCmd } from "../types";
export const AvatarCmd = utilityCmd({ export const AvatarCmd = utilityCmd({
@ -10,17 +10,17 @@ export const AvatarCmd = utilityCmd({
permission: "can_avatar", permission: "can_avatar",
signature: { signature: {
user: ct.resolvedUserLoose({ required: false }), user: ct.resolvedMember({ required: false }) || ct.resolvedUserLoose({ required: false }),
}, },
async run({ message: msg, args, pluginData }) { async run({ message: msg, args, pluginData }) {
const user = args.user || msg.author; const user = args.user ?? msg.member ?? msg.author;
if (!(user instanceof UnknownUser)) { if (!(user instanceof UnknownUser)) {
const embed: APIEmbed = { const embed: APIEmbed = {
image: { image: {
url: user.displayAvatarURL({ extension: ImageFormat.PNG, size: 2048 }), url: user.displayAvatarURL({ extension: ImageFormat.PNG, size: 2048 }),
}, },
title: `Avatar of ${renderUserUsername(user)}:`, title: `Avatar of ${renderUsername(user)}:`,
}; };
msg.channel.send({ embeds: [embed] }); msg.channel.send({ embeds: [embed] });
} else { } else {

View file

@ -1,6 +1,6 @@
import { helpers } from "knub"; import { helpers } from "knub";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { renderUserUsername } from "../../../utils"; import { renderUsername } from "../../../utils";
import { utilityCmd } from "../types"; import { utilityCmd } from "../types";
const { getMemberLevel } = helpers; const { getMemberLevel } = helpers;
@ -18,6 +18,6 @@ export const LevelCmd = utilityCmd({
run({ message, args, pluginData }) { run({ message, args, pluginData }) {
const member = args.member || message.member; const member = args.member || message.member;
const level = getMemberLevel(pluginData, member); const level = getMemberLevel(pluginData, member);
message.channel.send(`The permission level of ${renderUserUsername(member.user)} is **${level}**`); message.channel.send(`The permission level of ${renderUsername(member)} is **${level}**`);
}, },
}); });

View file

@ -15,7 +15,7 @@ export const searchCmdSignature = {
export: ct.switchOption({ def: false, shortcut: "e" }), export: ct.switchOption({ def: false, shortcut: "e" }),
ids: ct.switchOption(), ids: ct.switchOption(),
regex: ct.switchOption({ def: false, shortcut: "re" }), regex: ct.switchOption({ def: false, shortcut: "re" }),
"status-search": ct.switchOption({ def: false, shortcut: "ss" }), // "status-search": ct.switchOption({ def: false, shortcut: "ss" }),
}; };
export const SearchCmd = utilityCmd({ export const SearchCmd = utilityCmd({

View file

@ -1,7 +1,7 @@
import { VoiceChannel } from "discord.js"; import { VoiceChannel } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername } from "../../../utils"; import { renderUsername } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { utilityCmd } from "../types"; import { utilityCmd } from "../types";
@ -43,7 +43,7 @@ export const VcdisconnectCmd = utilityCmd({
sendSuccessMessage( sendSuccessMessage(
pluginData, pluginData,
msg.channel, msg.channel,
`**${renderUserUsername(args.member.user)}** disconnected from **${channel.name}**`, `**${renderUsername(args.member)}** disconnected from **${channel.name}**`,
); );
}, },
}); });

View file

@ -1,7 +1,7 @@
import { ChannelType, Snowflake, VoiceChannel } from "discord.js"; import { ChannelType, Snowflake, VoiceChannel } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { channelMentionRegex, isSnowflake, renderUserUsername, simpleClosestStringMatch } from "../../../utils"; import { channelMentionRegex, isSnowflake, renderUsername, simpleClosestStringMatch } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { utilityCmd } from "../types"; import { utilityCmd } from "../types";
@ -80,11 +80,7 @@ export const VcmoveCmd = utilityCmd({
newChannel: channel, newChannel: channel,
}); });
sendSuccessMessage( sendSuccessMessage(pluginData, msg.channel, `**${renderUsername(args.member)}** moved to **${channel.name}**`);
pluginData,
msg.channel,
`**${renderUserUsername(args.member.user)}** moved to **${channel.name}**`,
);
}, },
}); });
@ -157,7 +153,7 @@ export const VcmoveAllCmd = utilityCmd({
sendErrorMessage( sendErrorMessage(
pluginData, pluginData,
msg.channel, msg.channel,
`Failed to move ${renderUserUsername(currMember.user)} (${currMember.id}): You cannot act on this member`, `Failed to move ${renderUsername(currMember)} (${currMember.id}): You cannot act on this member`,
); );
errAmt++; errAmt++;
continue; continue;
@ -172,11 +168,7 @@ export const VcmoveAllCmd = utilityCmd({
sendErrorMessage(pluginData, msg.channel, "Unknown error when trying to move members"); sendErrorMessage(pluginData, msg.channel, "Unknown error when trying to move members");
return; return;
} }
sendErrorMessage( sendErrorMessage(pluginData, msg.channel, `Failed to move ${renderUsername(currMember)} (${currMember.id})`);
pluginData,
msg.channel,
`Failed to move ${renderUserUsername(currMember.user)} (${currMember.id})`,
);
errAmt++; errAmt++;
continue; continue;
} }

View file

@ -19,6 +19,8 @@ const PRIVATE_THREAD_ICON =
const FORUM_CHANNEL_ICON = const FORUM_CHANNEL_ICON =
"https://cdn.discordapp.com/attachments/740650744830623756/1091681253364875294/forum-channel-icon.png"; "https://cdn.discordapp.com/attachments/740650744830623756/1091681253364875294/forum-channel-icon.png";
const MEDIA_CHANNEL_ICON = "https://cdn.discordapp.com/attachments/876134205229252658/1178335624940490792/media.png";
export async function getChannelInfoEmbed( export async function getChannelInfoEmbed(
pluginData: GuildPluginData<UtilityPluginType>, pluginData: GuildPluginData<UtilityPluginType>,
channelId: string, channelId: string,
@ -41,6 +43,7 @@ export async function getChannelInfoEmbed(
[ChannelType.PrivateThread]: PRIVATE_THREAD_ICON, [ChannelType.PrivateThread]: PRIVATE_THREAD_ICON,
[ChannelType.AnnouncementThread]: PUBLIC_THREAD_ICON, [ChannelType.AnnouncementThread]: PUBLIC_THREAD_ICON,
[ChannelType.GuildForum]: FORUM_CHANNEL_ICON, [ChannelType.GuildForum]: FORUM_CHANNEL_ICON,
[ChannelType.GuildMedia]: MEDIA_CHANNEL_ICON,
}[channel.type] ?? TEXT_CHANNEL_ICON; }[channel.type] ?? TEXT_CHANNEL_ICON;
const channelType = const channelType =
@ -55,6 +58,7 @@ export async function getChannelInfoEmbed(
[ChannelType.AnnouncementThread]: "News Thread channel", [ChannelType.AnnouncementThread]: "News Thread channel",
[ChannelType.GuildDirectory]: "Hub channel", [ChannelType.GuildDirectory]: "Hub channel",
[ChannelType.GuildForum]: "Forum channel", [ChannelType.GuildForum]: "Forum channel",
[ChannelType.GuildMedia]: "Media channel",
}[channel.type] ?? "Channel"; }[channel.type] ?? "Channel";
embed.author = { embed.author = {

View file

@ -85,7 +85,7 @@ export async function getInviteInfoEmbed(
embed.fields.push({ embed.fields.push({
name: preEmbedPadding + "Invite creator", name: preEmbedPadding + "Invite creator",
value: trimLines(` value: trimLines(`
Name: **${renderUsername(invite.inviter.username, invite.inviter.discriminator)}** Name: **${renderUsername(invite.inviter)}**
ID: \`${invite.inviter.id}\` ID: \`${invite.inviter.id}\`
Mention: <@!${invite.inviter.id}> Mention: <@!${invite.inviter.id}>
`), `),

View file

@ -67,7 +67,7 @@ export async function getMessageInfoEmbed(
embed.fields.push({ embed.fields.push({
name: preEmbedPadding + "Author information", name: preEmbedPadding + "Author information",
value: trimLines(` value: trimLines(`
Name: **${renderUsername(message.author.username, message.author.discriminator)}** Name: **${renderUsername(message.author)}**
ID: \`${message.author.id}\` ID: \`${message.author.id}\`
Created: **<t:${Math.round(message.author.createdTimestamp / 1000)}:R>** Created: **<t:${Math.round(message.author.createdTimestamp / 1000)}:R>**
${authorJoinedAtTS ? `Joined: **<t:${Math.round(authorJoinedAtTS / 1000)}:R>**` : ""} ${authorJoinedAtTS ? `Joined: **<t:${Math.round(authorJoinedAtTS / 1000)}:R>**` : ""}

View file

@ -148,12 +148,16 @@ export async function getServerInfoEmbed(
const textChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildText); const textChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildText);
const voiceChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildVoice); const voiceChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildVoice);
const forumChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildForum); const forumChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildForum);
const mediaChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildMedia);
const threadChannelsText = thisServer.channels.cache.filter( const threadChannelsText = thisServer.channels.cache.filter(
(channel) => channel.isThread() && channel.parent?.type !== ChannelType.GuildForum, (channel) => channel.isThread() && channel.parent?.type !== ChannelType.GuildForum,
); );
const threadChannelsForums = thisServer.channels.cache.filter( const threadChannelsForums = thisServer.channels.cache.filter(
(channel) => channel.isThread() && channel.parent?.type === ChannelType.GuildForum, (channel) => channel.isThread() && channel.parent?.type === ChannelType.GuildForum,
); );
const threadChannelsMedia = thisServer.channels.cache.filter(
(channel) => channel.isThread() && channel.parent?.type === ChannelType.GuildMedia,
);
const announcementChannels = thisServer.channels.cache.filter( const announcementChannels = thisServer.channels.cache.filter(
(channel) => channel.type === ChannelType.GuildAnnouncement, (channel) => channel.type === ChannelType.GuildAnnouncement,
); );
@ -168,6 +172,7 @@ export async function getServerInfoEmbed(
Categories: **${categories.size}** Categories: **${categories.size}**
Text: **${textChannels.size}** (**${threadChannelsText.size} threads**) Text: **${textChannels.size}** (**${threadChannelsText.size} threads**)
Forums: **${forumChannels.size}** (**${threadChannelsForums.size} threads**) Forums: **${forumChannels.size}** (**${threadChannelsForums.size} threads**)
Media: **${mediaChannels.size}** (**${threadChannelsMedia.size} threads**)
Announcement: **${announcementChannels.size}** Announcement: **${announcementChannels.size}**
Voice: **${voiceChannels.size}** Voice: **${voiceChannels.size}**
Stage: **${stageChannels.size}** Stage: **${stageChannels.size}**

View file

@ -39,10 +39,10 @@ export async function getUserInfoEmbed(
}; };
embed.author = { embed.author = {
name: `${user.bot ? "Bot" : "User"}: ${renderUsername(user.username, user.discriminator)}`, name: `${user.bot ? "Bot" : "User"}: ${renderUsername(user)}`,
}; };
const avatarURL = user.displayAvatarURL(); const avatarURL = (member ?? user).displayAvatarURL();
embed.author.icon_url = avatarURL; embed.author.icon_url = avatarURL;
if (compact) { if (compact) {
@ -68,9 +68,8 @@ export async function getUserInfoEmbed(
} }
const userInfoLines = [`ID: \`${user.id}\``, `Username: **${user.username}**`]; const userInfoLines = [`ID: \`${user.id}\``, `Username: **${user.username}**`];
if (user.discriminator !== "0") { if (user.discriminator !== "0") userInfoLines.push(`Discriminator: **${user.discriminator}**`);
userInfoLines.push(`Discriminator: **${user.discriminator}**`); if (user.globalName) userInfoLines.push(`Display Name: **${user.globalName}**`);
}
userInfoLines.push(`Created: **<t:${Math.round(user.createdTimestamp / 1000)}:R>**`); userInfoLines.push(`Created: **<t:${Math.round(user.createdTimestamp / 1000)}:R>**`);
userInfoLines.push(`Mention: <@!${user.id}>`); userInfoLines.push(`Mention: <@!${user.id}>`);

View file

@ -14,15 +14,7 @@ import { ArgsFromSignatureOrArray, GuildPluginData } from "knub";
import moment from "moment-timezone"; import moment from "moment-timezone";
import { RegExpRunner, allowTimeout } from "../../RegExpRunner"; import { RegExpRunner, allowTimeout } from "../../RegExpRunner";
import { getBaseUrl, sendErrorMessage } from "../../pluginUtils"; import { getBaseUrl, sendErrorMessage } from "../../pluginUtils";
import { import { MINUTES, multiSorter, renderUsername, sorter, trimLines } from "../../utils";
InvalidRegexError,
MINUTES,
inputPatternToRegExp,
multiSorter,
renderUserUsername,
sorter,
trimLines,
} from "../../utils";
import { asyncFilter } from "../../utils/async"; import { asyncFilter } from "../../utils/async";
import { hasDiscordPermissions } from "../../utils/hasDiscordPermissions"; import { hasDiscordPermissions } from "../../utils/hasDiscordPermissions";
import { banSearchSignature } from "./commands/BanSearchCmd"; import { banSearchSignature } from "./commands/BanSearchCmd";
@ -388,7 +380,7 @@ async function performMemberSearch(
return true; return true;
} }
const fullUsername = renderUserUsername(member.user); const fullUsername = renderUsername(member);
if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true; if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true;
return false; return false;
@ -455,7 +447,7 @@ async function performBanSearch(
const execRegExp = getOptimizedRegExpRunner(pluginData, isSafeRegex); const execRegExp = getOptimizedRegExpRunner(pluginData, isSafeRegex);
matchingBans = await asyncFilter(matchingBans, async (user) => { matchingBans = await asyncFilter(matchingBans, async (user) => {
const fullUsername = renderUserUsername(user); const fullUsername = renderUsername(user);
if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true; if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true;
return false; return false;
}); });
@ -499,10 +491,10 @@ function formatSearchResultList(members: Array<GuildMember | User>): string {
const paddedId = member.id.padEnd(longestId, " "); const paddedId = member.id.padEnd(longestId, " ");
let line; let line;
if (member instanceof GuildMember) { if (member instanceof GuildMember) {
line = `${paddedId} ${renderUserUsername(member.user)}`; line = `${paddedId} ${renderUsername(member)}`;
if (member.nickname) line += ` (${member.nickname})`; if (member.nickname) line += ` (${member.nickname})`;
} else { } else {
line = `${paddedId} ${member.tag}`; line = `${paddedId} ${renderUsername(member)}`;
} }
return line; return line;
}); });

View file

@ -1120,12 +1120,12 @@ export function resolveUserId(bot: Client, value: string) {
return mentionMatch[1]; return mentionMatch[1];
} }
// A non-mention, full username? // a username
const usernameMatch = value.match(/^@?([^#]+)#(\d{4})$/); const usernameMatch = value.match(/^@?(\S{3,})$/);
if (usernameMatch) { if (usernameMatch) {
const profiler = getProfiler(); const profiler = getProfiler();
const start = performance.now(); const start = performance.now();
const user = bot.users.cache.find((u) => u.username === usernameMatch[1] && u.discriminator === usernameMatch[2]); const user = bot.users.cache.find((u) => u.tag === usernameMatch[1]);
profiler?.addDataPoint("utils:resolveUserId:usernameMatch", performance.now() - start); profiler?.addDataPoint("utils:resolveUserId:usernameMatch", performance.now() - start);
if (user) { if (user) {
return user.id; return user.id;
@ -1501,7 +1501,11 @@ export function isTruthy<T>(value: T): value is Exclude<T, false | null | undefi
export const DBDateFormat = "YYYY-MM-DD HH:mm:ss"; export const DBDateFormat = "YYYY-MM-DD HH:mm:ss";
export function renderUsername(username: string, discriminator: string): string { export function renderUsername(memberOrUser: GuildMember | UnknownUser | User): string;
export function renderUsername(username: string, discriminator: string): string;
export function renderUsername(username: string | User | GuildMember | UnknownUser, discriminator?: string): string {
if (username instanceof GuildMember) return username.user.tag;
if (username instanceof User || username instanceof UnknownUser) return username.tag;
if (discriminator === "0") { if (discriminator === "0") {
return username; return username;
} }

View file

@ -26,7 +26,7 @@ import {
TypedTemplateSafeValueContainer, TypedTemplateSafeValueContainer,
ingestDataIntoTemplateSafeValueContainer, ingestDataIntoTemplateSafeValueContainer,
} from "../templateFormatter"; } from "../templateFormatter";
import { UnknownUser, renderUserUsername } from "../utils"; import { UnknownUser, renderUsername } from "../utils";
type InputProps<T> = Omit< type InputProps<T> = Omit<
{ {
@ -49,9 +49,10 @@ export class TemplateSafeUser extends TemplateSafeValueContainer {
id: Snowflake | string; id: Snowflake | string;
username: string; username: string;
discriminator: string; discriminator: string;
globalName?: string;
mention: string; mention: string;
tag: string; tag: string;
avatarURL?: string; avatarURL: string;
bot?: boolean; bot?: boolean;
createdAt?: number; createdAt?: number;
renderedUsername: string; renderedUsername: string;
@ -91,7 +92,7 @@ export class TemplateSafeMember extends TemplateSafeUser {
nick: string; nick: string;
roles: TemplateSafeRole[]; roles: TemplateSafeRole[];
joinedAt?: number; joinedAt?: number;
// guildAvatarURL: string, Once DJS supports per-server avatars guildAvatarURL: string;
guildName: string; guildName: string;
constructor(data: InputProps<TemplateSafeMember>) { constructor(data: InputProps<TemplateSafeMember>) {
@ -249,7 +250,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
discriminator: "0000", discriminator: "0000",
mention: `<@${user.id}>`, mention: `<@${user.id}>`,
tag: "Unknown#0000", tag: "Unknown#0000",
renderedUsername: renderUserUsername(user), renderedUsername: renderUsername(user),
}); });
} }
@ -257,12 +258,13 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
id: user.id, id: user.id,
username: user.username, username: user.username,
discriminator: user.discriminator, discriminator: user.discriminator,
globalName: user.globalName,
mention: `<@${user.id}>`, mention: `<@${user.id}>`,
tag: user.tag, tag: user.tag,
avatarURL: user.displayAvatarURL?.(), avatarURL: user.displayAvatarURL(),
bot: user.bot, bot: user.bot,
createdAt: user.createdTimestamp, createdAt: user.createdTimestamp,
renderedUsername: renderUserUsername(user), renderedUsername: renderUsername(user),
}); });
} }
@ -285,6 +287,7 @@ export function memberToTemplateSafeMember(member: GuildMember | PartialGuildMem
nick: member.nickname ?? "*None*", nick: member.nickname ?? "*None*",
roles: [...member.roles.cache.mapValues((r) => roleToTemplateSafeRole(r)).values()], roles: [...member.roles.cache.mapValues((r) => roleToTemplateSafeRole(r)).values()],
joinedAt: member.joinedTimestamp ?? undefined, joinedAt: member.joinedTimestamp ?? undefined,
guildAvatarURL: member.displayAvatarURL(),
guildName: member.guild.name, guildName: member.guild.name,
}); });
} }