'use strict'; const async = require('async'); const db = require('../db'); const cache = require('../cache'); const utils = require('../utils'); const logger = require('../logger'); const hooks = require('./hooks'); const songs = require('../songs'); const reportableIssues = [ { name: 'Video', reasons: [ 'Doesn\'t exist', 'It\'s private', 'It\'s not available in my country' ] }, { name: 'Title', reasons: [ 'Incorrect', 'Inappropriate' ] }, { name: 'Duration', reasons: [ 'Skips too soon', 'Skips too late', 'Starts too soon', 'Skips too late' ] }, { name: 'Artists', reasons: [ 'Incorrect', 'Inappropriate' ] }, { name: 'Thumbnail', reasons: [ 'Incorrect', 'Inappropriate', 'Doesn\'t exist' ] } ]; cache.sub('report.resolve', reportId => { utils.emitToRoom('admin.reports', 'event:admin.report.resolved', reportId); }); cache.sub('report.create', report => { utils.emitToRoom('admin.reports', 'event:admin.report.created', report); }); module.exports = { /** * Gets all reports * * @param {Object} session - the session object automatically added by socket.io * @param {Function} cb - gets called with the result */ index: hooks.adminRequired((session, cb) => { async.waterfall([ (next) => { db.models.report.find({ resolved: false }).sort({ released: 'desc' }).exec(next); } ], (err, reports) => { if (err) { err = utils.getError(err); logger.error("REPORTS_INDEX", `Indexing reports failed. "${err}"`); return cb({ 'status': 'failure', 'message': err}); } logger.success("REPORTS_INDEX", "Indexing reports successful."); cb({ status: 'success', data: reports }); }); }), /** * Gets a specific report * * @param {Object} session - the session object automatically added by socket.io * @param {String} reportId - the id of the report to return * @param {Function} cb - gets called with the result */ findOne: hooks.adminRequired((session, reportId, cb) => { async.waterfall([ (next) => { db.models.report.findOne({ _id: reportId }).exec(next); } ], (err, report) => { if (err) { err = utils.getError(err); logger.error("REPORTS_FIND_ONE", `Finding report "${reportId}" failed. "${err}"`); return cb({ 'status': 'failure', 'message': err }); } logger.success("REPORTS_FIND_ONE", `Finding report "${reportId}" successful.`); cb({ status: 'success', data: report }); }); }), /** * Gets all reports for a songId * * @param {Object} session - the session object automatically added by socket.io * @param {String} songId - the id of the song to index reports for * @param {Function} cb - gets called with the result */ getReportsForSong: hooks.adminRequired((session, songId, cb) => { async.waterfall([ (next) => { db.models.report.find({ songId, resolved: false }).sort({ released: 'desc' }).exec(next); }, (reports, next) => { let data = []; for (let i = 0; i < reports.length; i++) { data.push(reports[i]._id); } next(null, data); } ], (err, data) => { if (err) { err = utils.getError(err); logger.error("GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" failed. "${err}"`); return cb({ 'status': 'failure', 'message': err}); } else { logger.success("GET_REPORTS_FOR_SONG", `Indexing reports for song "${songId}" successful.`); return cb({ status: 'success', data }); } }); }), /** * Resolves a report * * @param {Object} session - the session object automatically added by socket.io * @param {String} reportId - the id of the report that is getting resolved * @param {Function} cb - gets called with the result * @param {String} userId - the userId automatically added by hooks */ resolve: hooks.adminRequired((session, reportId, cb, userId) => { async.waterfall([ (next) => { db.models.report.findOne({ _id: reportId }).exec(next); }, (report, next) => { if (!report) return next('Report not found.'); report.resolved = true; report.save(err => { if (err) next(err.message); else next(); }); } ], (err) => { if (err) { err = utils.getError(err); logger.error("REPORTS_RESOLVE", `Resolving report "${reportId}" failed by user "${userId}". "${err}"`); return cb({ 'status': 'failure', 'message': err}); } else { cache.pub('report.resolve', reportId); logger.success("REPORTS_RESOLVE", `User "${userId}" resolved report "${reportId}".`); cb({ status: 'success', message: 'Successfully resolved Report' }); } }); }), /** * Creates a new report * * @param {Object} session - the session object automatically added by socket.io * @param {Object} data - the object of the report data * @param {Function} cb - gets called with the result * @param {String} userId - the userId automatically added by hooks */ create: hooks.loginRequired((session, data, cb, userId) => { async.waterfall([ (next) => { db.models.song.findOne({ songId: data.songId }).exec(next); }, (song, next) => { if (!song) return next('Song not found.'); songs.getSong(song._id, next); }, (song, next) => { if (!song) return next('Song not found.'); for (let z = 0; z < data.issues.length; z++) { if (reportableIssues.filter(issue => { return issue.name == data.issues[z].name; }).length > 0) { for (let r = 0; r < reportableIssues.length; r++) { if (reportableIssues[r].reasons.every(reason => data.issues[z].reasons.indexOf(reason) < -1)) { return cb({ status: 'failure', message: 'Invalid data' }); } } } else return cb({ status: 'failure', message: 'Invalid data' }); } next(); }, (next) => { let issues = []; for (let r = 0; r < data.issues.length; r++) { if (!data.issues[r].reasons.length <= 0) issues.push(data.issues[r]); } data.issues = issues; next(); }, (next) => { data.createdBy = userId; data.createdAt = Date.now(); db.models.report.create(data, next); } ], (err, report) => { if (err) { err = utils.getError(err); logger.error("REPORTS_CREATE", `Creating report for "${data.songId}" failed by user "${userId}". "${err}"`); return cb({ 'status': 'failure', 'message': err }); } else { cache.pub('report.create', report); logger.success("REPORTS_CREATE", `User "${userId}" created report for "${data.songId}".`); return cb({ 'status': 'success', 'message': 'Successfully created report' }); } }); }) };