adds sending toggle (true, false) information; adds color picker and sending that information back to server
- the color picker is from 'colorPick' which makes implementation easy. It's only a .js and a .css file which need to be included and the color-picker is simple enough to handle on the client side. The only main problem with it, is that accessing the 'id' information of the css it was called from is not straightforward - the toggle switch which is just implemented in .css currently has the checklist inverted, works but ugly - The Client sends this information back to the server via a json file, which defines the calendar id and either color or the toggle information. The server currently just prints this information.great stuff.
This commit is contained in:
parent
53a1f201f8
commit
596f690cce
43
app.py
43
app.py
@ -90,6 +90,7 @@ class Calendar:
|
|||||||
self.color = color
|
self.color = color
|
||||||
|
|
||||||
@app.route("/calendar")
|
@app.route("/calendar")
|
||||||
|
@login_required
|
||||||
def calendar():
|
def calendar():
|
||||||
ca1 = Calendar("Hightower", "#30ff30")
|
ca1 = Calendar("Hightower", "#30ff30")
|
||||||
ca2 = Calendar("Toast", "#66e230")
|
ca2 = Calendar("Toast", "#66e230")
|
||||||
@ -97,10 +98,6 @@ def calendar():
|
|||||||
return flask.render_template('calendar.html', calendars=calendars)
|
return flask.render_template('calendar.html', calendars=calendars)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/test')
|
@app.route('/test')
|
||||||
def test_api_request():
|
def test_api_request():
|
||||||
if 'credentials' not in flask.session:
|
if 'credentials' not in flask.session:
|
||||||
@ -118,6 +115,8 @@ def test_api_request():
|
|||||||
# credentials in a persistent database instead.
|
# credentials in a persistent database instead.
|
||||||
flask.session['credentials'] = credentials_to_dict(credentials)
|
flask.session['credentials'] = credentials_to_dict(credentials)
|
||||||
|
|
||||||
|
with open('./userinfo/' + current_user.id + '/calendarevents.json', 'w') as outfile:
|
||||||
|
json.dump(todaysCal, outfile)
|
||||||
return flask.jsonify(todaysCal)
|
return flask.jsonify(todaysCal)
|
||||||
|
|
||||||
@app.route("/login/google")
|
@app.route("/login/google")
|
||||||
@ -141,13 +140,11 @@ def login():
|
|||||||
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
|
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
|
||||||
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
||||||
CLIENT_SECRETS_FILE, scopes=SCOPES)
|
CLIENT_SECRETS_FILE, scopes=SCOPES)
|
||||||
|
|
||||||
# The URI created here must exactly match one of the authorized redirect URIs
|
# The URI created here must exactly match one of the authorized redirect URIs
|
||||||
# for the OAuth 2.0 client, which you configured in the API Console. If this
|
# for the OAuth 2.0 client, which you configured in the API Console. If this
|
||||||
# value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
|
# value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
|
||||||
# error.
|
# error.
|
||||||
flow.redirect_uri = request.base_url + "/callback"
|
flow.redirect_uri = request.base_url + "/callback"
|
||||||
|
|
||||||
authorization_url, state = flow.authorization_url(
|
authorization_url, state = flow.authorization_url(
|
||||||
# Enable offline access so that you can refresh an access token without
|
# Enable offline access so that you can refresh an access token without
|
||||||
# re-prompting the user for permission. Recommended for web server apps.
|
# re-prompting the user for permission. Recommended for web server apps.
|
||||||
@ -216,14 +213,40 @@ def credentials_to_dict(credentials):
|
|||||||
'scopes': credentials.scopes}
|
'scopes': credentials.scopes}
|
||||||
|
|
||||||
|
|
||||||
@app.route("/userinfo/107971745944668140075/calendarevents.json")
|
@app.route("/userinfo/<path:user>/calendarevents.json")
|
||||||
def downloader():
|
def downloader(user):
|
||||||
path = "/home/raphael/dev/website_ws/website/login/userinfo/107971745944668140075"
|
print(user)
|
||||||
|
path = "/home/raphael/dev/website_ws/website/userinfo/" + user
|
||||||
return flask.send_from_directory(path, "calendarevents.json")
|
return flask.send_from_directory(path, "calendarevents.json")
|
||||||
|
|
||||||
|
# POST
|
||||||
|
|
||||||
|
@app.route('/calendar', methods = ['POST', 'DELETE'])
|
||||||
|
@login_required
|
||||||
|
def user():
|
||||||
|
if request.method == 'POST':
|
||||||
|
calId = request.json.get('calendar_id')
|
||||||
|
color = request.json.get('color')
|
||||||
|
toggle = request.json.get('toggle')
|
||||||
|
|
||||||
|
print(calId)
|
||||||
|
if color != None:
|
||||||
|
print(color)
|
||||||
|
if toggle != None:
|
||||||
|
print(toggle)
|
||||||
|
# toggle specific calendar of user
|
||||||
|
elif request.method == 'DELETE':
|
||||||
|
# do nothing
|
||||||
|
return 'NONE'
|
||||||
|
else:
|
||||||
|
# POST Error 405
|
||||||
|
print("405")
|
||||||
|
|
||||||
|
return 'OK'
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
context = ('certificate/xip.io.crt', 'certificate/xip.io.key')#certificate and key files
|
context = ('certificate/xip.io.crt', 'certificate/xip.io.key')#certificate and key files
|
||||||
app.run('192.168.68.103.xip.io', 1234, ssl_context=context, debug=True)
|
app.run('0.0.0.0', 1234, ssl_context=context, debug=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
@ -1,35 +1,108 @@
|
|||||||
{% extends "sidebar.html" %}
|
{% extends "sidebar.html" %}
|
||||||
{% block body%}
|
{% block body%}
|
||||||
<div>
|
|
||||||
<div style="width: 30%; float: left" align="center" >Calendar</div>
|
<div style="height: 50px">
|
||||||
<div style="width: 30%; float: left" align="center">Show on device</div>
|
<div style="width: 30%; float: left; margin-left: 10%">Calendar</div>
|
||||||
<div style="width: 30%; float: left" align="center">Color</div>
|
<div style="width: 30%; float: left">Show on device</div>
|
||||||
|
<div style="width: 30%; float: left">Color</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: 50px">
|
<div>
|
||||||
{% for item in calendars %}
|
{% for item in calendars %}
|
||||||
<div style="width: 30%; float: left" align="center" >{{ item.name }}</div>
|
<div style="height: 30px">
|
||||||
|
<!--Name-->
|
||||||
|
<div style="width: 30%; float: left; font-size: 24px; text-align: left; margin-left: 10%">{{ item.name }}</div>
|
||||||
|
|
||||||
<div style="width: 30%; float: left" align="center">
|
<!--Toggle-->
|
||||||
|
<div style="width: 30%; float: left">
|
||||||
<!-- Rounded switch -->
|
<!-- Rounded switch -->
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input type="checkbox">
|
<input type="checkbox">
|
||||||
<span class="slider round"></span>
|
<span id={{item.name}} class="slider round" onclick="toggleReaction(this)"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="width: 30%; float: left" align="center">
|
<!--Color Selector-->
|
||||||
<div>
|
<div style="width: 30%; float: left">
|
||||||
<input type="color" id="head" name="head"
|
<div class="colorPickSelector" id={{item.name}}></div>
|
||||||
value="#e66465">
|
|
||||||
<label for="head">Test</label>
|
|
||||||
</div>
|
|
||||||
<!--svg height="20" width="20">
|
<!--svg height="20" width="20">
|
||||||
<circle cx="10" cy="10" r="10" stroke="black" stroke-width="0" fill={{ item.color }} />
|
<circle cx="10" cy="10" r="10" stroke="black" stroke-width="0" fill={{ item.color }} />
|
||||||
</svg-->
|
</svg-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(".colorPickSelector").colorPick({
|
||||||
|
'initialColor': '#3498db',
|
||||||
|
'allowRecent': true,
|
||||||
|
'recentMax': 5,
|
||||||
|
'allowCustomColor': false,
|
||||||
|
'palette': ["#1abc9c", "#16a085", "#2ecc71", "#27ae60", "#3498db", "#2980b9", "#9b59b6", "#8e44ad", "#34495e", "#2c3e50", "#f1c40f", "#f39c12", "#e67e22", "#d35400", "#e74c3c", "#c0392b", "#ecf0f1", "#bdc3c7", "#95a5a6", "#7f8c8d"],
|
||||||
|
'onColorSelected': function() {
|
||||||
|
|
||||||
|
// Todo getting the element id is currently done over [0] [#02]
|
||||||
|
this.element.css({'backgroundColor': this.color, 'color': this.color});
|
||||||
|
console.log(this.element[0].id);
|
||||||
|
console.log(this.color);
|
||||||
|
post("color", this.element[0].id, this.color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function post(type, id, data) {
|
||||||
|
var url = "https://192.168.68.103.xip.io:1234/calendar";
|
||||||
|
var method = "POST";
|
||||||
|
switch (type) {
|
||||||
|
case "color":
|
||||||
|
var postData = JSON.stringify({"calendar_id": id.toString(), "color": data.toString()});
|
||||||
|
break;
|
||||||
|
case "toggle":
|
||||||
|
var postData = JSON.stringify({"calendar_id": id.toString(), "toggle": data.toString()})
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.log(postData);
|
||||||
|
|
||||||
|
var shouldBeAsync = true;
|
||||||
|
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.onload = function () {
|
||||||
|
var status = request.status;
|
||||||
|
var data = request.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.open(method, url, shouldBeAsync);
|
||||||
|
// content type json makes app do error 400
|
||||||
|
request.setRequestHeader("Content-Type", "application/json");
|
||||||
|
request.send(postData);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleReaction(self) {
|
||||||
|
// the slider used defaults to inverted information [#01]
|
||||||
|
post("toggle", self.id, !self.previousElementSibling.checked);
|
||||||
|
|
||||||
|
/*console.log(self.id);
|
||||||
|
var url = "https://192.168.68.103.xip.io:1234/calendar";
|
||||||
|
var method = "POST";
|
||||||
|
var postData = JSON.stringify({"calendar_id": self.id.toString() });
|
||||||
|
console.log(postData);
|
||||||
|
var shouldBeAsync = true;
|
||||||
|
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.onload = function () {
|
||||||
|
var status = request.status;
|
||||||
|
var data = request.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.open(method, url, shouldBeAsync);
|
||||||
|
// content type json makes app do error 400
|
||||||
|
request.setRequestHeader("Content-Type", "application/json");
|
||||||
|
request.send(postData);*/
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -6,10 +6,19 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/main.css">
|
<link rel="stylesheet" type="text/css" href="/static/css/main.css">
|
||||||
|
<script src="static/js/jquery-3.5.0.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="static/css/colorPick.css">
|
||||||
|
<!-- OPTIONAL DARK THEME -->
|
||||||
|
<link rel="stylesheet" href="static/css/colorPick.dark.theme.css">
|
||||||
|
<script src="static/js/colorPick.js"></script>
|
||||||
|
|
||||||
<title>Index</title>
|
<title>Index</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
||||||
<!-- Side navigation -->
|
<!-- Side navigation -->
|
||||||
<div class="sidenav">
|
<div class="sidenav">
|
||||||
<a href="/view">View</a>
|
<a href="/view">View</a>
|
||||||
@ -26,6 +35,9 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user