diff --git a/hw7/Claudio_Maggioni/app.js b/hw7/Claudio_Maggioni/app.js index f674478..f9d345a 100644 --- a/hw7/Claudio_Maggioni/app.js +++ b/hw7/Claudio_Maggioni/app.js @@ -48,6 +48,7 @@ app.use('/', routers.root); app.use('/favorites', routers.favourites_db_asaw); app.use('/bookmarked', routers.bookmarked); app.use('/test/fetch', routers.fetch_tests); +app.use('/imgur', routers.imgur); app.set('port', process.env.PORT || 3000); const server = app.listen(app.get('port'), function() { @@ -89,6 +90,8 @@ eventBus.on('favorite.deleted', (event) => { io.emit('favorite.deleted', event); }); +// Imgur auth url open code + const { exec } = require('child_process'); const client = '3710c666dbec94e'; const imgURL = `https://api.imgur.com/oauth2/authorize?client_id=${client}` + diff --git a/hw7/Claudio_Maggioni/readme.md b/hw7/Claudio_Maggioni/readme.md new file mode 100644 index 0000000..e5aec12 --- /dev/null +++ b/hw7/Claudio_Maggioni/readme.md @@ -0,0 +1,6 @@ +# Bonuses implemented + +- Task 3 bookmarked code +- Task 6 +- Task 7 +- Access token fetching from authorization url diff --git a/hw7/Claudio_Maggioni/routes/imgur/router.js b/hw7/Claudio_Maggioni/routes/imgur/router.js new file mode 100644 index 0000000..6d8f568 --- /dev/null +++ b/hw7/Claudio_Maggioni/routes/imgur/router.js @@ -0,0 +1,274 @@ +/** @module root/router */ +'use strict'; +// vim: set ts=2 sw=2 et tw=80: + +const express = require('express'); +const router = express.Router(); + +const mongoose = require('mongoose'); +const Favorite = mongoose.model('Favorite'); +const fetch = require('node-fetch'); +const querystring = require('querystring'); +const promiseAny = require('promise-any'); +const eventBus = require('../../pubsub'); +const fetch64 = require('fetch-base64'); + +router.get('/', (req, res) => { + if (req.query.access_token) { + req.app.locals.imgur = req.query; + res.redirect('/'); + } else { + res.status(200, {'Content-Type': 'text/html'}); + res.end(` + `); + } +}); + +async function fetchImgur(req, res, method, url, body) { + const endpoint = 'https://api.imgur.com/3'; + + const response = await fetch(endpoint + url, { + method: method, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization' : 'Bearer ' + req.app.locals.imgur.access_token + }, + body: body ? querystring.stringify(body) : undefined + }); + + const json = await response.json(); + + if (json.status == 409 && url.match(/follow\/tag/)) { + return {}; + } + + if (Math.floor(json.status / 100) != 2) { + res.status(json.status).json(json); + return false; + } + + return json; +} + +router.post('/ordeal', async (req, res) => { + try { + if ((!req.body.replace && (!req.body.name || !req.body.album)) || + (req.body.replace && (!req.body.name || !req.body.oldName))) { + res.status(400).json({ error: "Malformed ordeal request" }); + return; + } + + const ordealResponse = { ordealSuccess: true }; + + const uploadData = { + image: req.body.dataURL.substring('data:image/png;base64,'.length), + type: 'base64', + title: req.body.name, + name: req.body.name + '.png', + }; + + const uploadJson = await fetchImgur(req, res, 'POST', '/upload', uploadData); + if (!uploadJson) { + return; + } + + const imageId = uploadJson.data.id; + + const albumData = { + 'ids[]': imageId, + }; + + if (!req.body.replace) { + if (req.body.album) { + albumData.title = req.body.album; + } + + const albumJson = await fetchImgur(req, res, 'POST', '/album', albumData); + if (!albumJson) { + return; + } + + if (req.body.favorites) { + if (!await fetchImgur(req, res, 'POST', '/album/' + albumJson.data.id + + '/favorite', {})) { + return; + } + } + } else { + req.body.album = undefined; + + const submissions = await fetchImgur(req, res, 'GET', + '/account/me/submissions'); + + if (!submissions) { + return; + } + + const submission = submissions.data + .filter(e => !e.images && e.in_gallery && + e.title == req.body.oldName)[0]; + + if (!submission) { + res.status(404).json({ error: "No image in submissions found" }); + return; + } + + console.log('submission', submission.id, submission.title); + + const result = {}; + result.image = submission; + ordealResponse.views = submission.views; + ordealResponse.votes = {}; + ordealResponse.votes.ups = submission.ups; + ordealResponse.votes.downs = submission.downs; + + const albumIds = await fetchImgur(req, res, 'GET', + '/account/me/albums/ids'); + + if (!albumIds) { + return; + } + + console.log('albumIds', albumIds.data.join(',')); + + let reject = false; + const promises = []; + for (const albumId of albumIds.data) { + promises.push(new Promise(async (res, rej) => { + if (reject) { + return reject; + } + + const images = await fetchImgur(req, res, 'GET', '/album/' + + albumId + '/images'); + + if (!images || reject) { + rej(); + return; + } + + console.log('album', albumId, 'images', images.data.map(e => e.id)); + + const image = images.data.filter(e => e.id == result.image.id)[0]; + + + if (!image || reject) { + rej(); + return; + } + + reject = true; + console.log('the album', albumId, 'image', image.id); + res(albumId); + })); + } + + try { + result.albumId = await promiseAny(promises); + } catch(_) { + res.status(400).json({ error: "Image not found in any album" }); + return; + } + + if (!await fetchImgur(req, res, 'DELETE', '/image/' + result.image.id)) { + return; + } + + if (!await fetchImgur(req, res, 'PUT', '/album/' + + result.albumId + '/add', { 'ids[]': uploadJson.data.id })) { + return; + } + } + + if (!await fetchImgur(req, res, 'POST', '/gallery/image/' + + uploadJson.data.id, { title: req.body.name, tags: req.body.tags })) { + return; + } + + if (req.body.tags) { + const tagsData = { + 'tags': req.body.tags + }; + + if (!await fetchImgur(req, res, 'POST', '/gallery/tags/' + + uploadJson.data.id, tagsData)) { + return; + } + + for (const tag of req.body.tags.split(',')) { + if (!await fetchImgur(req, res, 'POST', '/account/me/follow/tag/' + tag, + {})) { + return; + } + } + } + + res.json(ordealResponse); + } catch(e) { + console.error(e); + res.status(500).json({ error: e.toString() }); + } +}); + +router.post('/search', async (req, res) => { + try { + if (!req.body.name) { + res.status(400).json({ error: 'Bad parameters for /imgur/search' }); + return; + } + + const results = await fetchImgur(req, res, 'GET', + '/gallery/search/time/top/1?q=' + + encodeURIComponent(req.body.name) + '&q_type=png'); + + if (!results) { + return; + } + + if (results.data.length == 0) { + res.status(404).json({ error: 'No image found' }); + return; + } + + let image = results.data[0]; + if (image.is_album) { + image = image.images[0]; + } + + if (!await fetchImgur(req, res, 'POST', '/gallery/' + results.data[0].id + + '/vote/up', {})) { + return; + } + + if (!await fetchImgur(req, res, 'POST', '/image/' + image.id + '/favorite', + {})) { + return; + } + + const fetch64res = await fetch64.remote(image.link); + + const fav = { + _id: mongoose.Types.ObjectId(), + name: req.body.name, + dataURL: fetch64res[1], + bookmarked: false, + }; + + await new Favorite(fav).save(); + eventBus.emit('favorite.created', fav); + + res.json({ success: true }); + } catch(e) { + console.error(e); + res.status(500).json({ error: e.toString() }); + } +}); + +/** router for /root */ +module.exports = router; diff --git a/hw7/Claudio_Maggioni/routes/root/router.js b/hw7/Claudio_Maggioni/routes/root/router.js index df96c14..47cf564 100644 --- a/hw7/Claudio_Maggioni/routes/root/router.js +++ b/hw7/Claudio_Maggioni/routes/root/router.js @@ -24,261 +24,5 @@ router.get('/', (req, res) => { }); }); -router.get('/imgur', (req, res) => { - if (req.query.access_token) { - req.app.locals.imgur = req.query; - res.redirect('/'); - } else { - res.status(200, {'Content-Type': 'text/html'}); - res.end(` - `); - } -}); - -async function fetchImgur(req, res, method, url, body) { - const endpoint = 'https://api.imgur.com/3'; - - const response = await fetch(endpoint + url, { - method: method, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Authorization' : 'Bearer ' + req.app.locals.imgur.access_token - }, - body: body ? querystring.stringify(body) : undefined - }); - - const json = await response.json(); - - if (json.status == 409 && url.match(/follow\/tag/)) { - return {}; - } - - if (Math.floor(json.status / 100) != 2) { - res.status(json.status).json(json); - return false; - } - - return json; -} - -router.post('/imgur/ordeal', async (req, res) => { - try { - if ((!req.body.replace && (!req.body.name || !req.body.album)) || - (req.body.replace && (!req.body.name || !req.body.oldName))) { - res.status(400).json({ error: "Malformed ordeal request" }); - return; - } - - const ordealResponse = { ordealSuccess: true }; - - const uploadData = { - image: req.body.dataURL.substring('data:image/png;base64,'.length), - type: 'base64', - title: req.body.name, - name: req.body.name + '.png', - }; - - const uploadJson = await fetchImgur(req, res, 'POST', '/upload', uploadData); - if (!uploadJson) { - return; - } - - const imageId = uploadJson.data.id; - - const albumData = { - 'ids[]': imageId, - }; - - if (!req.body.replace) { - if (req.body.album) { - albumData.title = req.body.album; - } - - const albumJson = await fetchImgur(req, res, 'POST', '/album', albumData); - if (!albumJson) { - return; - } - - if (req.body.favorites) { - if (!await fetchImgur(req, res, 'POST', '/album/' + albumJson.data.id + - '/favorite', {})) { - return; - } - } - } else { - req.body.album = undefined; - - const submissions = await fetchImgur(req, res, 'GET', - '/account/me/submissions'); - - if (!submissions) { - return; - } - - const submission = submissions.data - .filter(e => !e.images && e.in_gallery && - e.title == req.body.oldName)[0]; - - if (!submission) { - res.status(404).json({ error: "No image in submissions found" }); - return; - } - - console.log('submission', submission.id, submission.title); - - const result = {}; - result.image = submission; - ordealResponse.views = submission.views; - ordealResponse.votes = {}; - ordealResponse.votes.ups = submission.ups; - ordealResponse.votes.downs = submission.downs; - - const albumIds = await fetchImgur(req, res, 'GET', - '/account/me/albums/ids'); - - if (!albumIds) { - return; - } - - console.log('albumIds', albumIds.data.join(',')); - - let reject = false; - const promises = []; - for (const albumId of albumIds.data) { - promises.push(new Promise(async (res, rej) => { - if (reject) { - return reject; - } - - const images = await fetchImgur(req, res, 'GET', '/album/' + - albumId + '/images'); - - if (!images || reject) { - rej(); - return; - } - - console.log('album', albumId, 'images', images.data.map(e => e.id)); - - const image = images.data.filter(e => e.id == result.image.id)[0]; - - - if (!image || reject) { - rej(); - return; - } - - reject = true; - console.log('the album', albumId, 'image', image.id); - res(albumId); - })); - } - - try { - result.albumId = await promiseAny(promises); - } catch(_) { - res.status(400).json({ error: "Image not found in any album" }); - return; - } - - if (!await fetchImgur(req, res, 'DELETE', '/image/' + result.image.id)) { - return; - } - - if (!await fetchImgur(req, res, 'PUT', '/album/' + - result.albumId + '/add', { 'ids[]': uploadJson.data.id })) { - return; - } - } - - if (!await fetchImgur(req, res, 'POST', '/gallery/image/' + - uploadJson.data.id, { title: req.body.name, tags: req.body.tags })) { - return; - } - - if (req.body.tags) { - const tagsData = { - 'tags': req.body.tags - }; - - if (!await fetchImgur(req, res, 'POST', '/gallery/tags/' + - uploadJson.data.id, tagsData)) { - return; - } - - for (const tag of req.body.tags.split(',')) { - if (!await fetchImgur(req, res, 'POST', '/account/me/follow/tag/' + tag, - {})) { - return; - } - } - } - - res.json(ordealResponse); - } catch(e) { - console.error(e); - res.status(500).json({ error: e.toString() }); - } -}); - -router.post('/imgur/search', async (req, res) => { - try { - if (!req.body.name) { - res.status(400).json({ error: 'Bad parameters for /imgur/search' }); - return; - } - - const results = await fetchImgur(req, res, 'GET', '/gallery/search/time/top/1?q=' + - encodeURIComponent(req.body.name) + '&q_type=png'); - - if (!results) { - return; - } - - if (results.data.length == 0) { - res.status(404).json({ error: 'No image found' }); - return; - } - - let image = results.data[0]; - if (image.is_album) { - image = image.images[0]; - } - - if (!await fetchImgur(req, res, 'POST', '/gallery/' + results.data[0].id + - '/vote/up', {})) { - return; - } - - if (!await fetchImgur(req, res, 'POST', '/image/' + image.id + '/favorite', - {})) { - return; - } - - const fetch64res = await fetch64.remote(image.link); - - const fav = { - _id: mongoose.Types.ObjectId(), - name: req.body.name, - dataURL: fetch64res[1], - bookmarked: false, - }; - - await new Favorite(fav).save(); - eventBus.emit('favorite.created', fav); - - res.json({ success: true }); - } catch(e) { - console.error(e); - res.status(500).json({ error: e.toString() }); - } -}); - /** router for /root */ module.exports = router;