Add base framework
Add Templates Add Static Files Add SQL
This commit is contained in:
parent
337811c5f6
commit
661b7bd2e6
@ -22,4 +22,14 @@ def create_app(test_config=None):
|
|||||||
def hello():
|
def hello():
|
||||||
return 'Hello, World!'
|
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
|
return app
|
59
period/cycles.py
Normal file
59
period/cycles.py
Normal 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
37
period/db.py
Normal 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
8
period/schema.sql
Normal 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
26
period/static/style.css
Normal 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; }
|
17
period/templates/base.html
Normal file
17
period/templates/base.html
Normal 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>
|
15
period/templates/cycle/create.html
Normal file
15
period/templates/cycle/create.html
Normal 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 %}
|
22
period/templates/cycle/index.html
Normal file
22
period/templates/cycle/index.html
Normal 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 %}
|
Loading…
Reference in New Issue
Block a user