From 97ee184ec521e466a5294edfff877f6c27aa7f48 Mon Sep 17 00:00:00 2001 From: david Date: Wed, 24 Jul 2019 16:50:41 +0200 Subject: [PATCH 1/3] . --- config/environments/development.js | 4 ++++ config/environments/production.js | 25 +++++++++++++++-------- helpers/cdn.helper.js | 31 +++++++++++++++++++++++++++++ modules/blog/blog.routes.js | 5 +++-- modules/comments/comment.model.js | 2 +- modules/events/event.service.js | 5 ++++- modules/speakers/speaker.model.js | 4 ++++ modules/speakers/speaker.service.js | 22 ++++++++++++++++++-- 8 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 helpers/cdn.helper.js diff --git a/config/environments/development.js b/config/environments/development.js index 25988f7..43a99cd 100644 --- a/config/environments/development.js +++ b/config/environments/development.js @@ -17,6 +17,10 @@ module.exports = { port: process.env.PORT || 18888 }, + cdn: { + hostname: "https://cdnapp2.loquedeverdadimporta.org", + }, + paginate: { limit: 10, maxLimit: 50 diff --git a/config/environments/production.js b/config/environments/production.js index 43d7f12..3910fb2 100644 --- a/config/environments/production.js +++ b/config/environments/production.js @@ -15,13 +15,22 @@ module.exports = { */ }, - session: { - secret_token: process.env.SECRET_TOKEN || "B57J=7B`NQ$y98|~5;hc715bo09^5oz8NR+]n9r~215B91Nd9P%25_N6r!GHcOKp|18y5-73Dr5^@9k7n]5l<-41D1o", - token_expires_in: '365d' - }, + session: { + secret_token: process.env.SECRET_TOKEN || "B57J=7B`NQ$y98|~5;hc715bo09^5oz8NR+]n9r~215B91Nd9P%25_N6r!GHcOKp|18y5-73Dr5^@9k7n]5l<-41D1o", + token_expires_in: '365d' + }, - server: { - hostname: process.env.HOSTNAME || '127.0.0.1', - port: process.env.PORT || 18888 - } + server: { + hostname: process.env.HOSTNAME || '127.0.0.1', + port: process.env.PORT || 18888 + }, + + cdn: { + hostname: "https://cdnapp2.loquedeverdadimporta.org", + }, + + paginate: { + limit: 10, + maxLimit: 50 + } } diff --git a/helpers/cdn.helper.js b/helpers/cdn.helper.js new file mode 100644 index 0000000..2e24b84 --- /dev/null +++ b/helpers/cdn.helper.js @@ -0,0 +1,31 @@ +const config = require('../config'); + +const assetsUrl = config.cdn.hostname; + +const CDN_PATHS = { + BLOG: "blog/", + CITIES: "cities/", + PROFILE: "profile/", + SPEAKERS: "speakers/", + WALLPAPERS: "wallpapers/" +}; + + +const getCDNMediaUrl = (mediaUri) => { + if (mediaUri) { + const pathParsed = mediaUri.indexOf("media") == 0 ? mediaUri.substr("media/".length, mediaUri.length) : mediaUri; + return encodeURI(encodeURI(`${assetsUrl}/${pathParsed}`)); + } + else { + return encodeURI(dummyMedia); + } +} + +const getCDNCityMediaUrl = (cityName) => encodeURI(`${assetsUrl}/${CDN_PATHS.CITIES}/${cityName}.jpg`); + + + +module.exports = { + getCDNCityMediaUrl, + getCDNMediaUrl +} \ No newline at end of file diff --git a/modules/blog/blog.routes.js b/modules/blog/blog.routes.js index 4a6f8e2..06f2195 100644 --- a/modules/blog/blog.routes.js +++ b/modules/blog/blog.routes.js @@ -16,7 +16,7 @@ routes.get('/posts', isLoggedUser, }), PaginateMiddleware.middleware(), SortMiddleware.middleware({ default: "date" }), - blogController.find); + blogController.find()); routes.post('/posts', isAdministratorUser, blogController.create); @@ -26,7 +26,8 @@ routes.get('/posts/:id', isLoggedUser, }), //PaginateMiddleware.middleware(), //SortMiddleware.middleware({ default: "date" }), - blogController.findOne); + blogController.findOne() + ); routes.put('/posts/:id', isAdministratorUser, blogController.update); diff --git a/modules/comments/comment.model.js b/modules/comments/comment.model.js index 73d0e1d..ab92f96 100644 --- a/modules/comments/comment.model.js +++ b/modules/comments/comment.model.js @@ -54,7 +54,7 @@ module.exports = function (sequelize, DataTypes) { Comment.associate = function (models) { - Comment.User = Comment.belongsTo(models.User, { foreignKey: 'userId', constraints: false }); + Comment.User = Comment.belongsTo(models.User, { foreignKey: 'userId', constraints: false, as: 'user' }); //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 }); diff --git a/modules/events/event.service.js b/modules/events/event.service.js index 1c7c05b..fc2655b 100644 --- a/modules/events/event.service.js +++ b/modules/events/event.service.js @@ -6,6 +6,7 @@ const moment = require('moment'); const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); const Sequelize = require('sequelize'); const models = require('../../core/models'); +const cdnHelper = require('../../helpers/cdn.helper'); const multimediaComposer = (multimedias) => multimedias.map(multimedia => ({ @@ -17,6 +18,7 @@ const multimediaComposer = (multimedias) => multimedias.map(multimedia => ({ createdAt: undefined, updatedAt: undefined, userId: undefined, + url: (multimedia.MultimediaFile.provider === 'cdn') ? cdnHelper.getCDNMediaUrl(multimedia.MultimediaFile.url) : multimedia.MultimediaFile.url, })); const speakerComposer = (speaker, context) => { @@ -31,7 +33,8 @@ const eventComposer = (event, context) => { if (context.scopes.includes('includeVenue')) { delete event.venue.updatedAt; - delete event.venue.createdAt; + delete event.venue.createdAt; + event.venue.image_url = cdnHelper.getCDNCityMediaUrl(event.venue.city); }; let multimedias = [] diff --git a/modules/speakers/speaker.model.js b/modules/speakers/speaker.model.js index 3b54b45..b03ecb9 100644 --- a/modules/speakers/speaker.model.js +++ b/modules/speakers/speaker.model.js @@ -141,6 +141,10 @@ module.exports = function (sequelize, DataTypes) { model: sequelize.models.Comment, as: 'comments', required: false, + include: [{ + model: sequelize.models.User, + as: 'user', + }] }] } }); diff --git a/modules/speakers/speaker.service.js b/modules/speakers/speaker.service.js index ab9d28a..aa21006 100644 --- a/modules/speakers/speaker.service.js +++ b/modules/speakers/speaker.service.js @@ -5,6 +5,7 @@ const _ = require('lodash'); const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); const Sequelize = require('sequelize'); const models = require('../../core/models'); +const cdnHelper = require('../../helpers/cdn.helper'); const multimediaComposer = (multimedias) => multimedias.map(multimedia => ({ @@ -16,6 +17,7 @@ const multimediaComposer = (multimedias) => multimedias.map(multimedia => ({ createdAt: undefined, updatedAt: undefined, userId: undefined, + url: (multimedia.MultimediaFile.provider === 'cdn') ? cdnHelper.getCDNMediaUrl(multimedia.MultimediaFile.url) : multimedia.MultimediaFile.url, })); const valuesComposer = (values) => values.map(value => ({ @@ -23,6 +25,16 @@ const valuesComposer = (values) => values.map(value => ({ name: value.name, })); + const commentsComposer = (comments) => comments.map(comment => ({ + ...comment, + userId: undefined, + user: { + ...comment.user, + profile_picture: cdnHelper.getCDNMediaUrl(comment.user.profile_picture) + + } + })) + const socialNetworksComposer = (speaker, context) => { return { @@ -44,9 +56,14 @@ const socialNetworksComposer = (speaker, context) => { }; const speakerComposer = (speaker, context) => { - let multimedias = [] + let multimedias = []; if (context.scopes.includes('includeMultimedias')) { - multimedias = multimediaComposer(speaker.multimedias) + multimedias = multimediaComposer(speaker.multimedias); + }; + + let comments = []; + if (context.scopes.includes('includeComments')) { + comments = commentsComposer(speaker.comments); }; speaker.typename = speaker.type.name; @@ -60,6 +77,7 @@ const speakerComposer = (speaker, context) => { speaker, rrss, { multimedias: multimedias }, + { comments: comments }, ) }; From 4aabf4258a7f625db538eedf1ebed4cc097534a0 Mon Sep 17 00:00:00 2001 From: david Date: Wed, 24 Jul 2019 23:03:10 +0200 Subject: [PATCH 2/3] . --- config/environments/development.js | 6 ++++++ config/environments/production.js | 8 +++++++- helpers/vimeo.helper.js | 22 ++++++++++++++++++++++ middlewares/cache.js | 20 ++++++++++++++++++++ modules/multimedia/multimedia.routes.js | 12 +++++++----- modules/multimedia/multimedia.service.js | 24 ++++++++++++++++++++++-- package.json | 3 +++ 7 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 helpers/vimeo.helper.js create mode 100644 middlewares/cache.js diff --git a/config/environments/development.js b/config/environments/development.js index 43a99cd..4883003 100644 --- a/config/environments/development.js +++ b/config/environments/development.js @@ -24,5 +24,11 @@ module.exports = { paginate: { limit: 10, maxLimit: 50 + }, + + vimeo: { + CLIENT_ID: '9581f2d0ed211dc1e31b5c825117dc1f00d77ba0', + CLIENT_SECRET: '3kf0hQ63OXSPm7z2X1qyOV4iH57Xha0cyRXn0VJneq8zHbWKjfB1/9H8KcgBgzgkzw0Y9x/xFLUAauuHLEkqHxLBw8QueanCgIZev1L5xoksrKuKX7gMvErqqP+uFNnA', + ACCESS_TOKEN: '2843aed2064f8148d74074dff7807d92' } } diff --git a/config/environments/production.js b/config/environments/production.js index 3910fb2..a62b311 100644 --- a/config/environments/production.js +++ b/config/environments/production.js @@ -32,5 +32,11 @@ module.exports = { paginate: { limit: 10, maxLimit: 50 - } + }, + + vimeo: { + CLIENT_ID: '9581f2d0ed211dc1e31b5c825117dc1f00d77ba0', + CLIENT_SECRET: '3kf0hQ63OXSPm7z2X1qyOV4iH57Xha0cyRXn0VJneq8zHbWKjfB1/9H8KcgBgzgkzw0Y9x/xFLUAauuHLEkqHxLBw8QueanCgIZev1L5xoksrKuKX7gMvErqqP+uFNnA', + ACCESS_TOKEN: '2843aed2064f8148d74074dff7807d92' + } } diff --git a/helpers/vimeo.helper.js b/helpers/vimeo.helper.js new file mode 100644 index 0000000..1121b1b --- /dev/null +++ b/helpers/vimeo.helper.js @@ -0,0 +1,22 @@ +const config = require('../config'); +const Vimeo = require('vimeo').Vimeo; +const client = new Vimeo(config.vimeo.CLIENT_ID, config.vimeo.CLIENT_SECRET, config.vimeo.ACCESS_TOKEN); + +function getVimeoVideoInfo(videoId) { + return new Promise(function(resolve, reject) { + client.request({ + method: 'GET', + path: '/videos/' + videoId + }, function (error, body, status_code, headers) { + if (error) { + console.log(error); + resolve({}) + } else { + resolve(body); + } + }) + }); +} + + +module.exports = getVimeoVideoInfo; diff --git a/middlewares/cache.js b/middlewares/cache.js new file mode 100644 index 0000000..a56be49 --- /dev/null +++ b/middlewares/cache.js @@ -0,0 +1,20 @@ +const apicache = require('apicache'); +const redis = require('redis'); + +let cacheWithRedis = apicache + .options({ + debug: true, + defaultDuration: '1 hour', + redisClient: redis.createClient() + }) + .middleware; + +// higher-order function returns false for responses of other status codes (e.g. 403, 404, 500, etc) +const onlyStatus200 = (req, res) => res.statusCode === 200 + +const cacheSuccesses = cacheWithRedis('1 hour', onlyStatus200); + +module.exports = { + cacheSuccesses, +} + diff --git a/modules/multimedia/multimedia.routes.js b/modules/multimedia/multimedia.routes.js index fb88ffd..8ab2774 100644 --- a/modules/multimedia/multimedia.routes.js +++ b/modules/multimedia/multimedia.routes.js @@ -1,6 +1,8 @@ const routes = require('express').Router(); const { isAdministratorUser, isLoggedUser } = require('../../middlewares/accessValidator'); +const { cacheSuccesses } = require('../../middlewares/cache'); + //const SchemaValidator = require('../../middlewares/schemaValidator'); const PaginateMiddleware = require('../../middlewares/paginate'); @@ -11,23 +13,23 @@ const SortMiddleware = require('../../middlewares/sort'); const multimediaController = require('./multimedia.controller'); -routes.get('/multimedias', +routes.get('/multimedias', cacheSuccesses, PaginateMiddleware.middleware(), //SortMiddleware.middleware({ default: "init_available_date" }), - multimediaController.find + multimediaController.find({}) ); -routes.get('/multimedias/:id', +routes.get('/multimedias/:id', cacheSuccesses, //PaginateMiddleware.middleware(), //SortMiddleware.middleware({ default: "init_available_date" }), - multimediaController.findOne + multimediaController.findOne({}) ); routes.get('/multimedias/:entityId', //PaginateMiddleware.middleware(), //SortMiddleware.middleware({ default: "init_available_date" }), - multimediaController.find + multimediaController.find({}) ); diff --git a/modules/multimedia/multimedia.service.js b/modules/multimedia/multimedia.service.js index 6029a3b..3375afc 100644 --- a/modules/multimedia/multimedia.service.js +++ b/modules/multimedia/multimedia.service.js @@ -4,7 +4,27 @@ const _ = require('lodash'); const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); const models = require('../../core/models'); +const getVimeoVideoInfo = require('../../helpers/vimeo.helper'); -const extraMethods = {}; +const providerComposer = (multimedia) => { + return getVimeoVideoInfo(multimedia.code) +} -module.exports = generateService(models.Multimedia, extraMethods); \ No newline at end of file +const extraMethods = { + afterFetchOne: async (result, params, context) => { + if (!result) { + return result; + } + + const multimedia = result.toJSON(); + console.log(multimedia); + + if (multimedia.provider === 'vimeo') { + multimedia.providerInfo = await providerComposer(multimedia); + } + return multimedia; + }, + +} + +module.exports = generateService(models.MultimediaFile, extraMethods); \ No newline at end of file diff --git a/package.json b/package.json index 88daa76..6e39c7a 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "nodemon": "^1.18.9" }, "dependencies": { + "apicache": "^1.4.0", "args-list": "^0.3.3", "async": "^2.6.2", "bcrypt": "^3.0.6", @@ -51,8 +52,10 @@ "path": "^0.12.7", "pino": "^4.7.1", "rand-token": "^0.4.0", + "redis": "^2.8.0", "response-time": "^2.3.2", "sequelize": "^5.3.5", + "vimeo": "^2.1.1", "vm": "^0.1.0", "winston": "^3.2.1" } From 71273e9a63b5bc1f4b8a6ba58be04686bed1a65f Mon Sep 17 00:00:00 2001 From: david Date: Thu, 25 Jul 2019 09:37:04 +0200 Subject: [PATCH 3/3] Multimedias --- modules/multimedia/multimedia.model.js | 16 +++++++- modules/multimedia/multimedia.routes.js | 12 ++++-- modules/multimedia/multimedia.service.js | 2 +- .../multimedia/multimedia_file.controller.js | 14 +++++++ modules/multimedia/multimedia_file.model.js | 10 ++++- modules/multimedia/multimedia_file.routes.js | 41 +++++++++++++++++++ modules/multimedia/multimedia_file.service.js | 30 ++++++++++++++ 7 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 modules/multimedia/multimedia_file.controller.js create mode 100644 modules/multimedia/multimedia_file.routes.js create mode 100644 modules/multimedia/multimedia_file.service.js diff --git a/modules/multimedia/multimedia.model.js b/modules/multimedia/multimedia.model.js index 8384628..7795bd4 100644 --- a/modules/multimedia/multimedia.model.js +++ b/modules/multimedia/multimedia.model.js @@ -60,8 +60,22 @@ module.exports = function (sequelize, DataTypes) { timestamps: true, }); + Multimedia.addScope('includeMultimediaFile', () => { + return { + include: [ + { model: sequelize.models.MultimediaFile, as: 'multimediaFile' } + ] + } + }); + Multimedia.associate = function (models) { - Multimedia.MultimediaFile = Multimedia.belongsTo(models.MultimediaFile, { foreignKey: 'multimediafileId' }); + Multimedia.MultimediaFile = Multimedia.belongsTo(models.MultimediaFile, { foreignKey: 'multimediafileId', as: "multimediaFile" }); + + Multimedia.Speaker = Multimedia.hasOne(models.Speaker, { + foreignKey: 'entityId', + as: 'speaker' + }); + }; return Multimedia; diff --git a/modules/multimedia/multimedia.routes.js b/modules/multimedia/multimedia.routes.js index 8ab2774..81e0e6c 100644 --- a/modules/multimedia/multimedia.routes.js +++ b/modules/multimedia/multimedia.routes.js @@ -13,16 +13,20 @@ const SortMiddleware = require('../../middlewares/sort'); const multimediaController = require('./multimedia.controller'); -routes.get('/multimedias', cacheSuccesses, +routes.get('/multimedias', //cacheSuccesses, PaginateMiddleware.middleware(), //SortMiddleware.middleware({ default: "init_available_date" }), - multimediaController.find({}) + multimediaController.find({ + scopes: ['includeMultimediaFile'] + }) ); -routes.get('/multimedias/:id', cacheSuccesses, +routes.get('/multimedias/:id', //cacheSuccesses, //PaginateMiddleware.middleware(), //SortMiddleware.middleware({ default: "init_available_date" }), - multimediaController.findOne({}) + multimediaController.findOne({ + scopes: ['includeMultimediaFile'] + }) ); diff --git a/modules/multimedia/multimedia.service.js b/modules/multimedia/multimedia.service.js index 3375afc..943ff16 100644 --- a/modules/multimedia/multimedia.service.js +++ b/modules/multimedia/multimedia.service.js @@ -27,4 +27,4 @@ const extraMethods = { } -module.exports = generateService(models.MultimediaFile, extraMethods); \ No newline at end of file +module.exports = generateService(models.Multimedia, extraMethods); \ No newline at end of file diff --git a/modules/multimedia/multimedia_file.controller.js b/modules/multimedia/multimedia_file.controller.js new file mode 100644 index 0000000..ac09681 --- /dev/null +++ b/modules/multimedia/multimedia_file.controller.js @@ -0,0 +1,14 @@ +'use strict'; + +const generateControllers = require('../../core/controllers'); +const multimediaFileService = require('./multimedia_file.service'); + + +// Module Name +const MODULE_NAME = '[multimediaFile.controller]'; + +const controllerOptions = { MODULE_NAME }; +const extraControllers = {}; + +module.exports = generateControllers(multimediaFileService, extraControllers, controllerOptions); + diff --git a/modules/multimedia/multimedia_file.model.js b/modules/multimedia/multimedia_file.model.js index 9731313..240e6d9 100644 --- a/modules/multimedia/multimedia_file.model.js +++ b/modules/multimedia/multimedia_file.model.js @@ -37,8 +37,16 @@ module.exports = function (sequelize, DataTypes) { MultimediaFile.associate = function (models) { MultimediaFile.UserCreate = MultimediaFile.belongsTo(models.User, { foreignKey: 'userId' }); - MultimediaFile.Multimedias = MultimediaFile.hasMany(models.Multimedia, { foreignKey: 'multimediafileId' }); + MultimediaFile.Multimedias = MultimediaFile.hasMany(models.Multimedia, { foreignKey: 'multimediafileId', as: "multimedias" }); }; + MultimediaFile.addScope('includeMultimedias', () => { + return { + include: [ + { model: sequelize.models.Multimedia, as: 'multimedias' } + ] + } + }); + return MultimediaFile; }; \ No newline at end of file diff --git a/modules/multimedia/multimedia_file.routes.js b/modules/multimedia/multimedia_file.routes.js new file mode 100644 index 0000000..42fefa0 --- /dev/null +++ b/modules/multimedia/multimedia_file.routes.js @@ -0,0 +1,41 @@ +const routes = require('express').Router(); + +const { isAdministratorUser, isLoggedUser } = require('../../middlewares/accessValidator'); +const { cacheSuccesses } = require('../../middlewares/cache'); + +//const SchemaValidator = require('../../middlewares/schemaValidator'); + +const PaginateMiddleware = require('../../middlewares/paginate'); +const FieldMiddleware = require('../../middlewares/fields'); +const SortMiddleware = require('../../middlewares/sort'); +const multimediaFileController = require('./multimedia_file.controller'); + +const generalInvalidFields = [ + 'userId', 'createdAt', 'updatedAt', +]; + +routes.get('/multimediafiles', //cacheSuccesses, + FieldMiddleware.middleware({ + invalidFields: generalInvalidFields + }), + PaginateMiddleware.middleware(), + //SortMiddleware.middleware({ default: "init_available_date" }), + multimediaFileController.find({ + scopes: ['includeMultimedias'] + }) +); + +routes.get('/multimediafiles/:id', //cacheSuccesses, + FieldMiddleware.middleware({ + invalidFields: generalInvalidFields + }), + //SortMiddleware.middleware({ default: "init_available_date" }), + multimediaFileController.findOne({ + scopes: ['includeMultimedias'] + }) +); + + + + +module.exports = routes; \ No newline at end of file diff --git a/modules/multimedia/multimedia_file.service.js b/modules/multimedia/multimedia_file.service.js new file mode 100644 index 0000000..3375afc --- /dev/null +++ b/modules/multimedia/multimedia_file.service.js @@ -0,0 +1,30 @@ +/* global Venue */ +'use strict'; + +const _ = require('lodash'); +const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); +const models = require('../../core/models'); +const getVimeoVideoInfo = require('../../helpers/vimeo.helper'); + +const providerComposer = (multimedia) => { + return getVimeoVideoInfo(multimedia.code) +} + +const extraMethods = { + afterFetchOne: async (result, params, context) => { + if (!result) { + return result; + } + + const multimedia = result.toJSON(); + console.log(multimedia); + + if (multimedia.provider === 'vimeo') { + multimedia.providerInfo = await providerComposer(multimedia); + } + return multimedia; + }, + +} + +module.exports = generateService(models.MultimediaFile, extraMethods); \ No newline at end of file