Skip to content

Commit

Permalink
feature(highlights): added create highlights endpoint
Browse files Browse the repository at this point in the history
added get single novel with highlights
[Delivers #167165007]
  • Loading branch information
Nerocodes committed Aug 26, 2019
1 parent a67d36d commit 513bd49
Show file tree
Hide file tree
Showing 16 changed files with 504 additions and 35 deletions.
62 changes: 60 additions & 2 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,50 @@ paths:
error:
type: string
example: error occured

/novels/{slug}:
get:
tags:
- Novels
summary: Get novel
description: Get single novel with highlights
security:
- token: []
responses:
200:
description: Request successful
401:
description: Authentication failed
404:
description: Novel not found
500:
description: internal server error
/novels/{slug}/highlight:
post:
tags:
- Highlight
summary: Creates highlight
description: Post highlighted text
requestBody:
description: fields containing novel data
content:
application/json:
schema:
$ref: '#/components/schemas/HighlightInput'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/HighlightInput'
required: true
security:
- token: []
responses:
201:
description: Highlight created successfully
401:
description: Authentication failed
404:
description: Novel not found
500:
description: internal server error
components:
schemas:
token:
Expand Down Expand Up @@ -1297,7 +1340,7 @@ components:
example: There are five steps to thinking big...
genre:
type: string
example: Action
example: action
UserProfileInput:
type: object
properties:
Expand Down Expand Up @@ -1413,6 +1456,21 @@ components:
following:
type: boolean
example: true
HighlightInput:
required:
- startIndex
- endIndex
type: object
properties:
startIndex:
type: integer
example: 1
endIndex:
type: integer
example: 19
comment:
type: string
example: There is a missing exclamation
securitySchemes:
token:
type: apiKey
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

96 changes: 72 additions & 24 deletions src/controllers/novelController.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,35 @@ const {
const { Novel } = models;
const {
novelServices: {
addNovel, findGenre, findNovel, findAllNovels
addNovel, findGenre, findNovel, findAllNovels,
highlightNovelText, getNovelHighlights
},
notificationServices: { addNotification }
} = services;

const { Genre } = models;

/**
* createNovel
*
* @param {object} req
* @param {object} res
* @name createNovel
* @param {object} request
* @param {object} response
* @returns {object} json
*/
const createNovel = async (req, res) => {
const newNovel = req.body;
const createdNovel = await addNovel(newNovel, req.user);
const createNovel = async (request, response) => {
const newNovel = request.body;
const createdNovel = await addNovel(newNovel, request.user);
if (createdNovel.error) {
return errorResponse(res, createdNovel.status, createdNovel.error);
return errorResponse(response, createdNovel.status, createdNovel.error);
}
const config = {
configObjectId: 0,
entityId: createdNovel.id,
followeeId: req.user.id,
followeeId: request.user.id,
isSingle: false,
response: res
response
};
addNotification(config);
return successResponse(res, 201, {
return successResponse(response, 201, {
message: 'Novel created successfully',
novel: {
...createdNovel
Expand Down Expand Up @@ -86,6 +86,41 @@ const getNovels = async (request, response) => {
}
};

/**
*
*
* @name getSingleNovel
* @param {object} request
* @param {object} response
* @returns {object} json
*/
const getSingleNovel = async (request, response) => {
const {
params: { slug },
user: { id: userId }
} = request;
try {
const novel = await findNovel(slug);
if (!novel) {
return responseMessage(response, 404, { error: 'Novel not found' });
}
const highlights = await getNovelHighlights(novel, userId);
if (highlights.length > 0) {
return responseMessage(response, 200, {
message: 'Request successful',
novel,
highlights
});
}
return responseMessage(response, 200, {
message: 'Request successful',
novel
});
} catch (error) {
return responseMessage(response, 500, { error: error.message });
}
};

/**
* @description creates a genre
* @param {object} request express request object
Expand Down Expand Up @@ -116,25 +151,38 @@ const createGenre = async (request, response) => {
};

/**
* @description returns novel with slug
* @param {object} request express request object
* @param {object} response express response object
* @param {object} next express next argument
* @returns {json} json
*/
const getNovel = async (request, response) => {
* @name highlightNovel
* @param {object} request
* @param {object} response
* @returns {object} json
*/
const highlightNovel = async (request, response) => {
const {
body: highlight,
user: { id: userId },
params: { slug }
} = request;
try {
const { slug } = request.params;
const novel = await findNovel(slug);
if (!novel) {
return responseMessage(response, 404, { error: 'novel not found' });
return responseMessage(response, 404, { error: 'Novel not found' });
}
return responseMessage(response, 200, { novel });
const createdHighlight = await highlightNovelText(novel.id, userId, highlight);
return successResponse(response, 201, {
message: 'Text highlighted successfully',
highlight: {
...createdHighlight
}
});
} catch (error) {
responseMessage(response, 500, { error: error.message });
return responseMessage(response, 500, { error: error.message });
}
};

export default {
createNovel, getNovel, getNovels, createGenre
createNovel,
getNovels,
createGenre,
highlightNovel,
getSingleNovel
};
44 changes: 44 additions & 0 deletions src/database/migrations/20190815104218-create-highlight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export const up = (queryInterface, Sequelize) => queryInterface.createTable('Highlights', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID
},
novelId: {
allowNull: false,
type: Sequelize.UUID,
references: {
model: 'Novels',
key: 'id'
},
},
readerId: {
allowNull: false,
type: Sequelize.UUID,
references: {
model: 'Users',
key: 'id'
},
},
startIndex: {
allowNull: false,
type: Sequelize.INTEGER
},
endIndex: {
allowNull: false,
type: Sequelize.INTEGER
},
comment: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});

export const down = queryInterface => queryInterface.dropTable('Highlights');
54 changes: 54 additions & 0 deletions src/database/models/highlight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export default (Sequelize, DataTypes) => {
const Highlight = Sequelize.define('Highlight', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
novelId: {
allowNull: false,
type: DataTypes.UUID,
references: {
model: 'Novels',
key: 'id'
},
},
readerId: {
allowNull: false,
type: DataTypes.UUID,
references: {
model: 'Users',
key: 'id'
},
},
startIndex: {
allowNull: false,
type: DataTypes.INTEGER
},
endIndex: {
allowNull: false,
type: DataTypes.INTEGER
},
comment: {
type: DataTypes.STRING
},
createdAt: {
allowNull: false,
type: DataTypes.DATE
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE
}
}, {});
Highlight.associate = (models) => {
Highlight.belongsTo(models.Novel, {
foreignKey: 'novelId'
});
Highlight.belongsTo(models.User, {
foreignKey: 'readerId'
});
};
return Highlight;
};
1 change: 1 addition & 0 deletions src/helpers/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const isValidComment = () => check('commentBody')
.withMessage('commentBody cannot be empty')
.isLength({ max: 200 });


/**
* @param {String} field
* @returns {Object} - Express-validator
Expand Down
18 changes: 18 additions & 0 deletions src/middlewares/highlightValidator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import validator from '../helpers/validator';
import errorHandler from './errorHandler';

const {
isValidInt
} = validator;

const { validatorError } = errorHandler;

const highlightValidator = {
createHighlightValidator: [
isValidInt('startIndex'),
isValidInt('endIndex'),
validatorError
]
};

export default highlightValidator;
2 changes: 2 additions & 0 deletions src/middlewares/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import errorHandler from './errorHandler';
import userValidator from './userValidator';
import novelValidator from './novelValidator';
import commentValidator from './commentValidator';
import highlightValidator from './highlightValidator';
import verifyToken from './verifyToken';
import authorizeUser from './authorizeUser';
import reportValidator from './reportValidator';
Expand All @@ -12,6 +13,7 @@ export default {
userValidator,
novelValidator,
commentValidator,
highlightValidator,
verifyToken,
authorizeUser,
reportValidator
Expand Down
Loading

0 comments on commit 513bd49

Please sign in to comment.