Refactor, implement countdown
This commit is contained in:
parent
f78c9d349a
commit
1ba8fc71a8
22 changed files with 111 additions and 100 deletions
|
@ -1,7 +0,0 @@
|
||||||
from flask import Blueprint
|
|
||||||
|
|
||||||
api_v1 = Blueprint('api.v1', __name__)
|
|
||||||
|
|
||||||
import api.v1.clock
|
|
||||||
import api.v1.countdown
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
from time import time
|
|
||||||
|
|
||||||
from api.v1 import api_v1
|
|
||||||
|
|
||||||
@api_v1.route('/time/<float:t1>')
|
|
||||||
def netime_time(t1: float) -> str:
|
|
||||||
return str(time())
|
|
|
@ -1,31 +0,0 @@
|
||||||
from flask import request, jsonify
|
|
||||||
from walrus import Walrus
|
|
||||||
from time import time
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
import struct
|
|
||||||
|
|
||||||
from api.v1 import api_v1
|
|
||||||
|
|
||||||
db = Walrus(host='localhost', port=6379, db=0)
|
|
||||||
|
|
||||||
@api_v1.route('/countdown/<uuid:id>', methods=['GET'])
|
|
||||||
def get_countdown(id):
|
|
||||||
ct = db.Hash(str(id))
|
|
||||||
|
|
||||||
resp = ct.as_dict(decode=True)
|
|
||||||
resp['left'] = float(ct['total']) - (time() - float(ct['start']))
|
|
||||||
|
|
||||||
return resp
|
|
||||||
|
|
||||||
@api_v1.route('/countdown', methods=['POST'])
|
|
||||||
def create_countdown():
|
|
||||||
countdown = request.json
|
|
||||||
ct_id = str(uuid.uuid4())
|
|
||||||
ct = db.Hash(ct_id)
|
|
||||||
ct.update(start=time(), total=countdown['total'])
|
|
||||||
|
|
||||||
resp = ct.as_dict(decode=True)
|
|
||||||
resp['id'] = ct_id
|
|
||||||
|
|
||||||
return resp
|
|
|
@ -1,6 +1,5 @@
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
|
|
||||||
app = Blueprint('countdown', __name__)
|
app = Blueprint('countdown', __name__, template_folder='templates')
|
||||||
|
from . import views
|
||||||
import views
|
from . import api
|
||||||
import apii
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ from time import time
|
||||||
import uuid
|
import uuid
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from countdown import api_api
|
from . import app
|
||||||
|
|
||||||
db = Walrus(host='localhost', port=6379, db=0)
|
db = Walrus(host='localhost', port=6379, db=0)
|
||||||
|
|
||||||
@app.route('/api/vi1/<uuid:id>', methods=['GET'])
|
@app.route('/api/v1/<uuid:id>', methods=['GET'])
|
||||||
def get_countdown(id):
|
def get_countdown(id):
|
||||||
ct = db.Hash(str(id))
|
ct = db.Hash(str(id))
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ def get_countdown(id):
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
@api_v1.route('/api/v1', methods=['POST'])
|
@app.route('/api/v1', methods=['POST'])
|
||||||
def create_countdown():
|
def create_countdown():
|
||||||
countdown = request.json
|
countdown = request.json
|
||||||
ct_id = str(uuid.uuid4())
|
ct_id = str(uuid.uuid4())
|
48
countdown/countdown.js
Normal file
48
countdown/countdown.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// This file is packed by webpack into /static/dist/countdown.bundle.js
|
||||||
|
// Use with: `url_for('static', filename='dist/countdown.bundle.js')`
|
||||||
|
// See: webpack.common.js
|
||||||
|
import log from 'loglevel';
|
||||||
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
import './countdown.scss';
|
||||||
|
|
||||||
|
let api_base = "/countdown/api/v1/";
|
||||||
|
|
||||||
|
|
||||||
|
const updateCountdown = () => $.getJSON({
|
||||||
|
url: api_base+countdown_id,
|
||||||
|
data: Date.now(),
|
||||||
|
success: function(countdown) {
|
||||||
|
if(countdown.left <= 0) {
|
||||||
|
// clear interval, don't count below 0
|
||||||
|
clearInterval(scheduledUpdater);
|
||||||
|
$("#countdown").text("Time is up!");
|
||||||
|
let end = new Date(Math.floor(countdown.start*1000 + countdown.total*1000));
|
||||||
|
$("#subtext").text("This countdown ended on "+ end.toLocaleDateString()+" "+end.toLocaleTimeString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// total seconds left
|
||||||
|
let sec = Math.floor(countdown.left);
|
||||||
|
// milliseconds left in seconds resolution
|
||||||
|
let frac = countdown.left - sec;
|
||||||
|
// milliseconds left in millisecond resolution
|
||||||
|
let milli = Math.floor(frac * 1000);
|
||||||
|
// seconds in hrs, minutes, seconds
|
||||||
|
let h = Math.floor(sec/(60*60));
|
||||||
|
let m = Math.floor(sec/60) - (h*60);
|
||||||
|
let s = sec - (m*60) - (h*60*60);
|
||||||
|
|
||||||
|
// let milliseconds pass, then set element to
|
||||||
|
// amount of full seconds left
|
||||||
|
let htext = padTime(h);
|
||||||
|
let mtext = padTime(m);
|
||||||
|
htext = htext !== "00" ? htext+":": "";
|
||||||
|
mtext = mtext !== "00" ? mtext+":": "";
|
||||||
|
setTimeout(() => $("#countdown").text(htext+mtext+padTime(s)), milli);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let scheduledUpdater = setInterval(updateCountdown, 1000);
|
||||||
|
let padTime = t => `${"0".repeat(2-t.toString().length)+t}`;
|
||||||
|
|
7
countdown/countdown.scss
Normal file
7
countdown/countdown.scss
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#countdown {
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#subtext {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
from flask_wtf import FlaskForm, TimeField
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import TimeField
|
||||||
|
|
||||||
class CountdownAdminForm(FlaskForm):
|
class CountdownAdminForm(FlaskForm):
|
||||||
totalTime = TimeField('Time')
|
totalTime = TimeField('Time')
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
{% block title %}Countdown{% endblock title %}
|
{% block title %}Countdown{% endblock title %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
Hello from Countdown
|
<div class="center">
|
||||||
<div id="clock"></div>
|
<p id="countdown" />
|
||||||
|
<p id="subtext" />
|
||||||
|
</div>
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
|
<script>
|
||||||
|
var countdown_id = "{{ countdown_id }}";
|
||||||
|
</script>
|
||||||
<script src="{{ url_for('static', filename='dist/countdown.bundle.js') }}"></script>
|
<script src="{{ url_for('static', filename='dist/countdown.bundle.js') }}"></script>
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
|
@ -1,19 +1,20 @@
|
||||||
from flask import render_template, request, flash, redirect, url_for
|
from flask import render_template, request, flash, redirect, url_for
|
||||||
|
|
||||||
from countdown import app, forms
|
from . import app
|
||||||
|
from . import forms
|
||||||
|
|
||||||
@app.route('/<uuid:id>', methods=['GET'])
|
@app.route('/<uuid:countdown_id>', methods=['GET'])
|
||||||
def countdown(id):
|
def countdown(countdown_id):
|
||||||
return render_template('countdown.html', id)
|
return render_template('countdown/countdown.html', countdown_id=countdown_id)
|
||||||
|
|
||||||
@app.route('/', methods=['GET', 'POST', 'PUT'])
|
@app.route('/', methods=['GET', 'POST', 'PUT'])
|
||||||
def countdown_admin():
|
def countdown_admin():
|
||||||
form = CountdownAdminForm(request.form)
|
form = forms.CountdownAdminForm(request.form)
|
||||||
if request.method == 'POST' and form.validate():
|
if request.method == 'POST' and form.validate():
|
||||||
user = User(form.username.data, form.email.data,
|
# user = User(form.username.data, form.email.data,
|
||||||
form.password.data)
|
# form.password.data)
|
||||||
db_session.add(user)
|
# db_session.add(user)
|
||||||
flash('Thanks for registering')
|
flash('Thanks for registering')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
return render_template('countdown_admin.html', form=form, clock=None)
|
return render_template('countdown/countdown_admin.html', form=form, clock=None)
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
body {
|
@import "~reset-css/sass/reset";
|
||||||
color: red;
|
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
4
forms.py
4
forms.py
|
@ -1,4 +0,0 @@
|
||||||
from flask_wtf import FlaskForm, TimeField
|
|
||||||
|
|
||||||
class CountdownAdminForm(FlaskForm):
|
|
||||||
totalTime = TimeField('Time')
|
|
|
@ -1,24 +0,0 @@
|
||||||
import log from 'loglevel';
|
|
||||||
import $ from 'jquery';
|
|
||||||
|
|
||||||
|
|
||||||
const updateCountdown = () => $.getJSON({
|
|
||||||
url: "api/v1/countdown/070f478f-e168-488c-918e-adb37c9c0cbd",
|
|
||||||
data: Date.now(),
|
|
||||||
success: function(countdown) {
|
|
||||||
if(countdown.left <= 0) {
|
|
||||||
clearInterval(scheduledUpdater);
|
|
||||||
$('#clock').text(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let floor = Math.floor(countdown.left);
|
|
||||||
|
|
||||||
let frac = countdown.left - floor;
|
|
||||||
let milli = Math.floor(frac * 1000); // get in millisecond resolution
|
|
||||||
|
|
||||||
setTimeout(() => $('#clock').text(floor), milli);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let scheduledUpdater = setInterval(updateCountdown, 1000);
|
|
|
@ -1,5 +1,6 @@
|
||||||
import '../css/netclock.scss';
|
import '../css/netclock.scss';
|
||||||
import log from 'loglevel';
|
import log from 'loglevel';
|
||||||
|
import $ from 'jquery';
|
||||||
|
|
||||||
if (process.env.LOG_LEVEL) {
|
if (process.env.LOG_LEVEL) {
|
||||||
log.setDefaultLevel(process.env.LOG_LEVEL);
|
log.setDefaultLevel(process.env.LOG_LEVEL);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
from api.v1 import api_v1
|
from countdown import app as countdown
|
||||||
app.register_blueprint(api_v1, url_prefix="/api/v1")
|
app.register_blueprint(countdown, url_prefix="/countdown")
|
||||||
|
|
||||||
import views
|
import views
|
||||||
|
|
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -2991,6 +2991,11 @@
|
||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"reset-css": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/reset-css/-/reset-css-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-VyuJdNFfp5x/W6e5wauJM59C02Vs0P22sxzZGhQMPaqu/NGTeFxlBFOOw3eq9vQd19gIDdZp7zi89ylyKOJ33Q=="
|
||||||
|
},
|
||||||
"resolve-cwd": {
|
"resolve-cwd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jquery": "^3.5.1",
|
"jquery": "^3.5.1",
|
||||||
"loglevel": "^1.7.0"
|
"loglevel": "^1.7.0",
|
||||||
|
"reset-css": "^5.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
querysheet.http
Normal file
6
querysheet.http
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Create a new countdown clock with
|
||||||
|
# 5000 seconds
|
||||||
|
POST http://localhost:5000/countdown/api/v1
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"total": "150"}
|
4
views.py
4
views.py
|
@ -1,9 +1,9 @@
|
||||||
from flask import Flask, render_template, request, flash
|
from flask import Flask, render_template, request, flash
|
||||||
from netclock import app
|
from netclock import app
|
||||||
|
|
||||||
from forms import CountdownAdminForm
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
|
breakpoint()
|
||||||
|
|
||||||
return render_template('netclock.html')
|
return render_template('netclock.html')
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ const path = require('path');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
netclock: './js/netclock.js',
|
netclock: './js/netclock.js',
|
||||||
countdown: './js/countdown.js'
|
countdown: './countdown/countdown.js'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CleanWebpackPlugin()
|
new CleanWebpackPlugin()
|
||||||
|
|
Loading…
Reference in a new issue