added js frontend skeleton with routing

This commit is contained in:
aj 2019-07-26 14:18:32 +01:00
parent 549d8b4e10
commit aaebf3a6e9
14 changed files with 6079 additions and 8 deletions

3
.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@babel/env", "@babel/preset-react"]
}

22
.gcloudignore Normal file
View File

@ -0,0 +1,22 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore
venv
node_modules
# Python pycache:
__pycache__/
# Ignored by the build system
/setup.cfg

5835
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

39
package.json Normal file
View File

@ -0,0 +1,39 @@
{
"name": "spotify.sarsoo.xyz",
"version": "1.0.0",
"description": "spotify playlist manager web app",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.js",
"devbuild": "webpack --config webpack.dev.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Sarsoo/spotify-web.git"
},
"author": "sarsoo",
"license": "ISC",
"bugs": {
"url": "https://github.com/Sarsoo/spotify-web/issues"
},
"homepage": "https://github.com/Sarsoo/spotify-web#readme",
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.1"
},
"devDependencies": {
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.1.0",
"style-loader": "^0.23.1",
"webpack": "^4.38.0",
"webpack-cli": "^3.3.6",
"webpack-merge": "^4.2.1"
}
}

24
requirements.txt Normal file
View File

@ -0,0 +1,24 @@
cachetools==3.1.1
certifi==2019.6.16
chardet==3.0.4
Click==7.0
Flask==1.1.1
google-api-core==1.14.0
google-auth==1.6.3
google-cloud-core==1.0.2
google-cloud-firestore==1.3.0
googleapis-common-protos==1.6.0
grpcio==1.22.0
idna==2.8
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
protobuf==3.9.0
pyasn1==0.4.5
pyasn1-modules==0.2.5
pytz==2019.1
requests==2.22.0
rsa==4.0
six==1.12.0
urllib3==1.25.3
Werkzeug==0.15.5

View File

@ -1,5 +1,9 @@
from flask import Flask, render_template, redirect from flask import Flask, render_template, redirect, request
from google.cloud import firestore from google.cloud import firestore
import requests
from base64 import b64encode
import os import os
import urllib import urllib
@ -24,15 +28,43 @@ def auth():
'client_id': client_id, 'client_id': client_id,
'response_type': 'code', 'response_type': 'code',
'scope': 'playlist-modify-public playlist-modify-private playlist-read-private', 'scope': 'playlist-modify-public playlist-modify-private playlist-read-private',
'redirect_uri': 'https://spotify.sarsoo.xyz/app' 'redirect_uri': 'https://spotify.sarsoo.xyz/token'
} }
) )
return redirect(urllib.parse.urlunparse(['https', 'accounts.spotify.com', 'authorize', '', params, ''])) 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)
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)
if 200 <= req.status_code < 300:
resp = req.json()
print(resp)
return redirect('/app')
@app.route('/app') @app.route('/app')
def app_route(): @app.route('/app/<path>')
def app_route(path = None):
return render_template('app.html') return render_template('app.html')
# [END gae_python37_app] # [END gae_python37_app]

View File

@ -1,8 +1,31 @@
{% extends 'base.html' %} <!doctype html>
<html>
<head>
<title>sarsoo/spotify</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link href="https://fonts.googleapis.com/css?family=Pirata+One|Lato" rel="stylesheet">
{% block title %}spotify{% endblock %} <link rel="apple-touch-icon" sizes="180x180" href="https://storage.googleapis.com/sarsooxyzstatic/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://storage.googleapis.com/sarsooxyzstatic/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://storage.googleapis.com/sarsooxyzstatic/favicon-16x16.png">
<link rel="manifest" href="https://storage.googleapis.com/sarsooxyzstatic/site.webmanifest">
<link rel="mask-icon" href="https://storage.googleapis.com/sarsooxyzstatic/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="https://storage.googleapis.com/sarsooxyzstatic/favicon.ico">
{% block content %} </head>
<body>
<div>
<h1 class="title">andy</h1>
</div>
<div class="row"></div> <br><br>
{% endblock %}
<div id="react"></div>
<script src="{{ url_for('static', filename='js/app.bundle.js') }}"></script>
<footer>
<a href="https://github.com/Sarsoo/sarsoo.xyz">view source code</a>
</footer>
</body>
</html>

8
src/js/Index.js Normal file
View File

@ -0,0 +1,8 @@
import React, { Component } from "react";
function Index(props){
return <p>index</p>;
}
export default Index;

25
src/js/PlaylistManager.js Normal file
View File

@ -0,0 +1,25 @@
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Index from "./Index.js";
import Settings from "./Settings.js";
class PlaylistManager extends Component {
render(){
return (
<Router>
<ul className="navbar">
<li><Link to="/app">home</Link></li>
<li><Link to="/app/settings">settings</Link></li>
</ul>
<Route path="/app" exact component={Index} />
<Route path="/app/settings" component={Settings} />
</Router>
);
}
}
export default PlaylistManager;

8
src/js/Settings.js Normal file
View File

@ -0,0 +1,8 @@
import React, { Component } from "react";
function Settings(props){
return <p>settings</p>;
}
export default Settings;

6
src/js/app.js Normal file
View File

@ -0,0 +1,6 @@
import React from "react";
import ReactDOM from "react-dom";
import PlaylistManager from "./PlaylistManager.js";
ReactDOM.render(<PlaylistManager />, document.getElementById('react'));

31
webpack.common.js Normal file
View File

@ -0,0 +1,31 @@
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/js/app.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
options: { presets: ["@babel/env"] }
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
plugins: [
new CleanWebpackPlugin()
],
resolve: { extensions: ["*", ".js", ".jsx"] },
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'build/js')
}
};

8
webpack.dev.js Normal file
View File

@ -0,0 +1,8 @@
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
watch: true
});

7
webpack.prod.js Normal file
View File

@ -0,0 +1,7 @@
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});