From 2a9ec3a346b6d3af8ed0886f6e9b0c0f1eef4e32 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 23 May 2019 11:40:50 +0200 Subject: [PATCH] . --- core/controllers/index.js | 35 +++++--- helpers/controller.helper.js | 7 +- helpers/service.helper.js | 126 +++++++++++++++++++--------- modules/blog/blog.controller.js | 27 +++++- modules/blog/blog.routes.js | 14 ++-- modules/blog/blog.service.js | 20 +++-- modules/blog/category.model.js | 6 +- modules/blog/category.routes.js | 4 +- modules/blog/post-category.model.js | 2 +- modules/blog/post.model.js | 2 +- modules/comments/comment.model.js | 49 +++++++++++ modules/comments/comment.service.js | 10 +++ 12 files changed, 227 insertions(+), 75 deletions(-) create mode 100644 modules/comments/comment.model.js create mode 100644 modules/comments/comment.service.js diff --git a/core/controllers/index.js b/core/controllers/index.js index e842bc0..dde31cf 100644 --- a/core/controllers/index.js +++ b/core/controllers/index.js @@ -9,42 +9,51 @@ function buildContext(req, res) { } const defaultOptions = { - MODULE_NAME: 'default' + MODULE_NAME: 'default', + params: { + find: { includeAll: true }, + findOne: { includeAll: true, paginate: { limit: 1, page: 1 } }, + count: {}, + } } -const generateControllers = (service, extraControllers = {}, options = defaultOptions) => { +const generateControllers = (service, extraControllers = {}, options = {}) => { + const _options = { + ...defaultOptions, + ...options + }; + const defaultControllers = { - find: async (req, res, next) => { - const params = extractParamsFromRequest(req, res); + find: async (req, res, next) => { + const params = extractParamsFromRequest(req, res, _options.params.find); try { const result = await service.fetchAll(params, buildContext(req, res)); return handleResultResponse(result.rows, result.count, params, res); } catch (error) { - handleErrorResponse(options.MODULE_NAME, 'find', error, res) + handleErrorResponse(_options.MODULE_NAME, 'find', error, res) } }, findOne: async (req, res, next) => { - const params = extractParamsFromRequest(req, res); + const params = extractParamsFromRequest(req, res, _options.params.findOne); try { const result = await service.fetchOne(params, buildContext(req, res)); - console.log(result); return handleResultResponse(result, null, params, res, (result === null) ? httpStatus.NOT_FOUND : httpStatus.OK); } catch (error) { - handleErrorResponse(options.MODULE_NAME, 'findOne', error, res) + handleErrorResponse(_options.MODULE_NAME, 'findOne', error, res) } }, count: async(req, res, next) => { - const params = extractParamsFromRequest(req, res); + const params = extractParamsFromRequest(req, res, _options.params.count); try { const result = await service.count(params, buildContext(req, res)); return handleResultResponse(result, null, params, res); } catch (error) { - handleErrorResponse(options.MODULE_NAME, 'count', error, res) + handleErrorResponse(_options.MODULE_NAME, 'count', error, res) } }, @@ -53,7 +62,7 @@ const generateControllers = (service, extraControllers = {}, options = defaultOp const result = await service.create(req.body, buildContext(req, res)); return handleResultResponse(result, null, null, res, httpStatus.CREATED) } catch (error) { - handleErrorResponse(options.MODULE_NAME, 'create', error, res) + handleErrorResponse(_options.MODULE_NAME, 'create', error, res) } }, @@ -62,7 +71,7 @@ const generateControllers = (service, extraControllers = {}, options = defaultOp const result = await service.update(req.params, req.body, buildContext(req, res)); return handleResultResponse(result, null, req.params, res, httpStatus.OK) } catch (error) { - handleErrorResponse(options.MODULE_NAME, 'update', error, res) + handleErrorResponse(_options.MODULE_NAME, 'update', error, res) } }, @@ -71,7 +80,7 @@ const generateControllers = (service, extraControllers = {}, options = defaultOp const result = await service.delete(req.params, buildContext(req, res)); return handleResultResponse(result, null, req.params, res, httpStatus.NO_CONTENT); } catch (error) { - handleErrorResponse(options.MODULE_NAME, 'delete', error, res) + handleErrorResponse(_options.MODULE_NAME, 'delete', error, res) } }, } diff --git a/helpers/controller.helper.js b/helpers/controller.helper.js index 6c65b69..3fbeb9b 100644 --- a/helpers/controller.helper.js +++ b/helpers/controller.helper.js @@ -86,7 +86,7 @@ function setPaginationInfo(totalCount, res) { // PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////// -function extractParamsFromRequest(req, res) { +function extractParamsFromRequest(req, res, extraParams = {}) { const result = {}; result.params = (req && req.params) ? req.params : null; @@ -98,7 +98,10 @@ function extractParamsFromRequest(req, res) { }) } - return result; + return { + ...result, + ...extraParams + } } diff --git a/helpers/service.helper.js b/helpers/service.helper.js index 8b94107..046dc7a 100644 --- a/helpers/service.helper.js +++ b/helpers/service.helper.js @@ -1,7 +1,79 @@ const _ = require('lodash'); + +function _debugModelInfo(model) { + if (!model.name) + return; + + console.log("\n\n----------------------------------\n", + model.name, + "\n----------------------------------"); + + console.log("\nAttributes"); + if (model.rawAttributes) { + for (let attr of Object.keys(model.rawAttributes)) { + console.log(model.name + '.' + attr); + } + } + + console.log("\nAssociations"); + if (model.associations) { + for (let assoc of Object.keys(model.associations)) { + console.log('as: ', model.associations[assoc].as, 'type: ', model.associations[assoc].associationType); + for (let accessor of Object.keys(model.associations[assoc].accessors)) { + console.log(accessor); + console.log(model.name + '.' + model.associations[assoc].accessors[accessor] + '()'); + } + } + } + + if (model.Instance && model.Instance.super_) { + console.log("\nCommon"); + for (let func of Object.keys(model.Instance.super_.prototype)) { + if (func === 'constructor' || func === 'sequelize') + continue; + console.log(model.name + '.' + func + '()'); + } + } + + console.log("\n\n----------------------------------\n", + "END", + "\n----------------------------------"); + + + return; +} + +function getAssociationArrayFromModel(model) { + const result = []; + + if (!model || typeof model.associations !== 'object') { + throw new Error("Model should have the 'associations' property."); + } + + Object.keys(model.associations).forEach(key => result.push(key)); + return result; +} + +function modelAssociationsToArray(model) { + const result = []; + + if (!model || typeof model.associations !== 'object') { + throw new Error("Model should be an object with the 'associations' property."); + } + + Object.keys(model.associations).forEach((key) => { + result[key] = model.associations[key]; + //result.push(key); + }); + + return result; +} + const parseParamsToFindOptions = (params) => { const result = {}; + // Include All + result.include = (params.includeAll) ? [{ all: true }] : []; // Query if (params.query) { @@ -52,63 +124,36 @@ const generateService = (model, extraMethods = {}, options = defaultOptions) => fetchAll: async (params, context) => { const findOptions = parseParamsToFindOptions(params); + console.log(model); return await model.findAndCountAll(findOptions); }, fetchOne: async (params, context) => { - return await model.findOne({ where: { 'id': params.id } }); + const findOptions = parseParamsToFindOptions(params); + return await model.findOne({ + where: findOptions.where, + include: findOptions.include + }); }, count: async (params, context) => { - // Convert `params` object to filters compatible with Bookshelf. - //const filters = strapi.utils.models.convertParams('post', params); - - return await model.count(params); + const findOptions = parseParamsToFindOptions(params); + return await model.count(findOptions); }, create: async (values, context) => { - return await model.create(values); + return await model.create(data); }, update: async (params, values, context) => { - // Extract values related to relational data. - const relations = _.pick(values, Post.associations.map(ast => ast.alias)); - const data = _.omit(values, Post.associations.map(ast => ast.alias)); - - // Create entry with no-relational data. - const entry = await Post.forge(params).save(data); - - // Create relational data and return the entry. - return Post.updateRelations(Object.assign(params, { - values: relations - })); + const findOptions = parseParamsToFindOptions(params); + return await model.update(values, findOptions) }, delete: async (params, context) => { - const numAffectedRows = await model.destroy({ where: { 'id': params.id } }); + const findOptions = parseParamsToFindOptions(params); + const numAffectedRows = await model.destroy(findOptions); return (numAffectedRows > 0); - - /*params.values = {}; - Post.associations.map(association => { - switch (association.nature) { - case 'oneWay': - case 'oneToOne': - case 'manyToOne': - case 'oneToManyMorph': - params.values[association.alias] = null; - break; - case 'oneToMany': - case 'manyToMany': - case 'manyToManyMorph': - params.values[association.alias] = []; - break; - default: - } - }); - - await Post.updateRelations(params); - - return Post.forge(params).destroy();*/ }, search: async (params, context) => { @@ -200,6 +245,7 @@ const generateService = (model, extraMethods = {}, options = defaultOptions) => module.exports = { + _debugModelInfo, generateService, parseParamsToFindOptions, defaultOptions diff --git a/modules/blog/blog.controller.js b/modules/blog/blog.controller.js index 65c1fc1..8a6255a 100644 --- a/modules/blog/blog.controller.js +++ b/modules/blog/blog.controller.js @@ -1,7 +1,10 @@ 'use strict'; +const { extractParamsFromRequest, handleErrorResponse, handleResultResponse } = require('../../helpers/controller.helper'); const generateControllers = require('../../core/controllers'); +const models = require('../../core/models'); const blogService = require('./blog.service'); +const generateCommentService = require('../comments/comment.service'); // Module Name @@ -13,9 +16,29 @@ const MODULE_NAME = '[blog.controller]'; // Success Messages //const VG_CT_VIDEOGAME_DELETED_SUCCESSFULLY = 'Videogame deleted successfully'; +const blogCommentsService = generateCommentService(models.Post.Comments); -const controllerOptions = { MODULE_NAME }; -const extraControllers = {}; +const controllerOptions = { + MODULE_NAME, + params: { + find: { includeAll: true }, + findOne: { includeAll: true, paginate: { limit: 1, page: 1 } }, + count: {}, + } +}; + +const extraControllers = { + getPostComments: async (req, res, next) => { + const params = extractParamsFromRequest(req, res, controllerOptions.params.find); + + try { + const result = await blogCommentsService.fetchAll(params, {}); + return handleResultResponse(result.rows, result.count, params, res); + } catch (error) { + handleErrorResponse(controllerOptions.MODULE_NAME, 'find', error, res) + } + }, +}; module.exports = generateControllers(blogService, extraControllers, controllerOptions); diff --git a/modules/blog/blog.routes.js b/modules/blog/blog.routes.js index 7b0cac1..4a6f8e2 100644 --- a/modules/blog/blog.routes.js +++ b/modules/blog/blog.routes.js @@ -10,10 +10,9 @@ const FieldMiddleware = require('../../middlewares/fields'); const blogController = require('./blog.controller') -routes.get('/posts', - isLoggedUser, +routes.get('/posts', isLoggedUser, FieldMiddleware.middleware({ - invalidFields: ['user', 'created'] + invalidFields: ['user', 'createdAt'] }), PaginateMiddleware.middleware(), SortMiddleware.middleware({ default: "date" }), @@ -21,8 +20,7 @@ routes.get('/posts', routes.post('/posts', isAdministratorUser, blogController.create); -routes.get('/posts/:id', - isLoggedUser, +routes.get('/posts/:id', isLoggedUser, FieldMiddleware.middleware({ invalidFields: ['updatedAt', 'createdAt'] }), @@ -34,4 +32,10 @@ routes.get('/posts/:id', routes.put('/posts/:id', isAdministratorUser, blogController.update); routes.delete('/posts/:id', isAdministratorUser, blogController.delete); +routes.get('/posts/:id/comments', isLoggedUser, + PaginateMiddleware.middleware(), + SortMiddleware.middleware({ default: "date" }), + blogController.getPostComments); + + module.exports = routes; \ No newline at end of file diff --git a/modules/blog/blog.service.js b/modules/blog/blog.service.js index d753810..4f92228 100644 --- a/modules/blog/blog.service.js +++ b/modules/blog/blog.service.js @@ -2,21 +2,29 @@ 'use strict'; const _ = require('lodash'); -const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); +const { generateService, parseParamsToFindOptions, _debugModelInfo } = require('../../helpers/service.helper'); const models = require('../../core/models'); const extraMethods = { - fetchOne: async (params, context) => { + /*fetchOne: async (params, context) => { const findOptions = parseParamsToFindOptions(params); - console.log(findOptions); const result = await models.Post.findByPk(findOptions.query.id, { include: [{ all: true }] }); - - console.log(result); return result; - }, + },*/ + create: async (values, context) => { + const { Categories, ...data } = values; + return models.sequelize.transaction(async transaction => { + const result = await models.Post.create(data, { transaction }); + + if (Categories) { + await result.setCategories(Categories, { transaction }); + } + return result; + }); + }, } diff --git a/modules/blog/category.model.js b/modules/blog/category.model.js index 9a3ddc8..f62fda1 100755 --- a/modules/blog/category.model.js +++ b/modules/blog/category.model.js @@ -11,7 +11,7 @@ module.exports = function (sequelize, DataTypes) { }, sort: { type: DataTypes.INTEGER, - defaultValue: 0, + defaultValue: 0, allowNull: false, } }, { @@ -20,9 +20,9 @@ module.exports = function (sequelize, DataTypes) { timestamps: false }); - Category.beforeCreate((category) => { + /*Category.beforeCreate((category) => { //category.dataValues.id = Math.floor(Math.random() * (999 - 8)) + 8; - }) + })*/ Category.associate = function (models) { Category.Posts = Category.belongsToMany(models.Post, { diff --git a/modules/blog/category.routes.js b/modules/blog/category.routes.js index 97c8d20..d418893 100644 --- a/modules/blog/category.routes.js +++ b/modules/blog/category.routes.js @@ -2,12 +2,12 @@ const routes = require('express').Router(); const { isAdministratorUser, isLoggedUser } = require('../../middlewares/accessValidator'); /*const PaginateMiddleware = require('../../middlewares/paginate'); -const SortMiddleware = require('../../middlewares/sort'); const FieldMiddleware = require('../../middlewares/fields');*/ +const SortMiddleware = require('../../middlewares/sort'); const categoryController = require('./category.controller'); -routes.get('/categories', isLoggedUser, categoryController.find); +routes.get('/categories', isLoggedUser, SortMiddleware.middleware({ default: "name" }), categoryController.find); routes.get('/categories/:id', isLoggedUser, categoryController.findOne); routes.post('/categories/', isAdministratorUser, categoryController.create); diff --git a/modules/blog/post-category.model.js b/modules/blog/post-category.model.js index 9e28f0a..3d5767d 100755 --- a/modules/blog/post-category.model.js +++ b/modules/blog/post-category.model.js @@ -11,7 +11,7 @@ module.exports = function (sequelize, DataTypes) { foreignKey: true } }, { - tableName: 'post-category', + tableName: 'post_category', freezeTableName: true, timestamps: false }); diff --git a/modules/blog/post.model.js b/modules/blog/post.model.js index de22709..afec525 100644 --- a/modules/blog/post.model.js +++ b/modules/blog/post.model.js @@ -35,7 +35,7 @@ module.exports = function (sequelize, DataTypes) { through: models.PostCategory, foreignKey: 'postId' }); - //Post.Comments = Post.hasMany(models.PostComment, { foreignKey: 'postId' }); + Post.Comments = Post.hasMany(models.Comment, { foreignKey: 'postId' }); //Post.Reactions = Post.hasMany(models.PostReaction, { foreignKey: 'postId' }); //Post.User = Post.belongsTo(models.User, { foreignKey: 'userId' }); }; diff --git a/modules/comments/comment.model.js b/modules/comments/comment.model.js new file mode 100644 index 0000000..5a4b20a --- /dev/null +++ b/modules/comments/comment.model.js @@ -0,0 +1,49 @@ +module.exports = function (sequelize, DataTypes) { + const Comment = sequelize.define('Comment', { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + entityType: { + field: 'type', + type: DataTypes.STRING, + allowNull: false + }, + entity: { + type: DataTypes.VIRTUAL(DataTypes.UUID, ['conferenceId', 'speakerId', 'postId']), + }, + content: { + type: DataTypes.STRING, + allowNull: false + }, + user: { + type: DataTypes.VIRTUAL(DataTypes.UUID, ['userId']), + }, + /*conference: { + type: DataTypes.VIRTUAL(DataTypes.UUID, ['conferenceId']), + },*/ + post: { + type: DataTypes.VIRTUAL(DataTypes.UUID, ['postId']), + }, + /*speaker: { + type: DataTypes.VIRTUAL(DataTypes.UUID, ['speakerId']), + },*/ + + }, { + tableName: 'comments', + freezeTableName: true, + timestamps: true, + + }); + + Comment.associate = function (models) { + Comment.User = Comment.belongsTo(models.User, { foreignKey: 'userId', constraints: false }); + //Comment.Conference = Comment.belongsTo(models.Conference, { foreignKey: 'conferenceId', constraints: false }); + Comment.Post = Comment.belongsTo(models.Post, { foreignKey: 'postId', constraints: false }); + //Comment.Speaker = Comment.belongsTo(models.Speaker, { foreignKey: 'speakerId', constraints: false }); + }; + + return Comment; + +}; \ No newline at end of file diff --git a/modules/comments/comment.service.js b/modules/comments/comment.service.js new file mode 100644 index 0000000..f8180bf --- /dev/null +++ b/modules/comments/comment.service.js @@ -0,0 +1,10 @@ +/* global Post */ +'use strict'; + +const _ = require('lodash'); +const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); +const models = require('../../core/models'); + +const extraMethods = {} + +module.exports = (model) => generateService(model, extraMethods); \ No newline at end of file