util.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { GuildMember, User } from "discord.js";
  2. import { getRepository, In } from "typeorm";
  3. import { KnownUser } from "@shared/db/entity/KnownUser";
  4. import humanizeDuration from "humanize-duration";
  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 | null): 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 | User | 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. if (member instanceof GuildMember) {
  38. const role = await repo.findOne({
  39. select: ["userID"],
  40. where: {
  41. userID: In(member.roles.cache.keyArray()),
  42. canModerate: true
  43. }
  44. });
  45. if (role)
  46. return true;
  47. }
  48. return false;
  49. }
  50. export function compareNumbers<T>(prop: (o: T) => number) {
  51. return (a: T, b: T): -1 | 0 | 1 => {
  52. const ap = prop(a);
  53. const bp = prop(b);
  54. if (ap < bp)
  55. return 1;
  56. else if (ap > bp)
  57. return -1;
  58. return 0;
  59. };
  60. }
  61. export type Dict<TVal> = { [key: string]: TVal };
  62. export function getNumberEnums<E>(e : Record<keyof E, number>) : number[] {
  63. return Object.keys(e).filter(k => typeof e[k as keyof E] === "number").map(k => e[k as keyof E]);
  64. }
  65. export function formatString(str: string, vars: Record<string, string>): string {
  66. return Object.keys(vars).filter(s => Object.prototype.hasOwnProperty.call(vars, s)).reduce((s, cur) => s.replace(`{${cur}}`, vars[cur]), str);
  67. }
  68. export function parseArgs(str: string): string[] {
  69. const result: string[] = [];
  70. let quoteMode = false;
  71. let escapeNext = false;
  72. let buffer = "";
  73. for (const char of str) {
  74. if (!escapeNext)
  75. if (char == "\"") {
  76. if (!quoteMode) {
  77. quoteMode = true;
  78. } else {
  79. quoteMode = false;
  80. result.push(buffer);
  81. buffer = "";
  82. }
  83. continue;
  84. } else if (char == "\\") {
  85. escapeNext = true;
  86. continue;
  87. } else if (/\s/.test(char)) {
  88. if (buffer.length == 0)
  89. continue;
  90. if (!quoteMode) {
  91. result.push(buffer);
  92. buffer = "";
  93. continue;
  94. }
  95. }
  96. buffer += char;
  97. escapeNext = false;
  98. }
  99. if (buffer.length != 0)
  100. result.push(buffer);
  101. return result;
  102. }
  103. export const UNIT_MEASURES: humanizeDuration.UnitMeasuresOptions = {
  104. ms: 1,
  105. s: 1000,
  106. m: 60 * 1000,
  107. h: 60 * 60 * 1000,
  108. d: 24 * 60 * 60 * 1000,
  109. w: 7 * 24 * 60 * 60 * 1000,
  110. mo: 30 * 24 * 60 * 60 * 1000,
  111. y: 365 * 24 * 60 * 60 * 1000
  112. };
  113. const durationUnits = UNIT_MEASURES as Record<string, number>;
  114. const durationPattern = new RegExp(`(\\d+(?:[.,]?\\d+)?)\\s*(${Object.keys(durationUnits).sort((a, b) => b.length - a.length).join("|")})`, "g");
  115. export function parseDuration(s: string): number | undefined {
  116. if (!s)
  117. return undefined;
  118. s = s.trim();
  119. let buffer = s;
  120. let result = 0;
  121. let match;
  122. while ((match = durationPattern.exec(s))) {
  123. buffer = buffer.replace(match[0], "").trim();
  124. result += +match[1] * durationUnits[match[2]];
  125. }
  126. if (buffer.length != 0)
  127. return undefined;
  128. return result;
  129. }