Adding POC lastfm authorization button

This commit is contained in:
James Barnsley
2017-11-02 21:20:56 +13:00
parent 5abb9c775a
commit 35a61686b3
13 changed files with 847 additions and 270 deletions

6
src/js/bootstrap.js vendored
View File

@ -63,7 +63,9 @@ var initialState = {
}
},
lastfm: {
connected: false
connected: false,
me: false,
authorization_url: 'https://jamesbarnsley.co.nz/auth_lastfm.php'
},
genius: {
connected: false
@ -72,7 +74,7 @@ var initialState = {
connected: false,
me: false,
autocomplete_results: {},
authorization_url: 'https://jamesbarnsley.co.nz/auth_v2.php'
authorization_url: 'https://jamesbarnsley.co.nz/auth_spotify.php'
}
};

View File

@ -0,0 +1,123 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { createStore, bindActionCreators } from 'redux'
import ReactGA from 'react-ga'
import FontAwesome from 'react-fontawesome'
import Thumbnail from './Thumbnail'
import * as uiActions from '../services/ui/actions'
import * as lastfmActions from '../services/lastfm/actions'
class LastfmAuthenticationFrame extends React.Component{
constructor(props){
super(props);
this.state = {
authorizing: false
}
}
componentDidMount(){
let self = this;
// Listen for incoming messages from the authorization iframe
// This is triggered when the popup posts a message, which is then passed to
// the iframe, and then passed on to the parent frame (our application)
window.addEventListener('message', function(event){
self.handleMessage(event)
}, false);
}
handleMessage(event){
var data = JSON.parse(event.data)
// Only allow incoming data from our authorized authenticator proxy
var authorization_domain = this.props.authorization_url.substring(0,this.props.authorization_url.indexOf('/',8))
if (event.origin != authorization_domain){
this.props.uiActions.createNotification('Authorization failed. '+event.origin+' is not the configured authorization_url.','bad')
return false
}
// Bounced with an error
if (typeof(data.error) !== 'undefined'){
this.props.uiActions.createNotification(data.error,'bad')
// No errors? We're in!
} else {
this.props.lastfmActions.authorizationGranted(data)
//this.props.lastfmActions.getMe()
}
// Turn off our authorizing switch
this.setState({authorizing: false})
}
startAuthorization(){
var self = this
this.setState({authorizing: true})
// Open an authentication request window
var url = this.props.authorization_url+'?action=authorize'
var popup = window.open(url,"popup","height=500,width=350");
// Start timer to check our popup's state
var timer = setInterval(checkPopup, 1000);
function checkPopup(){
// Popup has been closed
if (typeof(popup) !== 'undefined' && popup){
if (popup.closed){
self.setState({authorizing: false})
clearInterval(timer);
}
// Popup does not exist, so must have been blocked
} else {
self.props.uiActions.createNotification('Popup blocked. Please allow popups and try again.','bad')
self.setState({authorizing: false})
clearInterval(timer);
}
}
}
render(){
if (this.state.authorizing){
return (
<button className="working">
Authorizing...
</button>
)
} else if (this.props.authorized){
return (
<button className="destructive" onClick={() => this.props.lastfmActions.revokeAuthorization()}>Log out</button>
)
} else {
return (
<button className="primary" onClick={() => this.startAuthorization()}>Log in</button>
)
}
}
}
const mapStateToProps = (state, ownProps) => {
return {
authorization_url: state.lastfm.authorization_url,
authorized: state.lastfm.authorization,
authorizing: state.lastfm.authorizing
}
}
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch),
lastfmActions: bindActionCreators(lastfmActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(LastfmAuthenticationFrame)

View File

@ -45,6 +45,28 @@ const sendRequest = (dispatch, getState, params ) => {
})
}
export function set(data){
return {
type: 'LASTFM_SET',
data: data
}
}
/**
* Handle authorization process
**/
export function authorizationGranted(data){
data.token_expiry = new Date().getTime() + data.expires_in;
return { type: 'LASTFM_AUTHORIZATION_GRANTED', data: data }
}
export function revokeAuthorization(){
return { type: 'LASTFM_AUTHORIZATION_REVOKED' }
}
export function connect(){
return (dispatch, getState) => {

View File

@ -9,6 +9,27 @@ export default function reducer(lastfm = {}, action){
case 'LASTFM_CONNECTED':
return Object.assign({}, lastfm, { connected: true, connecting: false });
case 'LASTFM_SET':
return Object.assign({}, lastfm, action.data)
case 'LASTFM_AUTHORIZATION_GRANTED':
return Object.assign({}, lastfm, {
enabled: true,
authorizing: false,
authorization: action.data,
api_key: action.data.api_key,
token_expiry: action.data.token_expiry
})
case 'LASTFM_AUTHORIZATION_REVOKED':
return Object.assign({}, lastfm, {
authorizing: false,
authorization: false,
api_key: false,
token_expiry: 0,
me: false
})
default:
return lastfm
}

View File

@ -5,6 +5,7 @@ var helpers = require('../../helpers.js')
var coreActions = require('../core/actions.js')
var uiActions = require('../ui/actions.js')
var pusherActions = require('./actions.js')
var lastfmActions = require('../lastfm/actions.js')
var spotifyActions = require('../spotify/actions.js')
const PusherMiddleware = (function(){
@ -431,7 +432,10 @@ const PusherMiddleware = (function(){
store.dispatch(spotifyActions.set({
locale: (action.config.locale ? action.config.locale : null),
country: (action.config.country ? action.config.country : null),
authorization_url: (action.config.authorization_url ? action.config.authorization_url : null)
authorization_url: (action.config.spotify_authorization_url ? action.config.spotify_authorization_url : null)
}))
store.dispatch(lastfmActions.set({
authorization_url: (action.config.lastfm_authorization_url ? action.config.lastfm_authorization_url : null)
}))
next(action )

View File

@ -6,6 +6,7 @@ import { bindActionCreators } from 'redux'
import FontAwesome from 'react-fontawesome'
import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame'
import LastfmAuthenticationFrame from '../components/LastfmAuthenticationFrame'
import ConfirmationButton from '../components/ConfirmationButton'
import PusherConnectionList from '../components/PusherConnectionList'
import URISchemesList from '../components/URISchemesList'
@ -310,6 +311,15 @@ class Settings extends React.Component {
</div>
</div>
<h4 className="underline">LastFM</h4>
<div className="field">
<div className="name">Authorization</div>
<div className="input">
<LastfmAuthenticationFrame />
</div>
</div>
<h4 className="underline">Advanced</h4>
<div className="field checkbox">