punishments.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import async from "async";
  2. import mongoose from "mongoose";
  3. import CoreClass from "../core";
  4. class PunishmentsModule extends CoreClass {
  5. // eslint-disable-next-line require-jsdoc
  6. constructor() {
  7. super("punishments");
  8. }
  9. /**
  10. * Initialises the punishments module
  11. *
  12. * @returns {Promise} - returns promise (reject, resolve)
  13. */
  14. async initialize() {
  15. this.setStage(1);
  16. this.cache = this.moduleManager.modules.cache;
  17. this.db = this.moduleManager.modules.db;
  18. this.io = this.moduleManager.modules.io;
  19. this.utils = this.moduleManager.modules.utils;
  20. const punishmentModel = await this.db.runJob("GET_MODEL", { modelName: "punishment" });
  21. const punishmentSchema = await this.db.runJob("GET_SCHEMA", { schemaName: "punishment" });
  22. return new Promise((resolve, reject) =>
  23. async.waterfall(
  24. [
  25. next => {
  26. this.setStage(2);
  27. this.cache
  28. .runJob("HGETALL", { table: "punishments" })
  29. .then(punishments => {
  30. next(null, punishments);
  31. })
  32. .catch(next);
  33. },
  34. (punishments, next) => {
  35. this.setStage(3);
  36. if (!punishments) return next();
  37. const punishmentIds = Object.keys(punishments);
  38. return async.each(
  39. punishmentIds,
  40. (punishmentId, cb) => {
  41. punishmentModel.findOne({ _id: punishmentId }, (err, punishment) => {
  42. if (err) next(err);
  43. else if (!punishment)
  44. this.cache
  45. .runJob("HDEL", {
  46. table: "punishments",
  47. key: punishmentId
  48. })
  49. .then(() => {
  50. cb();
  51. })
  52. .catch(next);
  53. else cb();
  54. });
  55. },
  56. next
  57. );
  58. },
  59. next => {
  60. this.setStage(4);
  61. punishmentModel.find({}, next);
  62. },
  63. (punishments, next) => {
  64. this.setStage(5);
  65. async.each(
  66. punishments,
  67. (punishment, next) => {
  68. if (punishment.active === false || punishment.expiresAt < Date.now()) return next();
  69. return this.cache
  70. .runJob("HSET", {
  71. table: "punishments",
  72. key: punishment._id,
  73. value: punishmentSchema(punishment, punishment._id)
  74. })
  75. .then(() => next())
  76. .catch(next);
  77. },
  78. next
  79. );
  80. }
  81. ],
  82. async err => {
  83. if (err) {
  84. const formattedErr = await this.utils.runJob("GET_ERROR", { error: err });
  85. reject(new Error(formattedErr));
  86. } else resolve();
  87. }
  88. )
  89. );
  90. }
  91. /**
  92. * Gets all punishments in the cache that are active, and removes those that have expired
  93. *
  94. * @returns {Promise} - returns promise (reject, resolve)
  95. */
  96. GET_PUNISHMENTS() {
  97. return new Promise((resolve, reject) => {
  98. const punishmentsToRemove = [];
  99. async.waterfall(
  100. [
  101. next => {
  102. this.cache
  103. .runJob("HGETALL", { table: "punishments" })
  104. .then(punishmentsObj => next(null, punishmentsObj))
  105. .catch(next);
  106. },
  107. (punishments, next) => {
  108. let filteredPunishments = [];
  109. for (
  110. let id = 0, punishmentKeys = Object.keys(punishments);
  111. id < punishmentKeys.length;
  112. id += 1
  113. ) {
  114. const punishment = punishments[id];
  115. punishment.punishmentId = id;
  116. punishments.push(punishment);
  117. }
  118. filteredPunishments = punishments.filter(punishment => {
  119. if (punishment.expiresAt < Date.now()) punishmentsToRemove.push(punishment);
  120. return punishment.expiresAt > Date.now();
  121. });
  122. next(null, filteredPunishments);
  123. },
  124. (punishments, next) => {
  125. async.each(
  126. punishmentsToRemove,
  127. (punishment, next2) => {
  128. this.cache
  129. .runJob("HDEL", {
  130. table: "punishments",
  131. key: punishment.punishmentId
  132. })
  133. .finally(() => next2());
  134. },
  135. () => {
  136. next(null, punishments);
  137. }
  138. );
  139. }
  140. ],
  141. (err, punishments) => {
  142. if (err && err !== true) return reject(new Error(err));
  143. return resolve(punishments);
  144. }
  145. );
  146. });
  147. }
  148. /**
  149. * Gets a punishment by id
  150. *
  151. * @param {object} payload - object containing the payload
  152. * @param {string} payload.id - the id of the punishment we are trying to get
  153. * @returns {Promise} - returns promise (reject, resolve)
  154. */
  155. GET_PUNISHMENT(payload) {
  156. return new Promise((resolve, reject) => {
  157. let punishmentModel;
  158. this.db
  159. .runJob("GET_MODEL", { modelName: "punishment" })
  160. .then(model => {
  161. punishmentModel = model;
  162. })
  163. .catch(console.error);
  164. return async.waterfall(
  165. [
  166. next => {
  167. if (!mongoose.Types.ObjectId.isValid(payload.id)) return next("Id is not a valid ObjectId.");
  168. return this.cache
  169. .runJob("HGET", {
  170. table: "punishments",
  171. key: payload.id
  172. })
  173. .then(punishment => next(null, punishment))
  174. .catch(next);
  175. },
  176. (punishment, next) => {
  177. if (punishment) return next(true, punishment);
  178. return punishmentModel.findOne({ _id: payload.id }, next);
  179. },
  180. (punishment, next) => {
  181. if (punishment) {
  182. this.cache
  183. .runJob("HSET", {
  184. table: "punishments",
  185. key: payload.id,
  186. value: punishment
  187. })
  188. .then(punishment => {
  189. next(null, punishment);
  190. })
  191. .catch(next);
  192. } else next("Punishment not found.");
  193. }
  194. ],
  195. (err, punishment) => {
  196. if (err && err !== true) return reject(new Error(err));
  197. return resolve(punishment);
  198. }
  199. );
  200. });
  201. }
  202. /**
  203. * Gets all punishments from a userId
  204. *
  205. * @param {object} payload - object containing the payload
  206. * @param {string} payload.userId - the userId of the punishment(s) we are trying to get
  207. * @returns {Promise} - returns promise (reject, resolve)
  208. */
  209. GET_PUNISHMENTS_FROM_USER_ID(payload) {
  210. return new Promise((resolve, reject) => {
  211. async.waterfall(
  212. [
  213. next => {
  214. this.runJob("GET_PUNISHMENTS", {})
  215. .then(punishments => {
  216. next(null, punishments);
  217. })
  218. .catch(next);
  219. },
  220. (punishments, next) => {
  221. const filteredPunishments = punishments.filter(
  222. punishment => punishment.type === "banUserId" && punishment.value === payload.userId
  223. );
  224. next(null, filteredPunishments);
  225. }
  226. ],
  227. (err, punishments) => {
  228. if (err && err !== true) return reject(new Error(err));
  229. return resolve(punishments);
  230. }
  231. );
  232. });
  233. }
  234. /**
  235. * Adds a new punishment to the database
  236. *
  237. * @param {object} payload - object containing the payload
  238. * @param {string} payload.reason - the reason for the punishment e.g. spam
  239. * @param {string} payload.type - the type of punishment (enum: ["banUserId", "banUserIp"])
  240. * @param {string} payload.value - the user id/ip address for the ban (depends on punishment type)
  241. * @param {Date} payload.expiresAt - the date at which the punishment expires at
  242. * @param {string} payload.punishedBy - the userId of the who initiated the punishment
  243. * @returns {Promise} - returns promise (reject, resolve)
  244. */
  245. ADD_PUNISHMENT(payload) {
  246. return new Promise((resolve, reject) => {
  247. let PunishmentModel;
  248. let PunishmentSchema;
  249. this.db
  250. .runJob("GET_MODEL", { modelName: "punishment" })
  251. .then(model => {
  252. PunishmentModel = model;
  253. })
  254. .catch(console.error);
  255. this.db
  256. .runJob("GET_SCHEMA", { schemaName: "punishment" })
  257. .then(model => {
  258. PunishmentSchema = model;
  259. })
  260. .catch(console.error);
  261. return async.waterfall(
  262. [
  263. next => {
  264. const punishment = new PunishmentModel({
  265. type: payload.type,
  266. value: payload.value,
  267. reason: payload.reason,
  268. active: true,
  269. expiresAt: payload.expiresAt,
  270. punishedAt: Date.now(),
  271. punishedBy: payload.punishedBy
  272. });
  273. punishment.save((err, punishment) => {
  274. if (err) return next(err);
  275. return next(null, punishment);
  276. });
  277. },
  278. (punishment, next) => {
  279. this.cache
  280. .runJob("HSET", {
  281. table: "punishments",
  282. key: punishment._id,
  283. value: PunishmentSchema(punishment, punishment._id)
  284. })
  285. .then(() => next())
  286. .catch(next);
  287. },
  288. (punishment, next) => {
  289. // DISCORD MESSAGE
  290. next(null, punishment);
  291. }
  292. ],
  293. (err, punishment) => {
  294. if (err) return reject(new Error(err));
  295. return resolve(punishment);
  296. }
  297. );
  298. });
  299. }
  300. }
  301. export default new PunishmentsModule();