mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-01 05:32:18 +00:00
0.0.11
- Fix redirects to /login for auth required pages - Add handling for 401/429 + No connection responses in API calls - Add background workers for Go (clear out password resets) - Fixed timezone issues
This commit is contained in:
parent
fd615102a8
commit
9866dea36b
33 changed files with 795 additions and 248 deletions
|
@ -7,12 +7,38 @@ function getHeaders() {
|
|||
const user = JSON.parse(localStorage.getItem('user'));
|
||||
|
||||
if (user && user.jwt) {
|
||||
return { Authorization: 'Bearer ' + user.jwt };
|
||||
return { Authorization: 'Bearer ' + user.jwt, changeOrigin: true };
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function getUserUuid() {
|
||||
// Todo: move this to use Context values instead.
|
||||
const user = JSON.parse(localStorage.getItem('user'));
|
||||
|
||||
if (user && user.uuid) {
|
||||
return user.uuid
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function handleErrorResp(error) {
|
||||
if (error.response) {
|
||||
if (error.response.status === 401) {
|
||||
toast.error('Unauthorized')
|
||||
} else if (error.response.status === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('An unknown error has occurred');
|
||||
}
|
||||
} else {
|
||||
toast.error('Failed to connect to API');
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
export const PostLogin = (formValues) => {
|
||||
return axios.post(process.env.REACT_APP_API_URL + "login", formValues)
|
||||
.then((response) => {
|
||||
|
@ -34,7 +60,7 @@ export const PostLogin = (formValues) => {
|
|||
}
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
toast.error('Unauthorized')
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
|
@ -57,14 +83,8 @@ export const PostRegister = (formValues) => {
|
|||
return Promise.reject();
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return Promise.resolve();
|
||||
handleErrorResp(error)
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -81,15 +101,9 @@ export const PostResetPassword = (formValues) => {
|
|||
return Promise.reject();
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
handleErrorResp(error)
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
export const sendPasswordReset = (values) => {
|
||||
|
@ -97,14 +111,7 @@ export const sendPasswordReset = (values) => {
|
|||
(data) => {
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -113,14 +120,7 @@ export const getStats = () => {
|
|||
(data) => {
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -129,14 +129,7 @@ export const getRecentScrobbles = (id) => {
|
|||
.then((data) => {
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -145,14 +138,7 @@ export const getConfigs = () => {
|
|||
.then((data) => {
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -171,15 +157,8 @@ export const postConfigs = (values, toggle) => {
|
|||
toast.error(data.data.error);
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
});
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
export const getProfile = (userName) => {
|
||||
|
@ -187,14 +166,7 @@ export const getProfile = (userName) => {
|
|||
.then((data) => {
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -203,34 +175,56 @@ export const getUser = () => {
|
|||
.then((data) => {
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
export const validateResetPassword = (tokenStr) => {
|
||||
return axios.post(process.env.REACT_APP_API_URL + "resetpassword", { token: tokenStr })
|
||||
return axios.get(process.env.REACT_APP_API_URL + "user/", { headers: getHeaders() })
|
||||
.then((data) => {
|
||||
if (data.error) {
|
||||
toast.error(data.error);
|
||||
return {valid: false}
|
||||
}
|
||||
return data.data;
|
||||
}).catch((error) => {
|
||||
if (error.response === 401) {
|
||||
return {};
|
||||
} else if (error.response === 429) {
|
||||
toast.error('Rate limited. Please try again shortly')
|
||||
} else {
|
||||
toast.error('Failed to connect');
|
||||
}
|
||||
return {};
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
};
|
||||
|
||||
export const getSpotifyClientId = () => {
|
||||
return axios.get(process.env.REACT_APP_API_URL + "user/spotify", { headers: getHeaders() })
|
||||
.then((data) => {
|
||||
return data.data
|
||||
}).catch((error) => {
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
}
|
||||
|
||||
export const spotifyConnectionRequest = () => {
|
||||
return getSpotifyClientId().then((resp) => {
|
||||
var scopes = 'user-read-recently-played user-read-currently-playing';
|
||||
|
||||
// Local, lets forward it to API
|
||||
let redirectUri = window.location.origin.toString()+ "/api/v1/link/spotify";
|
||||
|
||||
// Stupid dev
|
||||
if (window.location.origin.toString() === "http://localhost:3000") {
|
||||
redirectUri = "http://localhost:42069/api/v1/link/spotify"
|
||||
}
|
||||
|
||||
window.location = 'https://accounts.spotify.com/authorize' +
|
||||
'?response_type=code' +
|
||||
'&client_id=' + resp.token +
|
||||
'&scope=' + encodeURIComponent(scopes) +
|
||||
'&redirect_uri=' + encodeURIComponent(redirectUri) +
|
||||
'&state=' + getUserUuid();
|
||||
})
|
||||
};
|
||||
|
||||
export const spotifyDisonnectionRequest = () => {
|
||||
return axios.delete(process.env.REACT_APP_API_URL + "user/spotify", { headers: getHeaders() })
|
||||
.then((data) => {
|
||||
toast.success(data.data.message);
|
||||
return true
|
||||
}).catch((error) => {
|
||||
return handleErrorResp(error)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ const ScrobbleTable = (props) => {
|
|||
<td>Track</td>
|
||||
<td>Artist</td>
|
||||
<td>Album</td>
|
||||
<td>Source</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -21,6 +22,7 @@ const ScrobbleTable = (props) => {
|
|||
<td>{element.track}</td>
|
||||
<td>{element.artist}</td>
|
||||
<td>{element.album}</td>
|
||||
<td>{element.source}</td>
|
||||
</tr>;
|
||||
})
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ const Admin = () => {
|
|||
if (data.configs) {
|
||||
setConfigs(data.configs);
|
||||
setToggle(data.configs.REGISTRATION_ENABLED === "1")
|
||||
setLoading(false);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
@ -31,6 +31,14 @@ const Admin = () => {
|
|||
setToggle(!toggle);
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
history.push("/login")
|
||||
}
|
||||
|
||||
if (user && !user.admin) {
|
||||
history.push("/Dashboard")
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
|
@ -39,9 +47,7 @@ const Admin = () => {
|
|||
)
|
||||
}
|
||||
|
||||
if (!user || !user.admin) {
|
||||
history.push("/login")
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
|
|
|
@ -8,7 +8,7 @@ import ScrobbleTable from "../Components/ScrobbleTable";
|
|||
import AuthContext from '../Contexts/AuthContext';
|
||||
|
||||
const Dashboard = () => {
|
||||
// const history = useHistory();
|
||||
const history = useHistory();
|
||||
let { user } = useContext(AuthContext);
|
||||
let [loading, setLoading] = useState(true);
|
||||
let [dashboardData, setDashboardData] = useState({});
|
||||
|
@ -24,6 +24,10 @@ const Dashboard = () => {
|
|||
})
|
||||
}, [user])
|
||||
|
||||
if (!user) {
|
||||
history.push("/login")
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
|
@ -37,10 +41,12 @@ const Dashboard = () => {
|
|||
<h1>
|
||||
{user.username}'s Dashboard!
|
||||
</h1>
|
||||
<div className="dashboardBody">
|
||||
{loading
|
||||
? <ScaleLoader color="#6AD7E5" size={60} />
|
||||
: <ScrobbleTable data={dashboardData.items} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ const Login = () => {
|
|||
className="loginButton"
|
||||
onClick={redirectReset}
|
||||
disabled={loading}
|
||||
>{loading ? <ScaleLoader color="#FFF" size={35} /> : "Reset Password"}</Button>
|
||||
>Reset Password</Button>
|
||||
</Form>
|
||||
</Formik>
|
||||
</div>
|
||||
|
|
|
@ -5,6 +5,8 @@ import { useHistory } from "react-router";
|
|||
import AuthContext from '../Contexts/AuthContext';
|
||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||
import { getUser } from '../Api/index'
|
||||
import { Button } from 'reactstrap';
|
||||
import { spotifyConnectionRequest, spotifyDisonnectionRequest } from '../Api/index'
|
||||
|
||||
const User = () => {
|
||||
const history = useHistory();
|
||||
|
@ -12,6 +14,7 @@ const User = () => {
|
|||
const [loading, setLoading] = useState(true);
|
||||
const [userdata, setUserdata] = useState({});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
return
|
||||
|
@ -24,6 +27,10 @@ const User = () => {
|
|||
})
|
||||
}, [user])
|
||||
|
||||
if (!user) {
|
||||
history.push("/login")
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
|
@ -32,10 +39,6 @@ const User = () => {
|
|||
)
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
history.push("/login")
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
<h1>
|
||||
|
@ -44,7 +47,25 @@ const User = () => {
|
|||
<p className="userBody">
|
||||
Created At: {userdata.created_at}<br/>
|
||||
Email: {userdata.email}<br/>
|
||||
Verified: {userdata.verified ? '✓' : '✖'}
|
||||
Verified: {userdata.verified ? '✓' : '✖'}<br/>
|
||||
{userdata.spotify_username
|
||||
? <div>Spotify Account: {userdata.spotify_username}<br/><br/>
|
||||
<Button
|
||||
color="secondary"
|
||||
type="button"
|
||||
className="loginButton"
|
||||
onClick={spotifyDisonnectionRequest}
|
||||
>Disconnect Spotify</Button></div>
|
||||
: <div>
|
||||
<br/>
|
||||
<Button
|
||||
color="primary"
|
||||
type="button"
|
||||
className="loginButton"
|
||||
onClick={spotifyConnectionRequest}
|
||||
>Connect To Spotify</Button>
|
||||
</div>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue