Compare commits
2 Commits
15bd8ee02f
...
196873aac9
| Author | SHA1 | Date | |
|---|---|---|---|
|
196873aac9
|
|||
|
8e7512965c
|
@@ -23,4 +23,11 @@ def create_app(test_config=None):
|
|||||||
def hello():
|
def hello():
|
||||||
return "'Ello, Wurld!"
|
return "'Ello, Wurld!"
|
||||||
|
|
||||||
|
from . import db
|
||||||
|
db.init_app(app)
|
||||||
|
|
||||||
|
from . import weather
|
||||||
|
app.register_blueprint(weather.bp)
|
||||||
|
app.add_url_rule('/', endpoint='index')
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
46
weather/db.py
Normal file
46
weather/db.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import sqlite3
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import click
|
||||||
|
from flask import current_app, g
|
||||||
|
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
if 'db' not in g:
|
||||||
|
g.db = sqlite3.connect(
|
||||||
|
current_app.config['DATABASE'],
|
||||||
|
detect_types=sqlite3.PARSE_DECLTYPES
|
||||||
|
)
|
||||||
|
g.db.row_factory = sqlite3.Row
|
||||||
|
|
||||||
|
return g.db
|
||||||
|
|
||||||
|
def close_db(e=None):
|
||||||
|
db = g.pop('db', None)
|
||||||
|
|
||||||
|
if db is not None:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
def init_db():
|
||||||
|
db = get_db()
|
||||||
|
|
||||||
|
with current_app.open_resource('schema.sql') as f:
|
||||||
|
db.executescript(f.read().decode('utf8'))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('init-db')
|
||||||
|
def init_db_command():
|
||||||
|
"""Refresh database"""
|
||||||
|
init_db()
|
||||||
|
click.echo('Initialized the database.')
|
||||||
|
|
||||||
|
|
||||||
|
sqlite3.register_converter(
|
||||||
|
"timestamp", lambda v: datetime.fromisoformat(v.decode())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def init_app(app):
|
||||||
|
app.teardown_appcontext(close_db)
|
||||||
|
app.cli.add_command(init_db_command)
|
||||||
|
|
||||||
43
weather/schema.sql
Normal file
43
weather/schema.sql
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
DROP TABLE IF EXISTS periods;
|
||||||
|
DROP TABLE IF EXISTS reports;
|
||||||
|
|
||||||
|
CREATE TABLE "periods" (
|
||||||
|
"id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"report_id" Integer NOT NULL,
|
||||||
|
"period_number" Integer NOT NULL,
|
||||||
|
"name" Text,
|
||||||
|
"start_time" DateTime NOT NULL,
|
||||||
|
"end_time" DateTime NOT NULL,
|
||||||
|
"is_daytime" Integer NOT NULL,
|
||||||
|
"temperature" Integer NOT NULL,
|
||||||
|
"temperature_unit" Text NOT NULL DEFAULT 'F',
|
||||||
|
"precipitation_probability" Integer,
|
||||||
|
"dewpoint_celsius" Numeric,
|
||||||
|
"relative_humidity" Integer,
|
||||||
|
"wind_speed" Text,
|
||||||
|
"wind_direction" Text,
|
||||||
|
"icon_url" Text,
|
||||||
|
"short_forecast" Text,
|
||||||
|
"detailed_forecast" Text,
|
||||||
|
"created_at" DateTime,
|
||||||
|
"updated_at" DateTime,
|
||||||
|
CONSTRAINT "periods_reports_CASCADE_NO ACTION_report_id_id_0" FOREIGN KEY ( "report_id" ) REFERENCES "reports"( "id" )
|
||||||
|
ON DELETE Cascade
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX "periods_report_id_start_time_index" ON "periods"( "report_id", "start_time" );
|
||||||
|
|
||||||
|
CREATE TABLE "reports" (
|
||||||
|
"id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"type" Text NOT NULL,
|
||||||
|
"reported_at" DateTime NOT NULL,
|
||||||
|
"generated_at" DateTime NOT NULL,
|
||||||
|
"latitude" Numeric NOT NULL,
|
||||||
|
"longitude" Numeric NOT NULL,
|
||||||
|
"elevation_meters" Numeric,
|
||||||
|
"created_at" DateTime,
|
||||||
|
"updated_at" DateTime,
|
||||||
|
CONSTRAINT "check ""type"" in ('hourly', 'weekly')" CHECK ("type" in ('hourly', 'weekly')) );
|
||||||
|
|
||||||
|
CREATE INDEX "reports_type_reported_at_index" ON "reports"( "type", "reported_at" );
|
||||||
|
CREATE UNIQUE INDEX "reports_type_reported_at_unique" ON "reports"( "type", "reported_at" );
|
||||||
BIN
weather/static/Abel-Regular.woff2
Normal file
BIN
weather/static/Abel-Regular.woff2
Normal file
Binary file not shown.
54
weather/static/reset.css
Normal file
54
weather/static/reset.css
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/* 1. Use a more-intuitive box-sizing model */
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Remove default margin */
|
||||||
|
*:not(dialog) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Enable keyword animations */
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
html {
|
||||||
|
interpolate-size: allow-keywords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
/* 4. Add accessible line-height */
|
||||||
|
line-height: 1.5;
|
||||||
|
/* 5. Improve text rendering */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6. Improve media defaults */
|
||||||
|
img, picture, video, canvas, svg {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. Inherit fonts for form controls */
|
||||||
|
input, button, textarea, select {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8. Avoid text overflows */
|
||||||
|
p, h1, h2, h3, h4, h5, h6 {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 9. Improve line wrapping */
|
||||||
|
p {
|
||||||
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
10. Create a root stacking context
|
||||||
|
*/
|
||||||
|
#root, #__next {
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
20
weather/static/style.css
Normal file
20
weather/static/style.css
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "Abel";
|
||||||
|
src: url(Abel-Regular.woff2) format("woff2");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-abel {
|
||||||
|
font-family: "Abel", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.antialiased {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-h-screen {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
28
weather/templates/base.html
Normal file
28
weather/templates/base.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
|
||||||
|
<!-- Font preloads (should be done for each font file) -->
|
||||||
|
<link href="{{ url_for('static', filename='Abel-Regular.woff2') }}" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<link href="{{ url_for('static', filename='reset.css') }}" rel="stylesheet" media="screen">
|
||||||
|
<link href="{{ url_for('static', filename='style.css') }}" rel="stylesheet" media="screen">
|
||||||
|
|
||||||
|
<!-- JS that must be executed before the document is loaded -->
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body class="font-abel antialiased">
|
||||||
|
<div id="app" class="min-h-screen">
|
||||||
|
{% for message in get_flashed_messages() %}
|
||||||
|
<div class="flash">{{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
weather/templates/weather/index.html
Normal file
9
weather/templates/weather/index.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
Hey what's going on on this side?
|
||||||
|
|
||||||
|
{% for period in periods %}
|
||||||
|
<p>{{ period['start_time'] }} - {{ period['end_time'] }} | {{ period['temperature'] }}{{ period['temperature_unit'] }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
18
weather/weather.py
Normal file
18
weather/weather.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from flask import (
|
||||||
|
Blueprint, flash, g, render_template, request, url_for
|
||||||
|
)
|
||||||
|
from werkzeug.exceptions import abort
|
||||||
|
|
||||||
|
from weather.db import get_db
|
||||||
|
|
||||||
|
bp = Blueprint('weather', __name__)
|
||||||
|
|
||||||
|
@bp.route('/')
|
||||||
|
def index():
|
||||||
|
db = get_db()
|
||||||
|
periods = db.execute(
|
||||||
|
'SELECT *'
|
||||||
|
' FROM `periods`'
|
||||||
|
' ORDER BY `id` DESC'
|
||||||
|
).fetchall()
|
||||||
|
return render_template('weather/index.html', periods=periods)
|
||||||
Reference in New Issue
Block a user