reports.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. 'use strict';
  2. const async = require('async');
  3. const db = require('../db');
  4. const cache = require('../cache');
  5. const utils = require('../utils');
  6. const logger = require('../logger');
  7. const hooks = require('./hooks');
  8. const songs = require('../songs');
  9. const reportableIssues = [
  10. {
  11. name: 'Video',
  12. reasons: [
  13. 'Doesn\'t exist',
  14. 'It\'s private',
  15. 'It\'s not available in my country'
  16. ]
  17. },
  18. {
  19. name: 'Title',
  20. reasons: [
  21. 'Incorrect',
  22. 'Inappropriate'
  23. ]
  24. },
  25. {
  26. name: 'Duration',
  27. reasons: [
  28. 'Skips too soon',
  29. 'Skips too late',
  30. 'Starts too soon',
  31. 'Skips too late'
  32. ]
  33. },
  34. {
  35. name: 'Artists',
  36. reasons: [
  37. 'Incorrect',
  38. 'Inappropriate'
  39. ]
  40. },
  41. {
  42. name: 'Thumbnail',
  43. reasons: [
  44. 'Incorrect',
  45. 'Inappropriate',
  46. 'Doesn\'t exist'
  47. ]
  48. }
  49. ];
  50. cache.sub('report.resolve', reportId => {
  51. utils.emitToRoom('admin.reports', 'event:admin.report.resolved', reportId);
  52. });
  53. cache.sub('report.create', report => {
  54. utils.emitToRoom('admin.reports', 'event:admin.report.created', report);
  55. });
  56. module.exports = {
  57. /**
  58. * Gets all reports
  59. *
  60. * @param {Object} session - the session object automatically added by socket.io
  61. * @param {Function} cb - gets called with the result
  62. */
  63. index: hooks.adminRequired((session, cb) => {
  64. async.waterfall([
  65. (next) => {
  66. db.models.report.find({ resolved: false }).sort({ released: 'desc' }).exec(next);
  67. }
  68. ], (err, reports) => {
  69. if (err) {
  70. err = utils.getError(err);
  71. logger.error("REPORTS_INDEX", `Indexing reports failed. "${err}"`);
  72. return cb({ 'status': 'failure', 'message': err});
  73. }
  74. logger.success("REPORTS_INDEX", "Indexing reports successful.");
  75. cb({ status: 'success', data: reports });
  76. });
  77. }),
  78. /**
  79. * Gets a specific report
  80. *
  81. * @param {Object} session - the session object automatically added by socket.io
  82. * @param {String} reportId - the id of the report to return
  83. * @param {Function} cb - gets called with the result
  84. */
  85. findOne: hooks.adminRequired((session, reportId, cb) => {
  86. async.waterfall([
  87. (next) => {
  88. db.models.report.findOne({ _id: reportId }).exec(next);
  89. }
  90. ], (err, report) => {
  91. if (err) {
  92. err = utils.getError(err);
  93. logger.error("REPORTS_FIND_ONE", `Finding report "${reportId}" failed. "${err}"`);
  94. return cb({ 'status': 'failure', 'message': err });
  95. }
  96. logger.success("REPORTS_FIND_ONE", `Finding report "${reportId}" successful.`);
  97. cb({ status: 'success', data: report });
  98. });
  99. }),
  100. /**
  101. * Gets all reports for a songId
  102. *
  103. * @param {Object} session - the session object automatically added by socket.io
  104. * @param {String} songId - the id of the song to index reports for
  105. * @param {Function} cb - gets called with the result
  106. */
  107. getReportsForSong: hooks.adminRequired((session, songId, cb) => {
  108. async.waterfall([
  109. (next) => {
  110. db.models.report.find({ songId, resolved: false }).sort({ released: 'desc' }).exec(next);
  111. },
  112. (reports, next) => {
  113. let data = [];
  114. for (let i = 0; i < reports.length; i++) {
  115. data.push(reports[i]._id);
  116. }
  117. next(null, data);
  118. }
  119. ], (err, data) => {
  120. if (err) {
  121. err = utils.getError(err);
  122. logger.error("GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" failed. "${err}"`);
  123. return cb({ 'status': 'failure', 'message': err});
  124. } else {
  125. logger.success("GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" successful.`);
  126. return cb({ status: 'success', data });
  127. }
  128. });
  129. }),
  130. /**
  131. * Resolves a report
  132. *
  133. * @param {Object} session - the session object automatically added by socket.io
  134. * @param {String} reportId - the id of the report that is getting resolved
  135. * @param {Function} cb - gets called with the result
  136. * @param {String} userId - the userId automatically added by hooks
  137. */
  138. resolve: hooks.adminRequired((session, reportId, cb, userId) => {
  139. async.waterfall([
  140. (next) => {
  141. db.models.report.findOne({ _id: reportId }).exec(next);
  142. },
  143. (report, next) => {
  144. if (!report) return next('Report not found.');
  145. report.resolved = true;
  146. report.save(err => {
  147. if (err) next(err.message);
  148. else next();
  149. });
  150. }
  151. ], (err) => {
  152. if (err) {
  153. err = utils.getError(err);
  154. logger.error("REPORTS_RESOLVE", `Resolving report "${reportId}" failed by user "${userId}". "${err}"`);
  155. return cb({ 'status': 'failure', 'message': err});
  156. } else {
  157. cache.pub('report.resolve', reportId);
  158. logger.success("REPORTS_RESOLVE", `User "${userId}" resolved report "${reportId}".`);
  159. cb({ status: 'success', message: 'Successfully resolved Report' });
  160. }
  161. });
  162. }),
  163. /**
  164. * Creates a new report
  165. *
  166. * @param {Object} session - the session object automatically added by socket.io
  167. * @param {Object} data - the object of the report data
  168. * @param {Function} cb - gets called with the result
  169. * @param {String} userId - the userId automatically added by hooks
  170. */
  171. create: hooks.loginRequired((session, data, cb, userId) => {
  172. async.waterfall([
  173. (next) => {
  174. db.models.song.findOne({ songId: data.songId }).exec(next);
  175. },
  176. (song, next) => {
  177. if (!song) return next('Song not found.');
  178. songs.getSong(song._id, next);
  179. },
  180. (song, next) => {
  181. if (!song) return next('Song not found.');
  182. for (let z = 0; z < data.issues.length; z++) {
  183. if (reportableIssues.filter(issue => { return issue.name == data.issues[z].name; }).length > 0) {
  184. for (let r = 0; r < reportableIssues.length; r++) {
  185. if (reportableIssues[r].reasons.every(reason => data.issues[z].reasons.indexOf(reason) < -1)) {
  186. return cb({ status: 'failure', message: 'Invalid data' });
  187. }
  188. }
  189. } else return cb({ status: 'failure', message: 'Invalid data' });
  190. }
  191. next();
  192. },
  193. (next) => {
  194. let issues = [];
  195. for (let r = 0; r < data.issues.length; r++) {
  196. if (!data.issues[r].reasons.length <= 0) issues.push(data.issues[r]);
  197. }
  198. data.issues = issues;
  199. next();
  200. },
  201. (next) => {
  202. data.createdBy = userId;
  203. data.createdAt = Date.now();
  204. db.models.report.create(data, next);
  205. }
  206. ], (err, report) => {
  207. if (err) {
  208. err = utils.getError(err);
  209. logger.error("REPORTS_CREATE", `Creating report for "${data.songId}" failed by user "${userId}". "${err}"`);
  210. return cb({ 'status': 'failure', 'message': err });
  211. } else {
  212. cache.pub('report.create', report);
  213. logger.success("REPORTS_CREATE", `User "${userId}" created report for "${data.songId}".`);
  214. return cb({ 'status': 'success', 'message': 'Successfully created report' });
  215. }
  216. });
  217. })
  218. };