Refactor, implement countdown

This commit is contained in:
Armin Friedl 2020-09-12 19:51:47 +02:00
parent f78c9d349a
commit 1ba8fc71a8
22 changed files with 111 additions and 100 deletions

View file

View file

@ -1,7 +0,0 @@
from flask import Blueprint
api_v1 = Blueprint('api.v1', __name__)
import api.v1.clock
import api.v1.countdown

View file

@ -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())

View file

@ -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

View file

@ -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

View file

@ -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
View 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
View file

@ -0,0 +1,7 @@
#countdown {
font-size: 3em;
}
#subtext {
margin-top: 1em;
}

View file

@ -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')

View file

@ -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 %}

View file

@ -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)

View file

@ -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%;
} }

View file

@ -1,4 +0,0 @@
from flask_wtf import FlaskForm, TimeField
class CountdownAdminForm(FlaskForm):
totalTime = TimeField('Time')

View file

@ -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);

View file

@ -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);

View file

@ -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
View file

@ -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",

View file

@ -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
View 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"}

View file

@ -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')

View file

@ -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()