integrated spotify auth/deauth, adding parts to playlist
This commit is contained in:
parent
6617160c75
commit
e3615d0ccf
@ -2,6 +2,8 @@ from flask import Blueprint, session, request, jsonify
|
||||
from google.cloud import firestore
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
import spotify.api.database as database
|
||||
|
||||
blueprint = Blueprint('api', __name__)
|
||||
db = firestore.Client()
|
||||
|
||||
@ -11,15 +13,9 @@ def get_playlists():
|
||||
|
||||
if 'username' in session:
|
||||
|
||||
users = db.collection(u'spotify_users').where(u'username', u'==', session['username']).stream()
|
||||
pulled_user = database.get_user_doc_ref(session['username'])
|
||||
|
||||
users = [i for i in users]
|
||||
|
||||
if len(users) == 1:
|
||||
playlists = db.document(u'spotify_users/{}'.format(users[0].id)).collection(u'playlists')
|
||||
else:
|
||||
error = {'error': 'multiple usernames?'}
|
||||
return jsonify(error), 500
|
||||
playlists = database.get_user_playlists_collection(pulled_user.id)
|
||||
|
||||
response = {
|
||||
'playlists': [i.to_dict() for i in playlists.stream()]
|
||||
@ -28,8 +24,7 @@ def get_playlists():
|
||||
return jsonify(response), 200
|
||||
|
||||
else:
|
||||
error = {'error': 'not logged in'}
|
||||
return jsonify(error), 401
|
||||
return jsonify({'error': 'not logged in'}), 401
|
||||
|
||||
|
||||
@blueprint.route('/playlist', methods=['GET', 'POST', 'PUT'])
|
||||
@ -37,33 +32,25 @@ def get_playlist():
|
||||
|
||||
if 'username' in session:
|
||||
|
||||
users = db.collection(u'spotify_users').where(u'username', u'==', session['username']).stream()
|
||||
|
||||
users = [i for i in users]
|
||||
|
||||
if len(users) == 1:
|
||||
playlists = db.document(u'spotify_users/{}'.format(users[0].id)).collection(u'playlists')
|
||||
else:
|
||||
error = {'error': 'multiple usernames?'}
|
||||
return jsonify(error), 500
|
||||
user_ref = database.get_user_doc_ref(session['username'])
|
||||
playlists = database.get_user_playlists_collection(user_ref.id)
|
||||
|
||||
if request.method == 'GET':
|
||||
playlist_name = request.args.get('name', None)
|
||||
|
||||
if playlist_name:
|
||||
|
||||
playlist = [i for i in playlists.where(u'name', u'==', playlist_name).stream()]
|
||||
queried_playlist = [i for i in playlists.where(u'name', u'==', playlist_name).stream()]
|
||||
|
||||
if len(playlist) == 0:
|
||||
if len(queried_playlist) == 0:
|
||||
return jsonify({'error': 'no playlist found'}), 404
|
||||
elif len(playlist) > 1:
|
||||
elif len(queried_playlist) > 1:
|
||||
return jsonify({'error': 'multiple playlists found'}), 500
|
||||
|
||||
return jsonify(playlist[0].to_dict()), 200
|
||||
return jsonify(queried_playlist[0].to_dict()), 200
|
||||
|
||||
else:
|
||||
response = {"error": 'no name requested'}
|
||||
return jsonify(response), 400
|
||||
return jsonify({"error": 'no name requested'}), 400
|
||||
|
||||
elif request.method == 'POST' or request.method == 'PUT':
|
||||
|
||||
@ -73,12 +60,54 @@ def get_playlist():
|
||||
return jsonify({'error': "no name provided"}), 400
|
||||
|
||||
playlist_name = request_json['name']
|
||||
playlist_parts = request_json.get('parts', None)
|
||||
playlist_id = request_json.get('id', None)
|
||||
|
||||
return 404
|
||||
queried_playlist = [i for i in playlists.where(u'name', u'==', playlist_name).stream()]
|
||||
|
||||
if request.method == 'PUT':
|
||||
|
||||
if len(queried_playlist) != 0:
|
||||
return jsonify({'error': 'playlist already exists'}), 400
|
||||
|
||||
if playlist_parts is None or playlist_id is None:
|
||||
return jsonify({'error': 'parts and id required'}), 400
|
||||
|
||||
playlists.add({
|
||||
'name': playlist_name,
|
||||
'parts': playlist_parts,
|
||||
'playlist_id': playlist_id
|
||||
})
|
||||
|
||||
return jsonify({"message": 'playlist added', "status": "success"}), 200
|
||||
|
||||
else:
|
||||
|
||||
if len(queried_playlist) == 0:
|
||||
return jsonify({'error': "playlist doesn't exist"}), 400
|
||||
|
||||
if len(queried_playlist) > 1:
|
||||
return jsonify({'error': "multiple playlists exist"}), 500
|
||||
|
||||
if playlist_parts is None and playlist_id is None:
|
||||
return jsonify({'error': "no chnages to make"}), 400
|
||||
|
||||
playlist_doc = playlists.document(queried_playlist[0].id)
|
||||
|
||||
dic = {}
|
||||
|
||||
if playlist_parts:
|
||||
dic['parts'] = playlist_parts
|
||||
|
||||
if playlist_id:
|
||||
dic['playlist_id'] = playlist_id
|
||||
|
||||
playlist_doc.update(dic)
|
||||
|
||||
return jsonify({"message": 'playlist updated', "status": "success"}), 200
|
||||
|
||||
else:
|
||||
error = {'error': 'not logged in'}
|
||||
return jsonify(error), 401
|
||||
return jsonify({'error': 'not logged in'}), 401
|
||||
|
||||
|
||||
@blueprint.route('/user', methods=['GET'])
|
||||
@ -86,28 +115,19 @@ def user():
|
||||
|
||||
if 'username' in session:
|
||||
|
||||
users = db.collection(u'spotify_users').where(u'username', u'==', session['username']).stream()
|
||||
users = [i for i in users]
|
||||
|
||||
if len(users) == 1:
|
||||
pulled_user = db.collection(u'spotify_users').document(u'{}'.format(users[0].id)).get()
|
||||
else:
|
||||
error = {'error': 'multiple usernames?'}
|
||||
return jsonify(error), 500
|
||||
|
||||
doc = pulled_user.to_dict()
|
||||
pulled_user = database.get_user_doc_ref(session['username']).get().to_dict()
|
||||
|
||||
response = {
|
||||
'username': doc['username'],
|
||||
'type': doc['type'],
|
||||
'validated': doc['validated']
|
||||
'username': pulled_user['username'],
|
||||
'type': pulled_user['type'],
|
||||
'spotify_linked': pulled_user['spotify_linked'],
|
||||
'validated': pulled_user['validated']
|
||||
}
|
||||
|
||||
return jsonify(response), 200
|
||||
|
||||
else:
|
||||
error = {'error': 'not logged in'}
|
||||
return jsonify(error), 401
|
||||
return jsonify({'error': 'not logged in'}), 401
|
||||
|
||||
|
||||
@blueprint.route('/user/password', methods=['POST'])
|
||||
@ -120,21 +140,12 @@ def change_password():
|
||||
if 'new_password' in request_json and 'current_password' in request_json:
|
||||
|
||||
if len(request_json['new_password']) == 0:
|
||||
response = {"error": 'zero length password'}
|
||||
return jsonify(response), 400
|
||||
return jsonify({"error": 'zero length password'}), 400
|
||||
|
||||
if len(request_json['new_password']) > 30:
|
||||
response = {"error": 'password too long'}
|
||||
return jsonify(response), 400
|
||||
return jsonify({"error": 'password too long'}), 400
|
||||
|
||||
users = db.collection(u'spotify_users').where(u'username', u'==', session['username']).stream()
|
||||
users = [i for i in users]
|
||||
|
||||
if len(users) == 1:
|
||||
current_user = db.collection(u'spotify_users').document(u'{}'.format(users[0].id))
|
||||
else:
|
||||
error = {'error': 'multiple usernames?'}
|
||||
return jsonify(error), 500
|
||||
current_user = database.get_user_doc_ref(session['username'])
|
||||
|
||||
if check_password_hash(current_user.get().to_dict()['password'], request_json['current_password']):
|
||||
|
||||
@ -144,18 +155,10 @@ def change_password():
|
||||
return jsonify(response), 200
|
||||
|
||||
else:
|
||||
error = {'error': 'wrong password provided'}
|
||||
return jsonify(error), 403
|
||||
return jsonify({'error': 'wrong password provided'}), 403
|
||||
|
||||
else:
|
||||
error = {'error': 'malformed request, no old_password/new_password'}
|
||||
return jsonify(error), 400
|
||||
return jsonify({'error': 'malformed request, no old_password/new_password'}), 400
|
||||
|
||||
else:
|
||||
error = {'error': 'not logged in'}
|
||||
return jsonify(error), 401
|
||||
|
||||
|
||||
@blueprint.route('/playlist', methods=['GET', 'PUT', 'POST'])
|
||||
def playlist():
|
||||
return 401
|
||||
return jsonify({'error': 'not logged in'}), 401
|
||||
|
32
spotify/api/database.py
Normal file
32
spotify/api/database.py
Normal file
@ -0,0 +1,32 @@
|
||||
from google.cloud import firestore
|
||||
db = firestore.Client()
|
||||
|
||||
|
||||
def get_user_query_stream(user):
|
||||
|
||||
users = db.collection(u'spotify_users').where(u'username', u'==', user).stream()
|
||||
users = [i for i in users]
|
||||
|
||||
return users
|
||||
|
||||
|
||||
def get_user_doc_ref(user):
|
||||
|
||||
users = get_user_query_stream(user)
|
||||
|
||||
if len(users) == 1:
|
||||
|
||||
return db.collection(u'spotify_users').document(u'{}'.format(users[0].id))
|
||||
|
||||
else:
|
||||
print(len(users))
|
||||
raise ValueError
|
||||
|
||||
|
||||
def get_user_playlists_collection(user_id):
|
||||
|
||||
playlists = db.document(u'spotify_users/{}'.format(user_id)).collection(u'playlists')
|
||||
|
||||
return playlists
|
||||
|
||||
|
@ -2,6 +2,13 @@ from flask import Blueprint, session, flash, request, redirect, url_for
|
||||
from google.cloud import firestore
|
||||
from werkzeug.security import check_password_hash
|
||||
|
||||
import urllib
|
||||
import datetime
|
||||
from base64 import b64encode
|
||||
import requests
|
||||
|
||||
import spotify.api.database as database
|
||||
|
||||
blueprint = Blueprint('authapi', __name__)
|
||||
|
||||
db = firestore.Client()
|
||||
@ -17,9 +24,7 @@ def login():
|
||||
username = request.form['username'].lower()
|
||||
password = request.form['password']
|
||||
|
||||
users = db.collection(u'spotify_users').where(u'username', u'==', username).stream()
|
||||
|
||||
users = [i for i in users]
|
||||
users = database.get_user_query_stream(username)
|
||||
|
||||
if len(users) == 0:
|
||||
flash('user not found')
|
||||
@ -35,6 +40,10 @@ def login():
|
||||
return redirect(url_for('index'))
|
||||
|
||||
if check_password_hash(doc['password'], password):
|
||||
|
||||
user_reference = db.collection(u'spotify_users').document(u'{}'.format(users[0].id))
|
||||
user_reference.update({'last_login': datetime.datetime.utcnow()})
|
||||
|
||||
session['username'] = username
|
||||
return redirect(url_for('app_route'))
|
||||
else:
|
||||
@ -50,3 +59,79 @@ def logout():
|
||||
session.pop('username', None)
|
||||
flash('logged out')
|
||||
return redirect(url_for('index'))
|
||||
|
||||
|
||||
@blueprint.route('/spotify')
|
||||
def auth():
|
||||
|
||||
if 'username' in session:
|
||||
|
||||
client_id = db.document('key/spotify').get().to_dict()['clientid']
|
||||
params = urllib.parse.urlencode(
|
||||
{
|
||||
'client_id': client_id,
|
||||
'response_type': 'code',
|
||||
'scope': 'playlist-modify-public playlist-modify-private playlist-read-private',
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/auth/spotify/token'
|
||||
}
|
||||
)
|
||||
|
||||
return redirect(urllib.parse.urlunparse(['https', 'accounts.spotify.com', 'authorize', '', params, '']))
|
||||
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@blueprint.route('/spotify/token')
|
||||
def token():
|
||||
|
||||
if 'username' in session:
|
||||
|
||||
code = request.args.get('code', None)
|
||||
if code is None:
|
||||
error = request.args.get('error', None)
|
||||
print('error')
|
||||
else:
|
||||
app_credentials = db.document('key/spotify').get().to_dict()
|
||||
|
||||
idsecret = b64encode(bytes(app_credentials['clientid'] + ':' + app_credentials['clientsecret'], "utf-8")).decode("ascii")
|
||||
headers = {'Authorization': 'Basic %s' % idsecret}
|
||||
|
||||
data = {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/auth/spotify/token'
|
||||
}
|
||||
|
||||
req = requests.post('https://accounts.spotify.com/api/token', data=data, headers=headers)
|
||||
|
||||
resp = req.json()
|
||||
|
||||
user_reference = database.get_user_doc_ref(session['username'])
|
||||
|
||||
user_reference.update({
|
||||
'access_token': resp['access_token'],
|
||||
'refresh_token': resp['refresh_token'],
|
||||
'spotify_linked': True
|
||||
})
|
||||
|
||||
return redirect('/app/settings/spotify')
|
||||
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@blueprint.route('/spotify/deauth')
|
||||
def deauth():
|
||||
|
||||
if 'username' in session:
|
||||
|
||||
user_reference = database.get_user_doc_ref(session['username'])
|
||||
|
||||
user_reference.update({
|
||||
'access_token': None,
|
||||
'refresh_token': None,
|
||||
'spotify_linked': False
|
||||
})
|
||||
|
||||
return redirect('/app/settings/spotify')
|
||||
|
||||
return redirect('/')
|
||||
|
@ -1,11 +1,7 @@
|
||||
from flask import Flask, render_template, redirect, request, session, flash, url_for
|
||||
from google.cloud import firestore
|
||||
import requests
|
||||
|
||||
from base64 import b64encode
|
||||
|
||||
import os
|
||||
import urllib
|
||||
|
||||
from spotify.auth import auth_blueprint
|
||||
from spotify.api import api_blueprint
|
||||
@ -24,51 +20,6 @@ def index():
|
||||
return render_template('index.html')
|
||||
|
||||
|
||||
@app.route('/spotify/auth')
|
||||
def auth():
|
||||
|
||||
client_id = db.document('key/spotify').get().to_dict()['clientid']
|
||||
params = urllib.parse.urlencode(
|
||||
{
|
||||
'client_id': client_id,
|
||||
'response_type': 'code',
|
||||
'scope': 'playlist-modify-public playlist-modify-private playlist-read-private',
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/token'
|
||||
}
|
||||
)
|
||||
|
||||
return redirect(urllib.parse.urlunparse(['https', 'accounts.spotify.com', 'authorize', '', params, '']))
|
||||
|
||||
|
||||
@app.route('/token')
|
||||
def token():
|
||||
|
||||
code = request.args.get('code', None)
|
||||
if code is None:
|
||||
error = request.args.get('error', None)
|
||||
print('error')
|
||||
else:
|
||||
app_credentials = db.document('key/spotify').get().to_dict()
|
||||
|
||||
idsecret = b64encode(bytes(app_credentials['clientid'] + ':' + app_credentials['clientsecret'], "utf-8")).decode("ascii")
|
||||
headers = {'Authorization': 'Basic %s' % idsecret}
|
||||
|
||||
data = {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/token'
|
||||
}
|
||||
|
||||
req = requests.post('https://accounts.spotify.com/api/token', data=data, headers=headers)
|
||||
|
||||
resp = req.json()
|
||||
# print(str(req.status_code) + str(resp))
|
||||
|
||||
# if 200 <= req.status_code < 300:
|
||||
|
||||
return redirect('/app')
|
||||
|
||||
|
||||
@app.route('/app', defaults={'path': ''})
|
||||
@app.route('/app/<path:path>')
|
||||
def app_route(path):
|
||||
|
@ -22,7 +22,7 @@ class Index extends Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
return <p>index</p>;
|
||||
return <h1 className="center-text">welcome to playlist manager!</h1>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,97 @@
|
||||
import React, { Component } from "react";
|
||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||
const axios = require('axios');
|
||||
|
||||
class PlaylistView extends Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
console.log(this.props);
|
||||
console.log(this.props.match.params.name);
|
||||
this.state = {
|
||||
name: this.props.match.name
|
||||
name: this.props.match.params.name,
|
||||
parts: [],
|
||||
error: false,
|
||||
error_text: null,
|
||||
add_part_value: ''
|
||||
}
|
||||
this.handleAddPart = this.handleAddPart.bind(this);
|
||||
this.handleAddPartChange = this.handleAddPartChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.getPlaylistInfo();
|
||||
}
|
||||
|
||||
getPlaylistInfo(){
|
||||
axios.get(`/api/playlist?name=${ this.state.name }`)
|
||||
.then((response) => {
|
||||
this.setState(response.data);
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
error: true,
|
||||
error_text: "error pulling playlist info"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleAddPartChange(event){
|
||||
this.setState({
|
||||
add_part_value: event.target.value
|
||||
});
|
||||
}
|
||||
|
||||
handleAddPart(event){
|
||||
var parts = this.state.parts;
|
||||
parts.push(this.state.add_part_value);
|
||||
this.setState({
|
||||
parts: parts
|
||||
});
|
||||
axios.post('/api/playlist', {
|
||||
name: this.state.name,
|
||||
parts: parts
|
||||
}).then((response) => {
|
||||
console.log(reponse);
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
return <p>{this.state.name}</p>;
|
||||
|
||||
const table = (
|
||||
<table className="app-table max-width">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan="2"><h1>{ this.state.name }</h1></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ this.state.parts.map((part) => <Row part={ part } key={ part }/>) }
|
||||
<tr>
|
||||
<td>
|
||||
<input type="text" className="full-width" value={this.state.add_part_value} onChange={this.handleAddPartChange}></input>
|
||||
</td>
|
||||
<td>
|
||||
<button className="button full-width" onClick={this.handleAddPart}>add</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
const error = <p style={{textAlign: "center"}}>{ this.state.error_text }</p>;
|
||||
|
||||
return this.state.error ? error : table;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PlaylistView
|
||||
function Row (props) {
|
||||
return (
|
||||
<tr>
|
||||
<td className="ui-text center-text">{ props.part }</td>
|
||||
<td className="ui-text center-text">remove</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default PlaylistView;
|
@ -16,7 +16,8 @@ class PlaylistManager extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
type: null
|
||||
type: null,
|
||||
spotify_linked: null
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +38,8 @@ class PlaylistManager extends Component {
|
||||
})
|
||||
.then((response) => {
|
||||
self.setState({
|
||||
type: response.data.type
|
||||
type: response.data.type,
|
||||
spotify_linked: response.data.spotify_linked
|
||||
})
|
||||
});
|
||||
}
|
||||
@ -61,7 +63,7 @@ class PlaylistManager extends Component {
|
||||
<Switch>
|
||||
<Route path="/app" exact component={Index} />
|
||||
<Route path="/app/playlists" exact component={Playlists} />
|
||||
<Route path="/app/settings" component={Settings} />
|
||||
<Route path="/app/settings" render={(props) => <Settings {...props} spotify_linked={this.state.spotify_linked}/>} />
|
||||
{ this.state.type == 'admin' && <Route path="/app/admin" component={Admin} /> }
|
||||
<Route path='/app/playlist/:name' component={PlaylistView} />
|
||||
<Route component={NotFound} />
|
||||
|
@ -79,10 +79,14 @@ class ChangePassword extends Component {
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
<h1>change password</h1>
|
||||
<div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<table className="app-table max-width">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan="2"><h1>change password</h1></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="ui-text center-text">current:</td>
|
||||
@ -117,7 +121,7 @@ class ChangePassword extends Component {
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
{ this.state.error && <p style={{color: "red"}}>{this.state.errorValue}</p>}
|
||||
{ this.state.error && <p style={{color: "red"}} className="center-text">{this.state.errorValue}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { Component } from "react";
|
||||
import { BrowserRouter as Router, Route, Link, Switch, Redirect} from "react-router-dom";
|
||||
|
||||
import ChangePassword from "./ChangePassword.js"
|
||||
import ChangePassword from "./ChangePassword.js";
|
||||
import SpotifyLink from "./SpotifyLink.js";
|
||||
|
||||
class Settings extends Component {
|
||||
|
||||
@ -10,9 +11,11 @@ class Settings extends Component {
|
||||
<div>
|
||||
<ul className="navbar" style={{width: "100%"}}>
|
||||
<li><Link to={`${this.props.match.url}/password`}>password</Link></li>
|
||||
<li><Link to={`${this.props.match.url}/spotify`}>spotify</Link></li>
|
||||
</ul>
|
||||
|
||||
<Route path={`${this.props.match.url}/password`} component={ChangePassword} />
|
||||
<Route path={`${this.props.match.url}/spotify`} render={(props) => <SpotifyLink {...props} spotify_linked={this.props.spotify_linked}/>} />
|
||||
|
||||
</div>
|
||||
);
|
||||
|
50
src/js/Settings/SpotifyLink.js
Normal file
50
src/js/Settings/SpotifyLink.js
Normal file
@ -0,0 +1,50 @@
|
||||
import React, { Component } from "react";
|
||||
const axios = require('axios');
|
||||
|
||||
class SpotifyLink extends Component {
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
spotify_linked: props.spotify_linked
|
||||
}
|
||||
}
|
||||
|
||||
getUserInfo(){
|
||||
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<table className="app-table max-width">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><h1 className="ui-text center-text">spotify link status</h1></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="ui-text center-text">
|
||||
status: { this.state.spotify_linked ? "linked" : "unlinked" }
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{ this.state.spotify_linked ? <DeAuthButton /> : <AuthButton /> }
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function AuthButton(props) {
|
||||
return <a className="button full-width" href="/auth/spotify">auth</a>;
|
||||
}
|
||||
|
||||
function DeAuthButton(props) {
|
||||
return <a className="button full-width" href="/auth/spotify/deauth">de-auth</a>;
|
||||
}
|
||||
|
||||
export default SpotifyLink;
|
Loading…
Reference in New Issue
Block a user