util.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { GuildMember } from "discord.js";
  2. import { getRepository, In } from "typeorm";
  3. import { KnownUser } from "@shared/db/entity/KnownUser";
  4. import { HTTPError } from "got/dist/source";
  5. const VALID_EXTENSIONS = new Set([
  6. "png",
  7. "jpg",
  8. "jpeg",
  9. "bmp",
  10. ]);
  11. export type EsModuleClass<T> = { prototype: T; new(...params: unknown[]): T; };
  12. export function isModuleClass<T>(obj: unknown) : obj is EsModuleClass<T> {
  13. return Object.prototype.hasOwnProperty.call(obj, "prototype");
  14. }
  15. export function isDevelopment(): boolean {
  16. return process.env.NODE_ENV == "dev";
  17. }
  18. export function isValidImage(fileName?: string): boolean {
  19. if (!fileName)
  20. return false;
  21. const extPosition = fileName.lastIndexOf(".");
  22. if (extPosition < 0)
  23. return false;
  24. const ext = fileName.substring(extPosition + 1).toLowerCase();
  25. return VALID_EXTENSIONS.has(ext);
  26. }
  27. export async function isAuthorisedAsync(member: GuildMember | null | undefined): Promise<boolean> {
  28. if (!member)
  29. return false;
  30. const repo = getRepository(KnownUser);
  31. const user = await repo.findOne({
  32. where: { userID: member.id },
  33. select: ["canModerate"]
  34. });
  35. if (user && user.canModerate)
  36. return true;
  37. const role = await repo.findOne({
  38. select: ["userID"],
  39. where: {
  40. userID: In(member.roles.cache.keyArray()),
  41. canModerate: true
  42. }
  43. });
  44. if (role)
  45. return true;
  46. return false;
  47. }
  48. export function compareNumbers<T>(prop: (o: T) => number) {
  49. return (a: T, b: T): -1 | 0 | 1 => {
  50. const ap = prop(a);
  51. const bp = prop(b);
  52. if (ap < bp)
  53. return 1;
  54. else if (ap > bp)
  55. return -1;
  56. return 0;
  57. };
  58. }
  59. export type Dict<TVal> = { [key: string]: TVal };
  60. export function getNumberEnums<E>(e : Record<keyof E, number>) : number[] {
  61. return Object.keys(e).filter(k => typeof e[k as keyof E] === "number").map(k => e[k as keyof E]);
  62. }
  63. export function formatString(str: string, vars: Record<string, string>): string {
  64. return Object.keys(vars).filter(s => Object.prototype.hasOwnProperty.call(vars, s)).reduce((s, cur) => s.replace(`{${cur}}`, vars[cur]), str);
  65. }
  66. export async function tryDo<TResult>(promise: Promise<TResult>) : Promise<{ok: boolean, result?: TResult, error?: unknown}> {
  67. try {
  68. return {ok: true, result: await promise};
  69. } catch(err) {
  70. return {ok: false, error: err};
  71. }
  72. }
  73. export async function assertOk<T>(promise: Promise<T>): Promise<T> {
  74. try {
  75. return await promise;
  76. } catch (err) {
  77. if (hasStackTrace(err)) {
  78. const trace: {stack?: string} = {};
  79. Error.captureStackTrace(trace);
  80. err.stack = `${err.stack}\nCaused by: ${trace.stack}`;
  81. }
  82. throw err;
  83. }
  84. }
  85. export function isHttpError(err?: unknown): err is HTTPError {
  86. return err && Object.prototype.hasOwnProperty.call(err, "response");
  87. }
  88. export function hasStackTrace(reason?: unknown): reason is {stack: unknown} {
  89. return reason && Object.prototype.hasOwnProperty.call(reason, "stack");
  90. }