diff --git a/README.md b/README.md index 932b59f..01441bc 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ const config = { clientSecret : 'yourClientSecret' } -const picasa = new Picasa(config) +const picasa = new Picasa() ``` API diff --git a/example/access_token.js b/example/access_token.js index 0da4eb2..73954ce 100644 --- a/example/access_token.js +++ b/example/access_token.js @@ -8,6 +8,6 @@ const code = '4/D7lZJ3L24ugIbgga_82j3JUyKdMVpXppkH3-XeMAE90' const picasa = new Picasa(config) -picasa.getAccessToken(code, (error, accessToken) => { +picasa.getAccessToken(config, code, (error, accessToken) => { console.log(error, accessToken) }) diff --git a/example/auth_url.js b/example/auth_url.js index 33e3fec..16de540 100644 --- a/example/auth_url.js +++ b/example/auth_url.js @@ -4,6 +4,6 @@ const Picasa = require('../.') const config = require('./config') // First stept -const picasa = new Picasa(config) +const picasa = new Picasa() -console.log(picasa.getAuthURL()) +console.log(picasa.getAuthURL(config)) diff --git a/example/photos.js b/example/photos.js index c229a2d..e930e06 100644 --- a/example/photos.js +++ b/example/photos.js @@ -1,12 +1,11 @@ 'use strict' const Picasa = require('../.') -const config = require('./config') // Third step const accessToken = 'ya29.ZAIXMKYXkuw_g_1BBSWfesb5YDi5JVA343G_0oH1qtjC5A6FUdsNBR6l8VOeGyUwH9QmbIc' -const picasa = new Picasa(config) +const picasa = new Picasa() picasa.getPhotos(accessToken, null, (error, photos) => { console.log(error, photos) diff --git a/src/picasa.js b/src/picasa.js index 31eb2ea..3865553 100644 --- a/src/picasa.js +++ b/src/picasa.js @@ -2,20 +2,15 @@ const querystring = require('querystring') -const request = require('./request') +const executeRequest = require('./request') -const userAuthenticationEndpoint = 'https://accounts.google.com/o/oauth2/auth' -const googleScope = 'https://picasaweb.google.com/data/' -const googleAPIhost = 'https://www.googleapis.com' -const googleAPIPath = '/oauth2/v3/token' +const GOOGLE_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth' +const GOOGLE_SCOPE = 'https://picasaweb.google.com/data/' +const GOOGLE_API_HOST = 'https://www.googleapis.com' +const GOOGLE_API_PATH = '/oauth2/v3/token' -function Picasa (config) { - this.clientId = config.clientId - this.redirectURI = config.redirectURI - this.clientSecret = config.clientSecret - - this.executeRequest = request.executeRequest - this.picasaRequest = request.picasaRequest +function Picasa () { + this.executeRequest = executeRequest } Picasa.prototype.getPhotos = getPhotos @@ -24,7 +19,9 @@ Picasa.prototype.getAuthURL = getAuthURL Picasa.prototype.getAccessToken = getAccessToken function getPhotos (accessToken, options, callback) { - this.picasaRequest(accessToken, 'get', 'photo', options, (error, body) => { + const requestOptions = buildPicasaRequestOptions(accessToken, 'photo', options) + + this.executeRequest('get', requestOptions, (error, body) => { if (error) return callback(error) const photoSchema = { @@ -60,43 +57,32 @@ function getPhotos (accessToken, options, callback) { }) } -function checkParam (param) { - if (!param) return '' - if (isValidType(param)) return param - else if (isValidType(param['$t'])) return param['$t'] - else return param -} - -function isValidType (value) { - return typeof value === 'string' || typeof value === 'number' -} - -function getAuthURL () { +function getAuthURL (config) { const authenticationParams = { access_type : 'offline', - scope : googleScope, + scope : GOOGLE_SCOPE, response_type : 'code', - client_id : this.clientId, - redirect_uri : this.redirectURI + client_id : config.clientId, + redirect_uri : config.redirectURI } const authenticationQuery = querystring.stringify(authenticationParams) - return `${userAuthenticationEndpoint}?${authenticationQuery}` + return `${GOOGLE_AUTH_ENDPOINT}?${authenticationQuery}` } -function getAccessToken (code, callback) { +function getAccessToken (config, code, callback) { const accessTokenParams = { grant_type : 'authorization_code', code : code, - redirect_uri : this.redirectURI, - client_id : this.clientId, - client_secret : this.clientSecret + redirect_uri : config.redirectURI, + client_id : config.clientId, + client_secret : config.clientSecret } const accessTokenQuery = querystring.stringify(accessTokenParams) const options = { - url : `${googleAPIhost}${googleAPIPath}?${accessTokenQuery}` + url : `${GOOGLE_API_HOST}${GOOGLE_API_PATH}?${accessTokenQuery}` } this.executeRequest('post', options, (error, body) => { @@ -106,4 +92,40 @@ function getAccessToken (code, callback) { }) } +function buildPicasaRequestOptions (accessToken, kind, options) { + const host = 'https://picasaweb.google.com' + const path = '/data/feed/api/user/default' + const fetchKind = 'json' + + const accessTokenParams = { + alt : fetchKind, + kind : kind, + access_token : accessToken + } + + options = options || {} + + if (options.maxResults) accessTokenParams['max-results'] = options.maxResults + + const accessTokenQuery = querystring.stringify(accessTokenParams) + + return { + url : `${host}${path}?${accessTokenQuery}`, + headers: { + 'GData-Version': '2' + } + } +} + +function checkParam (param) { + if (param === undefined) return '' + else if (isValidType(param)) return param + else if (isValidType(param['$t'])) return param['$t'] + else return param +} + +function isValidType (value) { + return typeof value === 'string' || typeof value === 'number' +} + module.exports = Picasa diff --git a/src/picasa.test.js b/src/picasa.test.js index f1f9029..504b7b3 100644 --- a/src/picasa.test.js +++ b/src/picasa.test.js @@ -18,62 +18,81 @@ describe('Picasa', () => { clientSecret : 'client_secretABC' } - beforeEach(() => { - picasa = new Picasa(config) - }) + beforeEach(() => picasa = new Picasa()) describe('getPhotos', () => { describe('on success', () => { - beforeEach(() => { - const body = { - "feed":{ - "entry":[ - { - "id":{ - "$t":"https://picasaweb.google.com/data/entry/user/11111/albumid/1111/photoid/11111" - }, - "published":{ - "$t":"2015-11-28T07:13:31.000Z" - }, - "updated":{ - "$t":"2015-11-28T07:22:35.478Z" - }, - "app$edited":{ - "$t":"2015-11-28T07:22:35.478Z" - }, - "title":{ - "$t":"IMG_0327.JPG" - }, - "summary":{ - "$t":"" - }, - "content":{ - "type":"image/jpeg", - "src":"https://lh3.googleusercontent.com/-1111111/1111/11111/1111/IMG_0327.JPG" - } + const fakeSuccessBody = { + "feed":{ + "entry":[ + { + "id":{ + "$t":"https://picasaweb.google.com/data/entry/user/11111/albumid/1111/photoid/11111" + }, + "published":{ + "$t":"2015-11-28T07:13:31.000Z" + }, + "updated":{ + "$t":"2015-11-28T07:22:35.478Z" + }, + "app$edited":{ + "$t":"2015-11-28T07:22:35.478Z" + }, + "title":{ + "$t":"IMG_0327.JPG" + }, + "summary":{ + "$t":"" + }, + "content":{ + "type":"image/jpeg", + "src":"https://lh3.googleusercontent.com/-1111111/1111/11111/1111/IMG_0327.JPG" } - ] - } + } + ] } + } - stub = sinon.stub(picasa, 'picasaRequest') - stub.callsArgWithAsync(4, null, body) + let photos + + beforeEach((done) => { + stub = sinon.stub(picasa, 'executeRequest') + stub.callsArgWithAsync(2, null, fakeSuccessBody) + + const accessToken = 'ya29.OwJqqa1Y2tivkkCWWvA8vt5ltKsdf9cDQ5IRNrTbIt-mcfr5xNj4dQu41K6hZa7lX9O-gw' + + picasa.getPhotos(accessToken, { maxResults : 1 }, (error, photosResponse) => { + expect(error).to.be.equals(null) + photos = photosResponse + + done() + }) }) afterEach(() => stub.restore()) - it('returns an array of photos', (done) => { - const accessToken = 'ya29.OwJqqa1Y2tivkkCWWvA8vt5ltKsdf9cDQ5IRNrTbIt-mcfr5xNj4dQu41K6hZa7lX9O-gw' + it('returns an array of photos', () => { + expect(photos).to.be.an('Array') + }) - picasa.getPhotos(accessToken, { maxResults : 1 }, (error, photos) => { - expect(error).to.be.equals(null) + it('returns a photo with its props', () => { + expect(photos[0].title).to.be.equals('IMG_0327.JPG') + expect(photos[0].content.src).to.contain('IMG_0327.JPG') + expect(photos[0].content.type).to.be.equals('image/jpeg') + }) + it('should make get request', () => { + const firstArgument = stub.args[0][0] - expect(photos[0].title).to.be.equals('IMG_0327.JPG') - expect(photos[0].content.src).to.contain('IMG_0327.JPG') - expect(photos[0].content.type).to.be.equals('image/jpeg') + expect(firstArgument).to.be.eql('get') + }) - done() + it('should add header and prepared URL to request', () => { + const secondArgument = stub.args[0][1] + + expect(secondArgument).to.be.eql({ + headers : { 'GData-Version': "2" }, + url : "https://picasaweb.google.com/data/feed/api/user/default?alt=json&kind=photo&access_token=ya29.OwJqqa1Y2tivkkCWWvA8vt5ltKsdf9cDQ5IRNrTbIt-mcfr5xNj4dQu41K6hZa7lX9O-gw&max-results=1" }) }) }) @@ -81,14 +100,14 @@ describe('Picasa', () => { describe('getAuthURL', () => { it('returns valid URI', () => { - expect(picasa.getAuthURL()) + expect(picasa.getAuthURL(config)) .to.be.equals('https://accounts.google.com/o/oauth2/auth?access_type=offline&scope=https%3A%2F%2Fpicasaweb.google.com%2Fdata%2F&response_type=code&client_id=apps.google.com&redirect_uri=http%3A%2F%2Flocalhost') }) }) describe('getAccessToken', () => { beforeEach(() => { - const body = { + const fakeBody = { access_token : 'ya29.KwLDeXsw1jNAavZ8jEMFgikhDg_CnUX1oMr5RQUyeqTBf229YV4HzhhXvRgBBvFGqTqxdw', token_type : 'Bearer', expires_in : 3580 @@ -96,13 +115,13 @@ describe('Picasa', () => { stub = sinon.stub(picasa, 'executeRequest') - stub.callsArgWithAsync(2, null, body) + stub.callsArgWithAsync(2, null, fakeBody) }) afterEach(() => stub.restore()) it('returns access token response', (done) => { - picasa.getAccessToken('4/DxoCTw8Rf3tQAAW94h6lK7ioEjnu6K8kEqVZ0d-cRA8', (error, accessToken) => { + picasa.getAccessToken(config, '4/DxoCTw8Rf3tQAAW94h6lK7ioEjnu6K8kEqVZ0d-cRA8', (error, accessToken) => { expect(stub).to.have.been.calledWith('post', { url : 'https://www.googleapis.com/oauth2/v3/token?grant_type=authorization_code&code=4%2FDxoCTw8Rf3tQAAW94h6lK7ioEjnu6K8kEqVZ0d-cRA8&redirect_uri=http%3A%2F%2Flocalhost&client_id=apps.google.com&client_secret=client_secretABC' }) expect(error).to.be.equal(null) diff --git a/src/request.js b/src/request.js index 1830625..6ca9042 100644 --- a/src/request.js +++ b/src/request.js @@ -3,32 +3,6 @@ const querystring = require('querystring') let request = require('request') -function picasaRequest (accessToken, method, kind, options, callback) { - const host = 'https://picasaweb.google.com' - const path = '/data/feed/api/user/default' - const fetchKind = 'json' - - const accessTokenParams = { - alt : fetchKind, - kind : kind, - access_token : accessToken - } - - options = options || {} - - if (options.maxResults) accessTokenParams['max-results'] = options.maxResults - - const accessTokenQuery = querystring.stringify(accessTokenParams) - const requestOptions = { - url : `${host}${path}?${accessTokenQuery}`, - headers: { - 'GData-Version': '2' - } - } - - executeRequest(method, requestOptions, callback) -} - function executeRequest (method, requestOptions, callback) { request[method](requestOptions, (error, response, body) => { if (error) return callback(error) @@ -51,7 +25,4 @@ function executeRequest (method, requestOptions, callback) { }) } -module.exports = { - picasaRequest : picasaRequest, - executeRequest : executeRequest -} +module.exports = executeRequest diff --git a/src/request.test.js b/src/request.test.js index c3155be..e12444d 100644 --- a/src/request.test.js +++ b/src/request.test.js @@ -23,36 +23,8 @@ describe('request', () => { }) }) - describe('picasaRequest', () => { - const picasaRequest = request.picasaRequest - - beforeEach((done) => { - stubExecuteRequest = sinon.stub() - - request.__set__('executeRequest', stubExecuteRequest) - stubExecuteRequest.callsArgWithAsync(2, null, 'aaaaa') - - picasaRequest('aaaaa', 'post', 'photos',{}, done) - }) - - it('should request verb given', () => { - const firstArgument = stubExecuteRequest.args[0][0] - - expect(firstArgument).to.be.eql('post') - }) - - it('should prepare header and url with access token given', () => { - const secondArgument = stubExecuteRequest.args[0][1] - - expect(secondArgument).to.be.eql({ - headers : { 'GData-Version': "2" }, - url : "https://picasaweb.google.com/data/feed/api/user/default?alt=json&kind=photos&access_token=aaaaa" - }) - }) - }) - describe('executeRequest', () => { - const executeRequest = request.executeRequest + const executeRequest = request describe('on status code different than 200', () => { describe('on error 403', () => {