punishments.js 9.4 KB

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