diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1ef824e..2cf00f9 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -640,6 +640,75 @@ paths: error: type: string example: no comment found with the provided id + /novels/{slug}/report: + post: + summary: Report a novel + description: Replort a novel that violates the terms and condition of the house + requestBody: + content: + application/json: + schema: + type: object + properties: + type: + type: string + body: + type: string + parameters: + - name: slug + in: path + required: true + schema: + type: string + responses: + 201: + description: succesfully reported an article + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: report was created successfully + 400: + description: bad request + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + field: + type: string + example: body + message: + type: string + example: body cannot be empty + 401: + description: unauthorized access + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: invalid token + 404: + description: entity not found + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: novel not found '/profiles': patch: tags: diff --git a/src/controllers/ReportController.js b/src/controllers/ReportController.js new file mode 100644 index 0000000..b8325c1 --- /dev/null +++ b/src/controllers/ReportController.js @@ -0,0 +1,69 @@ +import Sequelize from 'sequelize'; +import services from '../services'; +import models from '../database/models'; +import helpers from '../helpers'; + +const { Op } = Sequelize; + +const { reportHelper: { checkForBadWords }, responseMessage } = helpers; + +const { Report } = models; + +const { novelServices: { findNovel } } = services; + +const createReport = async (req, res) => { + const { slug } = req.params; + const { type, body } = req.body; + const { user: { id: userId } } = req; + let isConfirmed = false; + + try { + const novel = await findNovel(slug); + if (!novel) { + return responseMessage(res, 404, { error: 'novel not found' }); + } + const { body: novelBody, id: novelId } = novel; + if (type === 'badWords') { + isConfirmed = checkForBadWords(novelBody); + } + Report.create({ + type, body, userId, novelId, isConfirmed + }); + return responseMessage(res, 201, { message: 'report was created successfully' }); + } catch (error) { + responseMessage(res, 500, { error: error.message }); + } +}; + +const getReports = async (req, res) => { + const { isHandled } = req.query; + const reportCondition = isHandled ? { isHandled } : { id: { [Op.ne]: null } }; + try { + const reports = await Report.findAll({ where: reportCondition }); + responseMessage(res, 200, { data: reports }); + } catch (error) { + responseMessage(res, 500, { error: error.message }); + } +}; + +const markAsHandled = async (req, res) => { + const { id } = req.params; + try { + const report = await Report.findByPk(id); + if (!report) { + return responseMessage(res, 400, { error: 'report don\'t exist' }); + } + Report.update({ isHandled: true }, { + where: { id } + }); + return responseMessage(res, 200, { message: 'report was mark as Handled successfully' }); + } catch (error) { + responseMessage(res, 500, { error: error.message }); + } +}; + +export default { + createReport, + getReports, + markAsHandled +}; diff --git a/src/database/migrations/20190814223425-create-report.js b/src/database/migrations/20190814223425-create-report.js new file mode 100644 index 0000000..d71f9ae --- /dev/null +++ b/src/database/migrations/20190814223425-create-report.js @@ -0,0 +1,50 @@ + + +export const up = (queryInterface, Sequelize) => queryInterface.createTable('Reports', { + id: { + allowNull: false, + primaryKey: true, + type: Sequelize.UUID, + }, + type: { + type: Sequelize.STRING + }, + body: { + type: Sequelize.STRING + }, + userId: { + type: Sequelize.UUID, + onDelete: 'CASCADE', + allowNull: false, + references: { + model: 'Users', + key: 'id' + }, + }, + novelId: { + type: Sequelize.UUID, + onDelete: 'CASCADE', + allowNull: false, + references: { + model: 'Novels', + key: 'id' + }, + }, + isConfirmed: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + isHandled: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } +}); +export const down = queryInterface => queryInterface.dropTable('Reports'); diff --git a/src/database/migrations/20190814224806-add-column-to-novel.js b/src/database/migrations/20190814224806-add-column-to-novel.js new file mode 100644 index 0000000..231a13f --- /dev/null +++ b/src/database/migrations/20190814224806-add-column-to-novel.js @@ -0,0 +1,13 @@ +export const up = (queryInterface, Sequelize) => queryInterface.addColumn( + 'Novels', + 'isBanned', + { + type: Sequelize.BOOLEAN, + defaultValue: false + } +); + +export const down = queryInterface => queryInterface.removeColumn( + 'Novels', + 'isBanned', +); diff --git a/src/database/models/novel.js b/src/database/models/novel.js index 4fefe49..f1b6660 100644 --- a/src/database/models/novel.js +++ b/src/database/models/novel.js @@ -32,6 +32,11 @@ export default (Sequelize, DataTypes) => { allowNull: false, type: DataTypes.TEXT }, + isBanned: { + allowNull: false, + type: DataTypes.BOOLEAN, + defaultValue: false + }, createdAt: { allowNull: false, type: DataTypes.DATE diff --git a/src/database/models/report.js b/src/database/models/report.js new file mode 100644 index 0000000..da9268a --- /dev/null +++ b/src/database/models/report.js @@ -0,0 +1,35 @@ +export default (sequelize, DataTypes) => { + const Report = sequelize.define('Report', { + id: { + allowNull: false, + primaryKey: true, + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + }, + userId: { + type: DataTypes.UUID, + onDelete: 'CASCADE', + allowNull: false + }, + novelId: { + type: DataTypes.UUID, + onDelete: 'CASCADE', + allowNull: false + }, + type: DataTypes.STRING, + body: DataTypes.STRING, + isConfirmed: DataTypes.BOOLEAN, + isHandled: DataTypes.BOOLEAN + }, {}); + Report.associate = (models) => { + Report.belongsTo(models.User, { + foreignKey: 'userId', + onDelete: 'CASCADE', + }); + Report.belongsTo(models.Novel, { + foreignKey: 'novelId', + onDelete: 'CASCADE', + }); + }; + return Report; +}; diff --git a/src/database/seeders/20190724090406-user.js b/src/database/seeders/20190724090406-user.js index 46061d0..0d145ac 100644 --- a/src/database/seeders/20190724090406-user.js +++ b/src/database/seeders/20190724090406-user.js @@ -11,7 +11,7 @@ export const up = queryInterface => queryInterface.bulkInsert('Users', [{ phoneNo: null, isVerified: true, isSubscribed: true, - roleId: 'f2dec928-1ff9-421a-b77e-8998c8e2e720', + roleId: '2c4dfb3f-1798-43d4-8eb6-1c125994a263', createdAt: new Date(), updatedAt: new Date() }, diff --git a/src/database/seeders/20190815133001-report.js b/src/database/seeders/20190815133001-report.js new file mode 100644 index 0000000..f9127db --- /dev/null +++ b/src/database/seeders/20190815133001-report.js @@ -0,0 +1,12 @@ +export const up = queryInterface => queryInterface.bulkInsert('Reports', [{ + id: '67a68419-405a-45e6-8d4f-cb00cbff7a64', + userId: '122a0d86-8b78-4bb8-b28f-8e5f7811c456', + novelId: '7f45df6d-7003-424f-86ec-1e2b36e2fd14', + type: 'general', + body: 'i hate this novel', + createdAt: new Date(), + updatedAt: new Date() +}, +], {}); + +export const down = queryInterface => queryInterface.bulkDelete('Reports', null, {}); diff --git a/src/helpers/badWords.js b/src/helpers/badWords.js new file mode 100644 index 0000000..d3c2f04 --- /dev/null +++ b/src/helpers/badWords.js @@ -0,0 +1,453 @@ +export default [ + '4r5e', + '5h1t', + '5hit', + 'a55', + 'anal', + 'anus', + 'ar5e', + 'arrse', + 'arse', + 'ass', + 'ass-fucker', + 'asses', + 'assfucker', + 'assfukka', + 'asshole', + 'assholes', + 'asswhole', + 'a_s_s', + 'b!tch', + 'b00bs', + 'b17ch', + 'b1tch', + 'ballbag', + 'balls', + 'ballsack', + 'bastard', + 'beastial', + 'beastiality', + 'bellend', + 'bestial', + 'bestiality', + 'bi+ch', + 'biatch', + 'bitch', + 'bitcher', + 'bitchers', + 'bitches', + 'bitchin', + 'bitching', + 'bloody', + 'blow job', + 'blowjob', + 'blowjobs', + 'boiolas', + 'bollock', + 'bollok', + 'boner', + 'boob', + 'boobs', + 'booobs', + 'boooobs', + 'booooobs', + 'booooooobs', + 'breasts', + 'buceta', + 'bugger', + 'bum', + 'bunny fucker', + 'butt', + 'butthole', + 'buttmuch', + 'buttplug', + 'c0ck', + 'c0cksucker', + 'carpet muncher', + 'cawk', + 'chink', + 'cipa', + 'cl1t', + 'clit', + 'clitoris', + 'clits', + 'cnut', + 'cock', + 'cock-sucker', + 'cockface', + 'cockhead', + 'cockmunch', + 'cockmuncher', + 'cocks', + 'cocksuck', + 'cocksucked', + 'cocksucker', + 'cocksucking', + 'cocksucks', + 'cocksuka', + 'cocksukka', + 'cok', + 'cokmuncher', + 'coksucka', + 'coon', + 'cox', + 'crap', + 'cum', + 'cummer', + 'cumming', + 'cums', + 'cumshot', + 'cunilingus', + 'cunillingus', + 'cunnilingus', + 'cunt', + 'cuntlick', + 'cuntlicker', + 'cuntlicking', + 'cunts', + 'cyalis', + 'cyberfuc', + 'cyberfuck', + 'cyberfucked', + 'cyberfucker', + 'cyberfuckers', + 'cyberfucking', + 'd1ck', + 'damn', + 'dick', + 'dickhead', + 'dildo', + 'dildos', + 'dink', + 'dinks', + 'dirsa', + 'dlck', + 'dog-fucker', + 'doggin', + 'dogging', + 'donkeyribber', + 'doosh', + 'duche', + 'dyke', + 'ejaculate', + 'ejaculated', + 'ejaculates', + 'ejaculating', + 'ejaculatings', + 'ejaculation', + 'ejakulate', + 'fuck', + 'f u c k', + 'f u c k e r', + 'f4nny', + 'fag', + 'fagging', + 'faggitt', + 'faggot', + 'faggs', + 'fagot', + 'fagots', + 'fags', + 'fanny', + 'fannyflaps', + 'fannyfucker', + 'fanyy', + 'fatass', + 'fcuk', + 'fcuker', + 'fcuking', + 'feck', + 'fecker', + 'felching', + 'fellate', + 'fellatio', + 'fingerfuck', + 'fingerfucked', + 'fingerfucker', + 'fingerfuckers', + 'fingerfucking', + 'fingerfucks', + 'fistfuck', + 'fistfucked', + 'fistfucker', + 'fistfuckers', + 'fistfucking', + 'fistfuckings', + 'fistfucks', + 'flange', + 'fook', + 'fooker', + 'fuck', + 'fucka', + 'fucked', + 'fucker', + 'fuckers', + 'fuckhead', + 'fuckheads', + 'fuckin', + 'fucking', + 'fuckings', + 'fuckingshitmotherfucker', + 'fuckme', + 'fucks', + 'fuckwhit', + 'fuckwit', + 'fudge packer', + 'fudgepacker', + 'fuk', + 'fuker', + 'fukker', + 'fukkin', + 'fuks', + 'fukwhit', + 'fukwit', + 'fux', + 'fux0r', + 'f_u_c_k', + 'gangbang', + 'gangbanged', + 'gangbangs', + 'gaylord', + 'gaysex', + 'goatse', + 'God', + 'god-dam', + 'god-damned', + 'goddamn', + 'goddamned', + 'hardcoresex', + 'hell', + 'heshe', + 'hoar', + 'hoare', + 'hoer', + 'homo', + 'hore', + 'horniest', + 'horny', + 'hotsex', + 'jack-off', + 'jackoff', + 'jap', + 'jerk-off', + 'jism', + 'jiz', + 'jizm', + 'jizz', + 'kawk', + 'knob', + 'knobead', + 'knobed', + 'knobend', + 'knobhead', + 'knobjocky', + 'knobjokey', + 'kock', + 'kondum', + 'kondums', + 'kum', + 'kummer', + 'kumming', + 'kums', + 'kunilingus', + 'l3i+ch', + 'l3itch', + 'labia', + 'lust', + 'lusting', + 'm0f0', + 'm0fo', + 'm45terbate', + 'ma5terb8', + 'ma5terbate', + 'masochist', + 'master-bate', + 'masterb8', + 'masterbat*', + 'masterbat3', + 'masterbate', + 'masterbation', + 'masterbations', + 'masturbate', + 'mo-fo', + 'mof0', + 'mofo', + 'mothafuck', + 'mothafucka', + 'mothafuckas', + 'mothafuckaz', + 'mothafucked', + 'mothafucker', + 'mothafuckers', + 'mothafuckin', + 'mothafucking', + 'mothafuckings', + 'mothafucks', + 'mother fucker', + 'motherfuck', + 'motherfucked', + 'motherfucker', + 'motherfuckers', + 'motherfuckin', + 'motherfucking', + 'motherfuckings', + 'motherfuckka', + 'motherfucks', + 'muff', + 'mutha', + 'muthafecker', + 'muthafuckker', + 'muther', + 'mutherfucker', + 'n1gga', + 'n1gger', + 'nazi', + 'nigg3r', + 'nigg4h', + 'nigga', + 'niggah', + 'niggas', + 'niggaz', + 'nigger', + 'niggers', + 'nob', + 'nob jokey', + 'nobhead', + 'nobjocky', + 'nobjokey', + 'numbnuts', + 'nutsack', + 'orgasim', + 'orgasims', + 'orgasm', + 'orgasms', + 'p0rn', + 'pawn', + 'pecker', + 'penis', + 'penisfucker', + 'phonesex', + 'phuck', + 'phuk', + 'phuked', + 'phuking', + 'phukked', + 'phukking', + 'phuks', + 'phuq', + 'pigfucker', + 'pimpis', + 'piss', + 'pissed', + 'pisser', + 'pissers', + 'pisses', + 'pissflaps', + 'pissin', + 'pissing', + 'pissoff', + 'poop', + 'porn', + 'porno', + 'pornography', + 'pornos', + 'prick', + 'pricks', + 'pron', + 'pube', + 'pusse', + 'pussi', + 'pussies', + 'pussy', + 'pussys', + 'rectum', + 'retard', + 'rimjaw', + 'rimming', + 's hit', + 's.o.b.', + 'sadist', + 'schlong', + 'screwing', + 'scroat', + 'scrote', + 'scrotum', + 'semen', + 'sex', + 'sh!+', + 'sh!t', + 'sh1t', + 'shag', + 'shagger', + 'shaggin', + 'shagging', + 'shemale', + 'shi+', + 'shit', + 'shitdick', + 'shite', + 'shited', + 'shitey', + 'shitfuck', + 'shitfull', + 'shithead', + 'shiting', + 'shitings', + 'shits', + 'shitted', + 'shitter', + 'shitters', + 'shitting', + 'shittings', + 'shitty', + 'skank', + 'slut', + 'sluts', + 'smegma', + 'smut', + 'snatch', + 'son-of-a-bitch', + 'spac', + 'spunk', + 's_h_i_t', + 't1tt1e5', + 't1tties', + 'teets', + 'teez', + 'testical', + 'testicle', + 'tit', + 'titfuck', + 'tits', + 'titt', + 'tittie5', + 'tittiefucker', + 'titties', + 'tittyfuck', + 'tittywank', + 'titwank', + 'tosser', + 'turd', + 'tw4t', + 'twat', + 'twathead', + 'twatty', + 'twunt', + 'twunter', + 'v14gra', + 'v1gra', + 'vagina', + 'viagra', + 'vulva', + 'w00se', + 'wang', + 'wank', + 'wanker', + 'wanky', + 'whoar', + 'whore', + 'willies', + 'willy', + 'xrated', + 'xxx' +]; diff --git a/src/helpers/index.js b/src/helpers/index.js index d23ff23..e9ba0d5 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -7,6 +7,7 @@ import validators from './validator'; import verifyUser from './verifyUser'; import extractNovels from './extractNovels'; import notificationConfig from './notificationConfig'; +import reportHelper from './reportHelper'; const { forgotPasswordMessage, emailNotificationMessage } = emailMessages; @@ -21,5 +22,6 @@ export default { verifyUser, extractNovels, emailNotificationMessage, - notificationConfig + notificationConfig, + reportHelper }; diff --git a/src/helpers/reportHelper.js b/src/helpers/reportHelper.js new file mode 100644 index 0000000..a6a0dff --- /dev/null +++ b/src/helpers/reportHelper.js @@ -0,0 +1,14 @@ +import badWords from './badWords'; + +const checkForBadWords = (novelBody) => { + const isBadWordPresent = badWords.some((badWord) => { + const regex = new RegExp(`\\b${badWord}\\b`, 'i'); + const result = regex.test(novelBody); + return result === true; + }); + return isBadWordPresent; +}; + +export default { + checkForBadWords +}; diff --git a/src/helpers/validator.js b/src/helpers/validator.js index bac86d1..53c41be 100644 --- a/src/helpers/validator.js +++ b/src/helpers/validator.js @@ -86,10 +86,11 @@ const isValidAvatarUrl = () => check('avatarUrl') */ const isNotEmpty = field => check(field) .trim() + .exists() + .withMessage(`${field} is a required field`) .not() .isEmpty() - .exists() - .withMessage(`${field} is a required field`); + .withMessage(`${field} cannot be empty`); /** * @returns {Object} - Express-validator @@ -153,6 +154,15 @@ const isValidInt = field => check(field) .withMessage(`${field} cannot be empty`) .isInt() .withMessage(`${field} must be an integer`); +const isNotTypeOfReport = () => check('type') + .trim() + .isIn(['badWords', 'general']) + .withMessage('type must be badWords or general'); + +const isBoolean = field => check(field) + .isBoolean() + .optional() + .withMessage('isHandled must be a boolean ( true or false )'); export default { isValidEmail, @@ -166,5 +176,7 @@ export default { isValidProfileName, isValidProfilePassword, isValidAvatarUrl, - isValidInt + isValidInt, + isNotTypeOfReport, + isBoolean }; diff --git a/src/middlewares/index.js b/src/middlewares/index.js index 84628b0..f02a43d 100644 --- a/src/middlewares/index.js +++ b/src/middlewares/index.js @@ -4,6 +4,8 @@ import novelValidator from './novelValidator'; import commentValidator from './commentValidator'; import verifyToken from './verifyToken'; import authorizeUser from './authorizeUser'; +import reportValidator from './reportValidator'; + export default { errorHandler, @@ -11,5 +13,6 @@ export default { novelValidator, commentValidator, verifyToken, - authorizeUser + authorizeUser, + reportValidator }; diff --git a/src/middlewares/reportValidator.js b/src/middlewares/reportValidator.js new file mode 100644 index 0000000..27c8bce --- /dev/null +++ b/src/middlewares/reportValidator.js @@ -0,0 +1,28 @@ +import validator from '../helpers/validator'; +import errorHandler from './errorHandler'; + +const { + isNotEmpty, isNotEmptySlug, isNotTypeOfReport, isBoolean, isValidUUID +} = validator; + +const { validatorError } = errorHandler; + +const reportValidator = { + createReport: [ + isNotEmpty('type'), + isNotTypeOfReport(), + isNotEmpty('body'), + isNotEmptySlug(), + validatorError + ], + getReport: [ + isBoolean('isHandled'), + validatorError + ], + markAsHandled: [ + isValidUUID('id'), + validatorError + ] +}; + +export default reportValidator; diff --git a/src/routes/index.js b/src/routes/index.js index c9ae92e..af7911c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,9 +4,10 @@ import auth from './auth'; import novel from './novel'; import comment from './comment'; import notification from './notification'; +import report from './report'; const router = express.Router(); -router.use('/', user, auth, novel, comment, notification); +router.use('/', user, auth, novel, comment, notification, report); export default router; diff --git a/src/routes/report.js b/src/routes/report.js new file mode 100644 index 0000000..8587004 --- /dev/null +++ b/src/routes/report.js @@ -0,0 +1,21 @@ +import express from 'express'; +import middlewares from '../middlewares'; +import reportController from '../controllers/ReportController'; + +const { createReport, getReports, markAsHandled } = reportController; + +const { verifyToken, reportValidator, authorizeUser } = middlewares; +const validate = reportValidator.createReport; +const validateGetReport = reportValidator.getReport; +const validateMarkAsRead = reportValidator.markAsHandled; + +const router = express.Router(); + +const adminRoles = ['admin', 'superadmin']; + + +router.post('/novels/:slug/report', verifyToken, validate, createReport); +router.get('/report', verifyToken, validateGetReport, authorizeUser(adminRoles), getReports); +router.patch('/report/:id', verifyToken, validateMarkAsRead, authorizeUser(adminRoles), markAsHandled); + +export default router; diff --git a/tests/mockData/index.js b/tests/mockData/index.js index 507d8f7..d274188 100644 --- a/tests/mockData/index.js +++ b/tests/mockData/index.js @@ -1,9 +1,11 @@ import userMock from './userMock'; import novelMock from './novelMock'; import commentMock from './commentMock'; +import reportMock from './reportMock'; export default { userMock, novelMock, - commentMock + commentMock, + reportMock }; diff --git a/tests/mockData/reportMock.js b/tests/mockData/reportMock.js new file mode 100644 index 0000000..e25b9c1 --- /dev/null +++ b/tests/mockData/reportMock.js @@ -0,0 +1,20 @@ +const reportMock = { + validReport: { + type: 'general', + body: 'This novel is very bad, it criticizes my faith', + }, + invalidReport: { + typ: 'general', + body: 'This novel is very bad, it criticizes my faith', + }, + invalidType: { + type: 'oh', + body: 'This novel is very bad, it criticizes my faith', + }, + validReportBadWords: { + type: 'badWords', + body: 'This novel is very bad, it criticizes my faith', + } +}; + +export default reportMock; diff --git a/tests/report.spec.js b/tests/report.spec.js new file mode 100644 index 0000000..e6a9b27 --- /dev/null +++ b/tests/report.spec.js @@ -0,0 +1,191 @@ +import chai from 'chai'; +import chaiHttp from 'chai-http'; +import sinon from 'sinon'; +import server from '../src/index'; +import mockData from './mockData'; +import models from '../src/database/models'; + +chai.use(chaiHttp); + +const { expect } = chai; +const { userMock, reportMock } = mockData; +const { Novel, Report } = models; + +let authToken; + +const endpointUser = '/api/v1/users/login'; +const endpointReport = '/api/v1/novels/hancock/report'; +const invalidReportEnpoint = '/api/v1/novels/invalid/report'; +const getAllReportUrl = '/api/v1/report'; +const getAllHandledReportUrl = '/api/v1/report?isHandled=true'; +const markReportAsHandledUrl = '/api/v1/report/67a68419-405a-45e6-8d4f-cb00cbff7a64'; +const invalidMarkReportAsHandledUrl = '/api/v1/report/2cec37fd-feeb-4b01-9bfe-14e81d578e18'; +const invalidUUID = '/api/v1/report/2cec37fd-feeb-4b01-9bfe-14e81d578k'; + +describe('testing report route', () => { + it('should get users token', (done) => { + const user = userMock.seededUser1; + chai.request(server) + .post(endpointUser) + .send(user) + .end((err, res) => { + expect(res.body.user).to.have.property('token'); + authToken = res.body.user.token; + done(); + }); + }); + it('should return a message of successful report', (done) => { + chai.request(server) + .post(endpointReport) + .send(reportMock.validReport) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(201); + expect(res.body).to.have.property('message'); + done(); + }); + }); + it('should return a message of successful report and check for bad words', (done) => { + chai.request(server) + .post(endpointReport) + .send(reportMock.validReportBadWords) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(201); + expect(res.body).to.have.property('message'); + done(); + }); + }); + it('should return an error on wrong input', (done) => { + chai.request(server) + .post(endpointReport) + .send(reportMock.invalidReport) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(400); + expect(res.body).to.have.property('errors'); + done(); + }); + }); + it('should return an error on wrong input type', (done) => { + chai.request(server) + .post(endpointReport) + .send(reportMock.invalidType) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(400); + expect(res.body).to.have.property('errors'); + done(); + }); + }); +}); + +describe('test for reporting non existing novel', () => { + it('should return status 404', (done) => { + chai.request(server) + .post(invalidReportEnpoint) + .send(reportMock.validReport) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(404); + expect(res.body).to.have.property('error'); + done(); + }); + }); +}); +describe('test for getting reports', () => { + it('should return all report', (done) => { + chai.request(server) + .get(getAllReportUrl) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(200); + expect(res.body).to.have.property('data'); + done(); + }); + }); + it('should return all handled report', (done) => { + chai.request(server) + .get(getAllHandledReportUrl) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(200); + expect(res.body).to.have.property('data'); + done(); + }); + }); +}); +describe('test for marking report as handled', () => { + it('should return a success message', (done) => { + chai.request(server) + .patch(markReportAsHandledUrl) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(200); + expect(res.body).to.have.property('message'); + done(); + }); + }); + it('should return an error for wrong params', (done) => { + chai.request(server) + .patch(invalidMarkReportAsHandledUrl) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(400); + expect(res.body).to.have.property('error'); + done(); + }); + }); + it('should return an error for invalid UUID', (done) => { + chai.request(server) + .patch(invalidUUID) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(400); + expect(res.body).to.have.property('errors'); + done(); + }); + }); +}); +describe('test for handling 500 errors', () => { + it('should return a success message', (done) => { + const stub = sinon.stub(Novel, 'findOne'); + stub.throws(new Error('error occured!')); + + chai.request(server) + .post(endpointReport) + .send(reportMock.validReport) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(500); + stub.restore(); + done(); + }); + }); + it('should return an error 500 when trying to get all report', (done) => { + const stub = sinon.stub(Report, 'findAll'); + stub.throws(new Error('error occured!')); + + chai.request(server) + .get(getAllReportUrl) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(500); + stub.restore(); + done(); + }); + }); + it('should return an error 500 when trying to get all report', (done) => { + const stub = sinon.stub(Report, 'update'); + stub.throws(new Error('error occured!')); + + chai.request(server) + .patch(markReportAsHandledUrl) + .set('authorization', authToken) + .end((err, res) => { + expect(res).to.have.status(500); + stub.restore(); + done(); + }); + }); +}); diff --git a/tests/user.spec.js b/tests/user.spec.js index 299e413..0d396d2 100644 --- a/tests/user.spec.js +++ b/tests/user.spec.js @@ -223,7 +223,7 @@ describe('Test for getting users', () => { .get(endpointUser) .end((err, res) => { expect(res).to.have.status(401); - expect(res.body.error).to.equal('no token provided'); + expect(res.body.error).to.equal('you have to be signed in to continue'); done(); }); });