Created
April 12, 2017 00:43
-
-
Save dennermiranda/70963880dc95c199ecebfa5699c7abac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This file contains pieces of code related to our media REST routes. | |
* Requesting GET media/:id returns information about a media (photo or video) with that specific identifier. | |
* The JSON response also includes a self signed temporal URL to acess the image or video from AWS S3, | |
* also another URL for the thumbnail. | |
* | |
* This endpoint is used by the app to display thumbnails or the media content that the user is currently | |
* browsing in the app. However, for very large albums/folders that requires the app doing a lot of requests | |
* while the user is browsing. | |
* | |
* Your task is to create a GET endpoint that instead of returning a single media object (including the | |
* temporal S3 URLs), returns an array for all of the media of a given albumId. | |
* (Media object schema is defined using Mongoose and contains a field called albumId set up as | |
* type: mongoose.Schema.Types.ObjectId) | |
* | |
* Feel free to indicate any assumptions in your response or ask us any questions. Also you can make any | |
* comments about the existing code of things you find good or you would improve. We are not looking for | |
* a specific solution, we want to know how you think. | |
* | |
* You can send your responses and comments to: | |
* @author José Luis Sánchez <joseluis@fotolog.com> | |
*/ | |
/** | |
* routes/media.js | |
* | |
*/ | |
const Joi = require('joi'); | |
const router = require('express').Router(); | |
const Media = require('../models/media'); | |
const generateResponse = require('../lib/gen-response'); | |
const s3 = require('../lib/aws-s3'); | |
router.get('/:id', async (req, res) => { | |
try { | |
const media = await Media.findOne({ _id: req.params.id }); | |
if (!media) return generateResponse(res, 404, { message: 'Media not found' }); | |
if (media.userId.toString() !== req.userId) | |
return generateResponse(res, 401, { message: 'Not allowed' }); | |
const getUrl = await s3.generateGetUrl(media); | |
generateResponse(res, 200, null, { | |
userId: media.userId, | |
type: media.type, | |
createdAt: media.createdAt, | |
s3: media.s3, | |
mediaTypeIndex: media.mediaTypeIndex, | |
metaTypeIndex: media.metaTypeIndex, | |
metaSubtypeIndex: media.metaSubtypeIndex, | |
userLocationTypeIndex: media.userLocationTypeIndex, | |
duration: media.duration, | |
date: media.date, | |
syncDate: media.syncDate, | |
location: media.location, | |
albumId: media.albumId, | |
tags: media.tags, | |
getMediaUrl: getUrl.mediaUrl, | |
getThumbUrl: getUrl.thumbUrl | |
}) | |
} catch(error) { | |
console.log(error); | |
generateResponse(res, 500, error); | |
} | |
}); | |
//My solution starts here @author Dener Miranda <denner.miranda@gmail.com>. | |
router.get('/albums/:id', async (req, res) => { | |
try{ | |
var callback = function (err, data) { | |
if (err) { return console.error(err); } | |
else { console.log(data); } | |
} | |
const medias = await Media.find({ _albumId: req.params.id }, callback); | |
if (!media) return generateResponse(res, 404, { message: 'Album not found!' }); | |
if (media.userId.toString() !== req.userId) | |
return generateResponse(res, 401, { message: 'Not allowed' }); | |
var response = [] | |
medias.forEach(function(media){ | |
const getUrl = await s3.generateGetUrl(media); | |
//A possible improvement would be to create a method to generate the media and avoid repeating code | |
response.push({ | |
userId: media.userId, | |
type: media.type, | |
createdAt: media.createdAt, | |
s3: media.s3, | |
mediaTypeIndex: media.mediaTypeIndex, | |
metaTypeIndex: media.metaTypeIndex, | |
metaSubtypeIndex: media.metaSubtypeIndex, | |
userLocationTypeIndex: media.userLocationTypeIndex, | |
duration: media.duration, | |
date: media.date, | |
syncDate: media.syncDate, | |
location: media.location, | |
albumId: media.albumId, | |
tags: media.tags, | |
getMediaUrl: getUrl.mediaUrl, | |
getThumbUrl: getUrl.thumbUrl | |
}); | |
}); | |
generateResponse(res, 200, null, response); | |
}catch(error){ | |
console.log(error); | |
generateResponse(res, 500, error); | |
} | |
}); | |
/** | |
* gen-response.js | |
* @param res - Express response object | |
* @param status - response status code | |
* @param error - error | |
* @param body - body | |
*/ | |
module.exports = (res, status, error, body) => { | |
res.status(status); | |
if (error) { | |
res.json({ errorMessage: error.message || error }); | |
return Promise.resolve(); | |
} | |
res.json(body); | |
return Promise.resolve(); | |
}; | |
/** | |
* aws-s3.js | |
* @param res - Express response object | |
* @param status - response status code | |
* @param error - error | |
* @param body - body | |
*/ | |
const AWS = require('aws-sdk'); | |
const promisify = require('../lib/promisify'); | |
const config = require('../config'); | |
AWS.config.update(config.aws); | |
const s3 = new AWS.S3(); | |
module.exports = { | |
generateGetUrl: (media) => { | |
if (!media.s3.uploaded) return Promise.resolve({ | |
mediaUrl: 'none', | |
thumbUrl: 'none' | |
}); | |
return Promise.all([ | |
promisify(s3.getSignedUrl.bind(s3), 'getObject', { | |
Bucket: config.s3bucket, | |
Key: media.s3.key, | |
Expires: 120 | |
}), | |
promisify(s3.getSignedUrl.bind(s3), 'getObject', { | |
Bucket: config.s3bucket, | |
Key: media.s3.thumbKey, | |
Expires: 120 | |
}) | |
]).then(urls => Promise.resolve({ | |
mediaUrl: urls[0], | |
thumbUrl: urls[1] | |
})) | |
} | |
}; | |
/** | |
* promisify.js | |
* Promisificator. Converts es5 callback function to es6 promise. | |
* @param method | |
* @param args | |
* @returns {Promise} | |
*/ | |
let promisify = require('./promisify'); | |
module.exports = (method, ...args) => { | |
return new Promise((resolve, reject) => { | |
return method(...args, (err, result) => { | |
return err ? reject(err) : resolve(result); | |
}) | |
}) | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment