diff --git a/build_tools/auth_spotify.php b/build_tools/auth_spotify.php index cb774118..205a1cdb 100755 --- a/build_tools/auth_spotify.php +++ b/build_tools/auth_spotify.php @@ -1,5 +1,4 @@ $_GET["error"], + "origin" => "auth_spotify" + ); - // Pass our error back to the popup opener - ?> - - + + { return { authorization_url: state.lastfm.authorization_url, - authorized: state.lastfm.authorization, + authorized: state.lastfm.session, authorizing: state.lastfm.authorizing } } diff --git a/src/js/components/SpotifyAuthenticationFrame.js b/src/js/components/SpotifyAuthenticationFrame.js index aefa4aa9..86a74d6a 100755 --- a/src/js/components/SpotifyAuthenticationFrame.js +++ b/src/js/components/SpotifyAuthenticationFrame.js @@ -21,20 +21,20 @@ class SpotifyAuthenticationFrame extends React.Component{ } 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) + // Listen for incoming messages from the authorization popup window.addEventListener('message', function(event){ - self.handleMessage(event) + var data = JSON.parse(event.data); + + // Only digest messages relevant to us + if (data.origin == 'auth_spotify'){ + self.handleMessage(event, data); + } }, false); } - handleMessage(event){ - - var data = JSON.parse(event.data) + handleMessage(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)) @@ -44,7 +44,7 @@ class SpotifyAuthenticationFrame extends React.Component{ } // Spotify bounced with an error - if (typeof(data.error) !== 'undefined'){ + if (data.error !== undefined){ this.props.uiActions.createNotification(data.error,'bad') // No errors? We're in! @@ -80,7 +80,7 @@ class SpotifyAuthenticationFrame extends React.Component{ 'playlist-read-collaborative', 'ugc-image-upload' // playlist image uploading ] - var popup = window.open(url+'&scope='+scopes.join('%20'),"popup","height=500,width=350"); + var popup = window.open(url+'&scope='+scopes.join('%20'),"popup","height=580,width=350"); // Start timer to check our popup's state var timer = setInterval(checkPopup, 1000); diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index 63326fe8..3559a18f 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -97,6 +97,7 @@ const CoreMiddleware = (function(){ case 'CORE_START_SERVICES': store.dispatch(mopidyActions.connect()); store.dispatch(pusherActions.connect()); + store.dispatch(lastfmActions.connect()); next(action) break diff --git a/src/js/services/lastfm/actions.js b/src/js/services/lastfm/actions.js index 162c2324..8c4c3805 100755 --- a/src/js/services/lastfm/actions.js +++ b/src/js/services/lastfm/actions.js @@ -59,8 +59,11 @@ export function set(data){ **/ export function authorizationGranted(data){ - data.token_expiry = new Date().getTime() + data.expires_in; - return { type: 'LASTFM_AUTHORIZATION_GRANTED', data: data } + data.session.expiry = new Date().getTime() + 3600; + return { + type: 'LASTFM_AUTHORIZATION_GRANTED', + data: data + } } export function revokeAuthorization(){ @@ -70,12 +73,37 @@ export function revokeAuthorization(){ export function connect(){ return (dispatch, getState) => { - dispatch({ type: 'LASTFM_CONNECTING' }) + dispatch({ type: 'LASTFM_CONNECTING' }); - sendRequest(dispatch, getState, 'method=artist.getInfo&artist=') + // Authorized, dual-purpose our connection to get the current user + if (getState().lastfm.session){ + dispatch(getMe()); + + // Not authorized, just use a generic lookup to test our connection + } else { + sendRequest(dispatch, getState, 'method=artist.getInfo&artist=') + .then( + response => { + dispatch({ type: 'LASTFM_CONNECTED' }) + } + ) + } + } +} + +export function getMe(){ + return (dispatch, getState) => { + var params = 'method=user.getInfo&user='+getState().lastfm.session.name + sendRequest(dispatch, getState, params) .then( response => { - dispatch({ type: 'LASTFM_CONNECTED' }) + if (response.user){ + dispatch({ + type: 'LASTFM_USER_LOADED', + user: response.user + }); + dispatch({ type: 'LASTFM_CONNECTED' }) + } } ) } diff --git a/src/js/services/lastfm/middleware.js b/src/js/services/lastfm/middleware.js new file mode 100755 index 00000000..6759089b --- /dev/null +++ b/src/js/services/lastfm/middleware.js @@ -0,0 +1,43 @@ + +import ReactGA from 'react-ga' + +var helpers = require('./../../helpers') +var lastfmActions = require('./actions') +var uiActions = require('../ui/actions') +var pusherActions = require('../pusher/actions') + +const LastfmMiddleware = (function(){ + + /** + * The actual middleware inteceptor + **/ + return store => next => action => { + var state = store.getState(); + + switch(action.type){ + + case 'LASTFM_USER_LOADED': + var user = Object.assign( + {}, + action.user, + { + uri: "lastfm:user:"+action.user.name + } + ); + store.dispatch({ + type: "USER_LOADED", + key: user.uri, + user: user + }); + next(action); + break; + + // This action is irrelevant to us, pass it on to the next middleware + default: + return next(action); + } + } + +})(); + +export default LastfmMiddleware \ No newline at end of file diff --git a/src/js/services/lastfm/reducer.js b/src/js/services/lastfm/reducer.js index 93c2a228..d69fa469 100755 --- a/src/js/services/lastfm/reducer.js +++ b/src/js/services/lastfm/reducer.js @@ -13,22 +13,17 @@ export default function reducer(lastfm = {}, action){ return Object.assign({}, lastfm, action.data) case 'LASTFM_AUTHORIZATION_GRANTED': - return Object.assign({}, lastfm, { - enabled: true, + return Object.assign({}, lastfm, { authorizing: false, - authorization: action.data, - api_key: action.data.api_key, - token_expiry: action.data.token_expiry + session: action.data.session }) case 'LASTFM_AUTHORIZATION_REVOKED': return Object.assign({}, lastfm, { - authorizing: false, - authorization: false, - api_key: false, - token_expiry: 0, + authorizing: false, + session: false, me: false - }) + }); default: return lastfm diff --git a/src/js/services/localstorage/middleware.js b/src/js/services/localstorage/middleware.js index f34b8db3..365d2b8a 100755 --- a/src/js/services/localstorage/middleware.js +++ b/src/js/services/localstorage/middleware.js @@ -167,6 +167,17 @@ const localstorageMiddleware = (function(){ ); localStorage.setItem('ui', JSON.stringify(ui)) break + + case 'LASTFM_AUTHORIZATION_GRANTED': + var lastfm = JSON.parse(localStorage.getItem('lastfm') ); + lastfm = Object.assign( + {}, + { + session: action.data.session + } + ); + localStorage.setItem('lastfm', JSON.stringify(lastfm)); + break; } } diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js index 1b4e7320..378b5567 100755 --- a/src/js/views/Settings.js +++ b/src/js/views/Settings.js @@ -15,11 +15,13 @@ import Header from '../components/Header' import Parallax from '../components/Parallax' import Icon from '../components/Icon' import Thumbnail from '../components/Thumbnail' +import URILink from '../components/URILink' import * as coreActions from '../services/core/actions' import * as uiActions from '../services/ui/actions' import * as pusherActions from '../services/pusher/actions' import * as mopidyActions from '../services/mopidy/actions' +import * as lastfmActions from '../services/lastfm/actions' import * as spotifyActions from '../services/spotify/actions' class Settings extends React.Component { @@ -109,21 +111,45 @@ class Settings extends React.Component { if (user){ return ( - + {user.display_name ? user.display_name : user.id} - + ) } else { return ( - + Unknown - + + ) + } + } + + renderLastfmUser(){ + var user = this.props.core.users["lastfm:user:"+this.props.lastfm.session.name]; + + if (user){ + return ( + + + + {user.realname ? user.realname : user.name} + + + ) + } else { + return ( + + + + Unknown + + ) } } @@ -302,6 +328,7 @@ class Settings extends React.Component { +
Authorization
@@ -313,6 +340,15 @@ class Settings extends React.Component {

LastFM

+ {this.props.lastfm.session ?
+
Current user
+
+
+ { this.renderLastfmUser() } +
+
+
: null} +
Authorization
@@ -408,6 +444,7 @@ const mapDispatchToProps = (dispatch) => { uiActions: bindActionCreators(uiActions, dispatch), pusherActions: bindActionCreators(pusherActions, dispatch), mopidyActions: bindActionCreators(mopidyActions, dispatch), + lastfmActions: bindActionCreators(lastfmActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch) } }