Add base framework

Add Templates
Add Static Files
Add SQL
This commit is contained in:
Alexander Hosking 2022-04-13 19:12:49 -04:00
parent 337811c5f6
commit 661b7bd2e6
8 changed files with 194 additions and 0 deletions

View File

@ -22,4 +22,14 @@ def create_app(test_config=None):
def hello():
return 'Hello, World!'
from . import db
db.init_app(app)
# from . import auth
# app.register_blueprint(auth.bp)
from . import cycles
app.register_blueprint(cycles.bp)
app.add_url_rule('/', endpoint='index')
return app

59
period/cycles.py Normal file
View File

@ -0,0 +1,59 @@
from itertools import cycle
from tracemalloc import start
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort
import pendulum
# from flaskr.auth import login_required
from period.db import get_db
bp = Blueprint('cycles', __name__)
@bp.route('/')
def index():
db = get_db()
cycles = db.execute(
'SELECT id, start_time, end_time, cycle_length'
' FROM cycle ORDER BY start_time DESC'
).fetchall()
return render_template('cycle/index.html', cycles=cycles)
@bp.route('/create', methods=('GET', 'POST'))
def create():
if request.method == 'POST':
start_time = pendulum.from_format(request.form['start_time'], 'YYYY-MM-DD')
# start_time = start_time.to_datetime_string()
try:
end_time = pendulum.from_format(request.form['end_time'], 'YYYY-MM-DD')
except ValueError:
end_time = pendulum.datetime(1900,1,1)
error = None
print(request.form['end_time'])
if not start_time:
error = "You must provide a start date"
if end_time > start_time:
cycle_length = (end_time - start_time).days
else:
cycle_length = (pendulum.now() - start_time).days
if error is not None:
flash(error)
else:
db = get_db()
if end_time > start_time:
db.execute(
'INSERT INTO cycle (start_time, end_time, cycle_length) VALUES (?, ?, ?)',
(start_time.to_datetime_string(), end_time.to_datetime_string(), cycle_length)
)
else:
db.execute(
'INSERT INTO cycle (start_time, cycle_length) VALUES (?, ?)',
(start_time.to_datetime_string(), cycle_length)
)
db.commit()
return redirect(url_for('index'))
return render_template('cycle/create.html')

37
period/db.py Normal file
View File

@ -0,0 +1,37 @@
import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext
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')
@with_appcontext
def init_db_command():
init_db()
click.echo('Initializing the database.')
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)

8
period/schema.sql Normal file
View File

@ -0,0 +1,8 @@
DROP TABLE IF EXISTS cycle;
CREATE TABLE cycle (
id INTEGER PRIMARY KEY AUTOINCREMENT,
start_time DATETIME,
end_time DATETIME,
cycle_length INTEGER
);

26
period/static/style.css Normal file
View File

@ -0,0 +1,26 @@
html { font-family: sans-serif; background: #eee; padding: 1rem; }
body { max-width: 960px; margin: 0 auto; background: white; }
h1 { font-family: serif; color: #377ba8; margin: 1rem 0; }
a { color: #377ba8; }
hr { border: none; border-top: 1px solid lightgray; }
nav { background: lightgray; display: flex; align-items: center; padding: 0 0.5rem; }
nav h1 { flex: auto; margin: 0; }
nav h1 a { text-decoration: none; padding: 0.25rem 0.5rem; }
nav ul { display: flex; list-style: none; margin: 0; padding: 0; }
nav ul li a, nav ul li span, header .action { display: block; padding: 0.5rem; }
.content { padding: 0 1rem 1rem; }
.content > header { border-bottom: 1px solid lightgray; display: flex; align-items: flex-end; }
.content > header h1 { flex: auto; margin: 1rem 0 0.25rem 0; }
.flash { margin: 1em 0; padding: 1em; background: #cae6f6; border: 1px solid #377ba8; }
.post > header { display: flex; align-items: flex-end; font-size: 0.85em; }
.post > header > div:first-of-type { flex: auto; }
.post > header h1 { font-size: 1.5em; margin-bottom: 0; }
.post .about { color: slategray; font-style: italic; }
.post .body { white-space: pre-line; }
.content:last-child { margin-bottom: 0; }
.content form { margin: 1em 0; display: flex; flex-direction: column; }
.content label { font-weight: bold; margin-bottom: 0.5em; }
.content input, .content textarea { margin-bottom: 1em; }
.content textarea { min-height: 12em; resize: vertical; }
input.danger { color: #cc2f2e; }
input[type=submit] { align-self: start; min-width: 10em; }

View File

@ -0,0 +1,17 @@
<!doctype html>
<title>{% block title %}{% endblock %} - Period</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
<h1>Period</h1>
<ul>
</ul>
</nav>
<section class="content">
<header>
{% block header %}{% endblock %}
</header>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block content %}{% endblock %}
</section>

View File

@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}New Cycle{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="start_time">Start Time</label>
<input name="start_time" id="title" value="{{ request.form['start_time'] }}" required type="date">
<label for="end_time">End Time</label>
<input name="end_time" id="end_time" value="{{ request.form['end_time'] }}" type="date">
<input type="submit" value="Save">
</form>
{% endblock %}

View File

@ -0,0 +1,22 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Cycles{% endblock %}</h1><a class="action" href="{{ url_for('cycles.create') }}">New</a>
{% endblock %}
{% block content %}
{% for cycle in cycles %}
<article class="post">
<header>
<div>
<h1>{{ cycle['id'] }}</h1>
<div class="about">Started: {{ cycle['start_time'] }} and ended: {{ cycle['end_time'] }}</div>
</div>
</header>
<p class="body">Cycle Length: {{ cycle['cycle_length'] }} days.</p>
</article>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}