From 1ba8fc71a8aefd5370fe35a4688973de4ad4552d Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sat, 12 Sep 2020 19:51:47 +0200 Subject: [PATCH] Refactor, implement countdown --- api/__init__.py | 0 api/v1/__init__.py | 7 --- api/v1/clock.py | 7 --- api/v1/countdown.py | 31 ------------ countdown/__init__.py | 7 ++- api.py => countdown/api.py | 6 +-- countdown/countdown.js | 48 +++++++++++++++++++ countdown/countdown.scss | 7 +++ countdown/forms.py | 3 +- .../templates/countdown}/countdown.html | 9 +++- .../templates/countdown}/countdown_admin.html | 0 countdown/views.py | 19 ++++---- css/netclock.scss | 14 +++++- forms.py | 4 -- js/countdown.js | 24 ---------- js/netclock.js | 1 + netclock.py | 4 +- package-lock.json | 5 ++ package.json | 3 +- querysheet.http | 6 +++ views.py | 4 +- webpack.common.js | 2 +- 22 files changed, 111 insertions(+), 100 deletions(-) delete mode 100644 api/__init__.py delete mode 100644 api/v1/__init__.py delete mode 100644 api/v1/clock.py delete mode 100644 api/v1/countdown.py rename api.py => countdown/api.py (82%) create mode 100644 countdown/countdown.js create mode 100644 countdown/countdown.scss rename {templates => countdown/templates/countdown}/countdown.html (63%) rename {templates => countdown/templates/countdown}/countdown_admin.html (100%) delete mode 100644 forms.py delete mode 100644 js/countdown.js create mode 100644 querysheet.http diff --git a/api/__init__.py b/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/api/v1/__init__.py b/api/v1/__init__.py deleted file mode 100644 index e47b422..0000000 --- a/api/v1/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from flask import Blueprint - -api_v1 = Blueprint('api.v1', __name__) - -import api.v1.clock -import api.v1.countdown - diff --git a/api/v1/clock.py b/api/v1/clock.py deleted file mode 100644 index 437d97a..0000000 --- a/api/v1/clock.py +++ /dev/null @@ -1,7 +0,0 @@ -from time import time - -from api.v1 import api_v1 - -@api_v1.route('/time/') -def netime_time(t1: float) -> str: - return str(time()) diff --git a/api/v1/countdown.py b/api/v1/countdown.py deleted file mode 100644 index 99a843b..0000000 --- a/api/v1/countdown.py +++ /dev/null @@ -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/', 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 diff --git a/countdown/__init__.py b/countdown/__init__.py index 6a2e550..8b42197 100644 --- a/countdown/__init__.py +++ b/countdown/__init__.py @@ -1,6 +1,5 @@ from flask import Blueprint -app = Blueprint('countdown', __name__) - -import views -import apii +app = Blueprint('countdown', __name__, template_folder='templates') +from . import views +from . import api diff --git a/api.py b/countdown/api.py similarity index 82% rename from api.py rename to countdown/api.py index bfa631c..3980dfe 100644 --- a/api.py +++ b/countdown/api.py @@ -5,11 +5,11 @@ from time import time import uuid import struct -from countdown import api_api +from . import app db = Walrus(host='localhost', port=6379, db=0) -@app.route('/api/vi1/', methods=['GET']) +@app.route('/api/v1/', methods=['GET']) def get_countdown(id): ct = db.Hash(str(id)) @@ -18,7 +18,7 @@ def get_countdown(id): return resp -@api_v1.route('/api/v1', methods=['POST']) +@app.route('/api/v1', methods=['POST']) def create_countdown(): countdown = request.json ct_id = str(uuid.uuid4()) diff --git a/countdown/countdown.js b/countdown/countdown.js new file mode 100644 index 0000000..ed75a26 --- /dev/null +++ b/countdown/countdown.js @@ -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}`; + diff --git a/countdown/countdown.scss b/countdown/countdown.scss new file mode 100644 index 0000000..dda5231 --- /dev/null +++ b/countdown/countdown.scss @@ -0,0 +1,7 @@ +#countdown { + font-size: 3em; +} + +#subtext { + margin-top: 1em; +} diff --git a/countdown/forms.py b/countdown/forms.py index 6684e84..e81027c 100644 --- a/countdown/forms.py +++ b/countdown/forms.py @@ -1,4 +1,5 @@ -from flask_wtf import FlaskForm, TimeField +from flask_wtf import FlaskForm +from wtforms import TimeField class CountdownAdminForm(FlaskForm): totalTime = TimeField('Time') diff --git a/templates/countdown.html b/countdown/templates/countdown/countdown.html similarity index 63% rename from templates/countdown.html rename to countdown/templates/countdown/countdown.html index 5d3c123..54fee78 100644 --- a/templates/countdown.html +++ b/countdown/templates/countdown/countdown.html @@ -2,10 +2,15 @@ {% block title %}Countdown{% endblock title %} {% block body %} -Hello from Countdown -
+
+

