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