diff --git a/client/src/api.ts b/client/src/api.ts
index 3d681e6..b4733c1 100644
--- a/client/src/api.ts
+++ b/client/src/api.ts
@@ -359,15 +359,15 @@ export const LoginEndpoint = "/login";
export const LogoutEndpoint = "/logout";
export enum IntegrationType {
- spotify = "spotify",
+ SpotifyClientCredentials = "SpotifyClientCredentials",
}
-export interface SpotifyIntegrationDetails {
+export interface SpotifyClientCredentialsDetails {
clientId: string,
clientSecret: string,
}
-export type IntegrationDetails = SpotifyIntegrationDetails;
+export type IntegrationDetails = SpotifyClientCredentialsDetails;
// Create a new integration (POST).
export const CreateIntegrationEndpoint = '/integration';
diff --git a/client/src/components/windows/settings/IntegrationSettingsEditor.tsx b/client/src/components/windows/settings/IntegrationSettingsEditor.tsx
index 6f966a5..ccfb08a 100644
--- a/client/src/components/windows/settings/IntegrationSettingsEditor.tsx
+++ b/client/src/components/windows/settings/IntegrationSettingsEditor.tsx
@@ -1,7 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import { useAuth } from '../../../lib/useAuth';
-import { Box, CircularProgress, IconButton, Typography, FormControl, Select, MenuItem, TextField, Menu } from '@material-ui/core';
-import { IntegrationDetails } from '../../../api';
+import { Box, CircularProgress, IconButton, Typography, FormControl, Select, MenuItem, TextField, Menu, Button } from '@material-ui/core';
import { getIntegrations, createIntegration, modifyIntegration, deleteIntegration } from '../../../lib/backend/integrations';
import AddIcon from '@material-ui/icons/Add';
import EditIcon from '@material-ui/icons/Edit';
@@ -10,6 +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';
let _ = require('lodash')
interface EditIntegrationProps {
@@ -22,9 +22,42 @@ interface EditIntegrationProps {
onDelete: () => void,
}
+function EditSpotifyClientCredentialsDetails(props: {
+ clientId: string,
+ clientSecret: string,
+ editing: boolean,
+ onChangeClientId: (v: string) => void,
+ onChangeClientSecret: (v: string) => void,
+}) {
+ return
+
+ Client id:
+ {props.editing ?
+ props.onChangeClientId(e.target.value)}
+ /> :
+ {props.clientId}}
+
+
+ Client secret:
+ {props.editing ?
+ props.onChangeClientSecret(e.target.value)}
+ /> :
+ {props.clientSecret}}
+
+ ;
+}
+
function EditIntegration(props: EditIntegrationProps) {
let IntegrationHeaders: Record = {
- [serverApi.IntegrationType.spotify]:
+ [serverApi.IntegrationType.SpotifyClientCredentials]:
:
{props.integration.name}}
- {props.integration.type === serverApi.IntegrationType.spotify && <>
-
- Client id:
- {props.editing ?
- props.onChange({
- ...props.integration,
- details: {
- ...props.integration.details,
- clientId: e.target.value,
- }
- }, props.editing)}
- /> :
- {props.integration.details.clientId}}
-
-
- Client secret:
- {props.editing ?
- props.onChange({
- ...props.integration,
- details: {
- ...props.integration.details,
- clientSecret: e.target.value,
- }
- }, props.editing)}
- /> :
- {props.integration.details.clientSecret}}
-
- {!props.editing && !props.submitting && { props.onChange(props.integration, true); }}
- >}
- {props.editing && !props.submitting && { props.onSubmit(); }}
- >}
- {!props.submitting && { props.onDelete(); }}
- >}
- {props.submitting && }
- >}
+ {props.integration.type === serverApi.IntegrationType.SpotifyClientCredentials &&
+ props.onChange({
+ ...props.integration,
+ details: {
+ ...props.integration.details,
+ clientId: v,
+ }
+ }, props.editing)}
+ onChangeClientSecret={(v: string) => props.onChange({
+ ...props.integration,
+ details: {
+ ...props.integration.details,
+ clientSecret: v,
+ }
+ }, props.editing)}
+ />
+ }
+ {!props.editing && !props.submitting && { props.onChange(props.integration, true); }}
+ >}
+ {props.editing && !props.submitting && { props.onSubmit(); }}
+ >}
+ {!props.submitting && { props.onDelete(); }}
+ >}
+ {!props.submitting && }
+ {props.submitting && }
}
@@ -117,7 +138,7 @@ function AddIntegrationMenu(props: {
>
@@ -176,7 +197,7 @@ export default function IntegrationSettingsEditor(props: {}) {
}
const deleteEditor = (state: EditorState) => {
- if(!state.upstreamId) {
+ if (!state.upstreamId) {
throw new Error('Cannot delete integration: has no upstream')
}
deleteIntegration(state.upstreamId).then((response: any) => {
@@ -267,7 +288,7 @@ export default function IntegrationSettingsEditor(props: {}) {
let cpy = _.cloneDeep(editors);
cpy.push({
integration: {
- type: serverApi.IntegrationType.spotify,
+ type: serverApi.IntegrationType.SpotifyClientCredentials,
details: {
clientId: '',
clientSecret: '',
diff --git a/client/src/lib/integration/spotify/spotify.tsx b/client/src/lib/integration/spotify/spotify.tsx
new file mode 100644
index 0000000..02aa5ca
--- /dev/null
+++ b/client/src/lib/integration/spotify/spotify.tsx
@@ -0,0 +1,11 @@
+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 {}
\ No newline at end of file
diff --git a/server/integrations/spotifyClientCreds.ts b/server/integrations/spotifyClientCreds.ts
new file mode 100644
index 0000000..7bcd887
--- /dev/null
+++ b/server/integrations/spotifyClientCreds.ts
@@ -0,0 +1,15 @@
+// The authorization token to use with the Spotify API.
+// Will need to be refreshed once in a while.
+let authToken: string | null = null;
+
+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 async function
\ No newline at end of file