+

+

{% endblock body %} {% block scripts %} + {% endblock scripts %} diff --git a/templates/countdown_admin.html b/countdown/templates/countdown/countdown_admin.html similarity index 100% rename from templates/countdown_admin.html rename to countdown/templates/countdown/countdown_admin.html diff --git a/countdown/views.py b/countdown/views.py index 33aabdd..e05194e 100644 --- a/countdown/views.py +++ b/countdown/views.py @@ -1,19 +1,20 @@ from flask import render_template, request, flash, redirect, url_for -from countdown import app, forms +from . import app +from . import forms -@app.route('/', methods=['GET']) -def countdown(id): - return render_template('countdown.html', id) +@app.route('/', methods=['GET']) +def countdown(countdown_id): + return render_template('countdown/countdown.html', countdown_id=countdown_id) @app.route('/', methods=['GET', 'POST', 'PUT']) def countdown_admin(): - form = CountdownAdminForm(request.form) + form = forms.CountdownAdminForm(request.form) if request.method == 'POST' and form.validate(): - user = User(form.username.data, form.email.data, - form.password.data) - db_session.add(user) + # user = User(form.username.data, form.email.data, + # form.password.data) + # db_session.add(user) flash('Thanks for registering') 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) diff --git a/css/netclock.scss b/css/netclock.scss index b05faf8..41599a3 100644 --- a/css/netclock.scss +++ b/css/netclock.scss @@ -1,3 +1,13 @@ -body { - color: red; +@import "~reset-css/sass/reset"; + +html, body { + height: 100%; +} + +.center { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100%; } diff --git a/forms.py b/forms.py deleted file mode 100644 index 6684e84..0000000 --- a/forms.py +++ /dev/null @@ -1,4 +0,0 @@ -from flask_wtf import FlaskForm, TimeField - -class CountdownAdminForm(FlaskForm): - totalTime = TimeField('Time') diff --git a/js/countdown.js b/js/countdown.js deleted file mode 100644 index 334200f..0000000 --- a/js/countdown.js +++ /dev/null @@ -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); diff --git a/js/netclock.js b/js/netclock.js index 0f584c1..72a0a18 100644 --- a/js/netclock.js +++ b/js/netclock.js @@ -1,5 +1,6 @@ import '../css/netclock.scss'; import log from 'loglevel'; +import $ from 'jquery'; if (process.env.LOG_LEVEL) { log.setDefaultLevel(process.env.LOG_LEVEL); diff --git a/netclock.py b/netclock.py index 17018a9..1bb05ed 100644 --- a/netclock.py +++ b/netclock.py @@ -1,7 +1,7 @@ from flask import Flask app = Flask(__name__) -from api.v1 import api_v1 -app.register_blueprint(api_v1, url_prefix="/api/v1") +from countdown import app as countdown +app.register_blueprint(countdown, url_prefix="/countdown") import views diff --git a/package-lock.json b/package-lock.json index 372486a..0daa5ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2991,6 +2991,11 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "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": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", diff --git a/package.json b/package.json index 0119bdb..a8f9bb5 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "jquery": "^3.5.1", - "loglevel": "^1.7.0" + "loglevel": "^1.7.0", + "reset-css": "^5.0.1" } } diff --git a/querysheet.http b/querysheet.http new file mode 100644 index 0000000..b9e82e1 --- /dev/null +++ b/querysheet.http @@ -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"} diff --git a/views.py b/views.py index ce423b8..c200b43 100644 --- a/views.py +++ b/views.py @@ -1,9 +1,9 @@ from flask import Flask, render_template, request, flash from netclock import app -from forms import CountdownAdminForm - @app.route('/') def index(): + breakpoint() + return render_template('netclock.html') diff --git a/webpack.common.js b/webpack.common.js index 996b6d1..dee13bc 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -4,7 +4,7 @@ const path = require('path'); module.exports = { entry: { netclock: './js/netclock.js', - countdown: './js/countdown.js' + countdown: './countdown/countdown.js' }, plugins: [ new CleanWebpackPlugin()