Got quick n dirty request to Spotify API working.

pull/34/head
Sander Vocke 5 years ago
parent 3d094c024b
commit e9d6d4055c
  1. 4
      client/src/components/windows/settings/IntegrationSettingsEditor.tsx
  2. 11
      client/src/lib/integration/spotify/spotify.tsx
  3. 14
      client/src/lib/integration/spotify/spotifyClientCreds.tsx
  4. 4
      server/app.ts
  5. 68
      server/integrations/spotifyClientCreds.ts
  6. 113
      server/package-lock.json
  7. 4
      server/package.json

@ -9,7 +9,7 @@ import DeleteIcon from '@material-ui/icons/Delete';
import * as serverApi from '../../../api';
import StoreLinkIcon, { ExternalStore } from '../../common/StoreLinkIcon';
import { v4 as genUuid } from 'uuid';
import { getAuthToken } from '../../../lib/integration/spotify/spotify';
import { testSpotify } from '../../../lib/integration/spotify/spotifyClientCreds';
let _ = require('lodash')
interface EditIntegrationProps {
@ -113,7 +113,7 @@ function EditIntegration(props: EditIntegrationProps) {
onClick={() => { props.onDelete(); }}
><DeleteIcon /></IconButton>}
{!props.submitting && <Button
onClick={() => { }}
onClick={testSpotify}
>Test</Button>}
{props.submitting && <CircularProgress />}
</Box >

@ -1,11 +0,0 @@
export async function getAuthToken(clientId: string, clientSecret: string) {
let requestOpts = {
method: "POST",
headers: { "Authorization": "Basic " + clientId + ":" + clientSecret },
}
const response = await fetch("https://accounts.spotify.com/api/token?grant_type=client_credentials", requestOpts)
return await response.json();
}
export default {}

@ -0,0 +1,14 @@
export async function testSpotify() {
const requestOpts = {
method: 'GET',
};
const response = await fetch(
(process.env.REACT_APP_BACKEND || "") + '/spotifycc/v1/search?q=queens&type=artist',
requestOpts
);
if (!response.ok) {
throw new Error("Response to tag merge not OK: " + JSON.stringify(response));
}
console.log("Spotify response: ", response);
}

@ -14,6 +14,7 @@ import { RegisterUser } from './endpoints/RegisterUser';
import * as endpointTypes from './endpoints/types';
import { sha512 } from 'js-sha512';
import { useSpotifyClientCreds } from './integrations/spotifyClientCreds';
// For authentication
var passport = require('passport');
@ -100,6 +101,9 @@ const SetupApp = (app: any, knex: Knex, apiBaseUrl: string) => {
}
}
// Set up integration proxies
useSpotifyClientCreds(app);
// Set up REST API endpoints
app.post(apiBaseUrl + api.CreateSongEndpoint, checkLogin(), _invoke(PostSong));
app.put(apiBaseUrl + api.ModifySongEndpoint, checkLogin(), _invoke(PutSong));

@ -1,15 +1,65 @@
const { createProxyMiddleware } = require('http-proxy-middleware');
let axios = require('axios')
let qs = require('querystring')
// The authorization token to use with the Spotify API.
// Will need to be refreshed once in a while.
let authToken: string | null = null;
var authToken: string | null = null;
async function updateToken(clientId: string, clientSecret: string) {
if (authToken) { return; }
let buf = Buffer.from(clientId + ':' + clientSecret)
let encoded = buf.toString('base64');
let response = await axios.post(
'https://accounts.spotify.com/api/token',
qs.stringify({ 'grant_type': 'client_credentials' }),
{
'headers': {
'Authorization': 'Basic ' + encoded,
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
authToken = (await response).data.access_token;
}
export async function getAuthToken(clientId: string, clientSecret: string) {
let requestOpts = {
method: "POST",
headers: { "Authorization": "Basic " + clientId + ":" + clientSecret },
}
let onProxyReq = (proxyReq: any, req: any, res: any) => {
proxyReq.setHeader("Authorization", "Bearer " + req._access_token)
const response = await fetch("https://accounts.spotify.com/api/token?grant_type=client_credentials", requestOpts)
return await response.json();
console.log("Proxying request",
{
'path': req.path,
'originalUrl': req.originalUrl,
'baseUrl': req.baseUrl,
},
{
'path': proxyReq.path,
'originalUrl': proxyReq.originalUrl,
'baseUrl': req.baseUrl,
},
);
}
export async function
export function useSpotifyClientCreds(app: any) {
// First add a layer which creates a token and saves it in the request.
app.use((req: any, res: any, next: any) => {
updateToken('c3e5e605e7814cdf94cd86eeba6f4c4f', '5d870c84a3c34aa3a4cf803aa95cb96a')
.then(() => {
req._access_token = authToken;
next();
})
})
app.use(
'/spotifycc',
createProxyMiddleware({
target: 'https://api.spotify.com/',
changeOrigin: true,
onProxyReq: onProxyReq,
logLevel: 'debug',
pathRewrite: { '^/spotifycc': '' },
})
)
}

@ -24,6 +24,14 @@
"xml2js": "^0.4.19"
},
"dependencies": {
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
@ -69,6 +77,14 @@
"resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.1.tgz",
"integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw=="
},
"@types/http-proxy": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.4.tgz",
"integrity": "sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q==",
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "14.6.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.2.tgz",
@ -304,11 +320,18 @@
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
},
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz",
"integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==",
"requires": {
"follow-redirects": "1.5.10"
"follow-redirects": "^1.10.0"
},
"dependencies": {
"follow-redirects": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
}
}
},
"balanced-match": {
@ -1034,6 +1057,11 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@ -1654,6 +1682,68 @@
"toidentifier": "1.0.0"
}
},
"http-proxy": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"requires": {
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
}
},
"http-proxy-middleware": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.0.6.tgz",
"integrity": "sha512-NyL6ZB6cVni7pl+/IT2W0ni5ME00xR0sN27AQZZrpKn1b+qRh+mLbBxIq9Cq1oGfmTc7BUq4HB77mxwCaxAYNg==",
"requires": {
"@types/http-proxy": "^1.17.4",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"lodash": "^4.17.20",
"micromatch": "^4.0.2"
},
"dependencies": {
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"requires": {
"to-regex-range": "^5.0.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@ -2474,6 +2564,11 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz",
"integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA=="
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
@ -3052,6 +3147,11 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
},
"random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
@ -3206,6 +3306,11 @@
}
}
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",

@ -8,11 +8,13 @@
"test": "ts-node node_modules/jasmine/bin/jasmine --config=test/jasmine.json"
},
"dependencies": {
"axios": "^0.21.0",
"body-parser": "^1.18.3",
"chai": "^4.2.0",
"chai-http": "^4.3.0",
"express": "^4.16.4",
"express-session": "^1.17.1",
"http-proxy-middleware": "^1.0.6",
"jasmine": "^3.5.0",
"js-sha512": "^0.8.0",
"knex": "^0.21.5",
@ -20,11 +22,13 @@
"mssql": "^6.2.1",
"mysql": "^2.18.1",
"mysql2": "^2.1.0",
"node-fetch": "^2.6.1",
"nodemon": "^2.0.4",
"oracledb": "^5.0.0",
"passport": "^0.4.1",
"passport-local": "^1.0.0",
"pg": "^8.3.3",
"querystring": "^0.2.0",
"sqlite3": "^5.0.0",
"ts-node": "^8.10.2",
"typescript": "~3.7.2"

Loading…
Cancel
Save