dockerized it

This commit is contained in:
Joachim Lusiardi 2015-03-07 09:51:38 +01:00
parent 0a778295b6
commit 00c6f6d71d
17 changed files with 43 additions and 332 deletions

View File

@ -1,6 +1,9 @@
FROM debian8_python3
ADD app /app
RUN pip3 install -r /app/requirements.txt
RUN (cd /app; python3 init.py)
RUN pip3 install -r /app/requirements.txt; \
mkdir /data
VOLUME ["/data"]
ENTRYPOINT python3 /app/main.py

View File

@ -5,9 +5,10 @@ from flask import render_template
from flask import url_for
from flask import request, redirect, g
from contextlib import closing
import os, os.path
app = Flask(__name__)
DATABASE = '/tmp/rollerverbrauch.db'
DATABASE = '/data/rollerverbrauch.db'
DEBUG = True
SECRET_KEY = 'development key'
USERNAME = 'admin'
@ -21,7 +22,9 @@ def connect_db():
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
sql_commands = f.read()
print(sql_commands)
db.cursor().executescript(sql_commands)
db.commit()
@app.before_request
@ -62,6 +65,34 @@ def getPitStops():
data = {'pitstops': preparePitStops(getAllPitStops())}
return render_template('pitstops.html', data=data)
@app.route('/statistics', methods=['GET'])
def getStatistics():
pitstops = getAllPitStops()
count = len(pitstops)
distance = 0
sumLitres = 0
averageDistance = 0
averageLitresFuelled = 0
averageLitresUsed = 0
count = len(pitstops)
if len(pitstops) > 0:
sumLitres = 0
for pitstop in pitstops:
sumLitres += pitstop['litres']
averageLitresFuelled = round(sumLitres/count, 2)
if len(pitstops) > 1:
distance = pitstops[-1]['odometer'] - pitstops[0]['odometer']
averageDistance = round(distance/(count - 1), 2)
averageLitresUsed = round(100 * (sumLitres-pitstops[0]['litres'])/distance, 2)
data = {
'distance':distance,
'count': count,
'litres': round(sumLitres, 2),
'averageDistance': averageDistance,
'averageListresFuelled': averageLitresFuelled,
'averageListresUsed': averageLitresUsed}
return render_template('statistics.html', data=data)
def preparePitStops(pitstops):
for index in range(1, len(pitstops)):
last = pitstops[index - 1]
@ -92,4 +123,6 @@ def addPitStop(date, odometer, litres):
if __name__ == '__main__':
if not os.path.isfile(DATABASE) or os.stat(DATABASE).st_size == 0:
init_db()
app.run(debug=True, host='0.0.0.0')

View File

@ -3,6 +3,7 @@
{% block navigation %}
<li><a href='{{ url_for('getPitStops') }}'>Home</a></li>
<li><a href='{{ url_for('createPitStopForm') }}' class="active">Create Pitstop</a></li>
<li><a href='{{ url_for('getStatistics') }}'>Statistics</a></li>
{% endblock %}
{% block body %}

View File

@ -3,6 +3,7 @@
{% block navigation %}
<li><a href='{{ url_for('getPitStops') }}' class="active">Home</a></li>
<li><a href='{{ url_for('createPitStopForm') }}'>Create Pitstop</a></li>
<li><a href='{{ url_for('getStatistics') }}'>Statistics</a></li>
{% endblock %}
{% block body %}
@ -49,5 +50,5 @@
</td>
</tr>
{% endfor %}
</table
</table>
{% endblock %}

108
main.py
View File

@ -1,108 +0,0 @@
import sqlite3
from datetime import datetime
from flask import Flask
from flask import render_template
from flask import url_for
from flask import request, redirect, g
app = Flask(__name__)
DATABASE = '/tmp/rollerverbrauch.db'
DEBUG = True
SECRET_KEY = 'development key'
USERNAME = 'admin'
PASSWORD = 'default'
app.config.from_object(__name__)
def connect_db():
result = sqlite3.connect(app.config['DATABASE'])
return result
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
db = getattr(g, 'db', None)
if db is not None:
db.close()
@app.route('/')
def index():
#data = {'pitstopsUrl': url_for('getPitStops')}
#return render_template('index.html', data=data)
return redirect(url_for('getPitStops'))
@app.route('/pitstops', methods=['POST'])
def createPitStop():
date = request.form['date']
odometer = request.form['odometer']
litres = request.form['litres']
# error checking here
addPitStop(date, odometer, litres)
return redirect(url_for('getPitStops'))
@app.route('/pitstops/createForm', methods=['GET'])
def createPitStopForm():
data = {'last':getLastPitStop(), 'error': None}
return render_template('newPitStopForm.html', data=data)
@app.route('/pitstops', methods=['GET'])
def getPitStops():
data = {'pitstops': preparePitStops(getAllPitStops())}
return render_template('pitstops.html', data=data)
@app.route('/statistics', methods=['GET'])
def getStatistics():
pitstops = getAllPitStops()
distance = pitstops[-1]['odometer'] - pitstops[0]['odometer']
count = len(pitstops)
averageDistance = round(distance/count, 2)
sumLitres = 0
for pitstop in pitstops:
sumLitres += pitstop['litres']
averageLitresFuelled = round(sumLitres/count, 2)
averageLitresUsed = round(100 * sumLitres/distance, 2)
data = {
'distance':distance,
'count': count,
'litres': round(sumLitres, 2),
'averageDistance': averageDistance,
'averageListresFuelled': averageLitresFuelled,
'averageListresUsed': averageLitresUsed}
return render_template('statistics.html', data=data)
def preparePitStops(pitstops):
for index in range(1, len(pitstops)):
last = pitstops[index - 1]
curr = pitstops[index]
curr['distance'] = curr['odometer'] - last['odometer']
curr['average'] = round(100 * curr['litres']/curr['distance'], 2)
last_date = datetime.strptime(last['date'], '%Y-%m-%d')
curr_date = datetime.strptime(curr['date'], '%Y-%m-%d')
curr['days'] = (curr_date - last_date).days
return pitstops
def getLastPitStop():
cur = g.db.execute('select date, odometer, litres from pitstops order by date desc limit 1')
pitstops = [dict(date=row[0], odometer=row[1], litres=row[2]) for row in cur.fetchall()]
if len(pitstops) == 0:
return {'date': datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d'), 'odometer': 0, 'litres': 0}
return pitstops[0]
def getAllPitStops():
cur = g.db.execute('select date, odometer, litres from pitstops order by id asc')
pitstops = [dict(date=row[0], odometer=row[1], litres=row[2]) for row in cur.fetchall()]
return pitstops
def addPitStop(date, odometer, litres):
g.db.execute('insert into pitstops (date, odometer, litres) values (?, ?, ?)', [date, odometer, litres])
g.db.commit()
if __name__ == '__main__':
app.run(debug=True)

View File

@ -1,7 +0,0 @@
drop table if exists pitstops;
create table pitstops (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`date` TEXT NOT NULL,
`odometer` INTEGER NOT NULL,
`litres` REAL NOT NULL
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,19 +0,0 @@
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
th {
text-align: center;
padding-left: 10px;
padding-right: 10px;
}
td {
text-align: right;
padding-left: 10px;
padding-right: 10px;
}

View File

@ -1 +0,0 @@

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}

View File

@ -1,5 +0,0 @@
{% extends "layout.html" %}
{% block body %}
<a href='{{ url_for('getPitStops') }}'>Pitstop List</a>
<a href='{{ url_for('createPitStopForm') }}'>Create Pitstop</a>
{% endblock %}

View File

@ -1,60 +0,0 @@
<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang=""> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang=""> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9" lang=""> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang=""> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Rollerverbrauch</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link rel="apple-touch-icon" href="{{ url_for('static', filename='apple-touch-icon.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='normalize.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='main.css') }}">
<script src="{{ url_for('static', filename='modernizr-2.8.3-respond-1.4.2.min.js') }}"></script>-->
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='main.css') }}">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ url_for('getPitStops') }}">Rollerverbrauch</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
{% block navigation %}
{% endblock %}
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
<div class="starter-template">
{% block body %}
{% endblock %}
</div>
</div>
</body>
</html>

View File

@ -1,57 +0,0 @@
{% extends "layout.html" %}
{% block navigation %}
<li><a href='{{ url_for('getPitStops') }}'>Home</a></li>
<li><a href='{{ url_for('createPitStopForm') }}' class="active">Create Pitstop</a></li>
<li><a href='{{ url_for('getStatistics') }}'>Statistics</a></li>
{% endblock %}
{% block body %}
{% if data.error %}
<div>
<p class='error'><strong>Error:</strong> {{ data.error }}</p>
</div>
{% endif %}
<form class="form-horizontal" id='createPitStop' action="{{ url_for('createPitStop') }}" method='post'>
<fieldset>
<!-- Form Name -->
<legend>Create Pitstop</legend>
<!-- Text input-->
<div class="control-group">
<label class="control-label" for="date">Date of Pitstop</label>
<div class="controls">
<input id="date" name="date" placeholder="" class="input-large" required="" type="date" value='{{ data.last.date }}' />
</div>
</div>
<!-- Text input-->
<div class="control-group">
<label class="control-label" for="odometer">Odometer</label>
<div class="controls">
<input id="odometer" name="odometer" placeholder="" class="input-large" required="" type="text" value='{{ data.last.odometer }}' />
</div>
</div>
<!-- Text input-->
<div class="control-group">
<label class="control-label" for="litres">Litres</label>
<div class="controls">
<input id="litres" name="litres" placeholder="" class="input-large" required="" type="text" value='{{ data.last.litres }}' />
</div>
</div>
<!-- Button (Double) -->
<div class="control-group">
<label class="control-label" for="buttonLogId"></label>
<div class="controls">
<button id="buttonLogId" name="buttonLogId" class="btn btn-success" onclick="document.getElementById('createPitStop').submit();">Log Pitstop</button>
<button id="buttonAbortId" type="button" name="buttonAbortId" class="btn btn-warning" onclick="window.location.href='{{ url_for('getPitStops') }}'">Abort</button>
</div>
</div>
</fieldset>
</form>
{% endblock %}

View File

@ -1,54 +0,0 @@
{% extends "layout.html" %}
{% block navigation %}
<li><a href='{{ url_for('getPitStops') }}' class="active">Home</a></li>
<li><a href='{{ url_for('createPitStopForm') }}'>Create Pitstop</a></li>
<li><a href='{{ url_for('getStatistics') }}'>Statistics</a></li>
{% endblock %}
{% block body %}
<table>
<tr>
<th>
Date
</th>
<th>
Day
</th>
<th>
Odometer
</th>
<th>
Distance
</th>
<th>
Litres
</th>
<th>
Average
</th>
</tr>
{% for pitstop in data['pitstops'] %}
<tr>
<td>
{{pitstop.date}}
</td>
<td>
{% if pitstop.days %}{{pitstop.days}}{% else %} --{% endif %} days
</td>
<td>
{{pitstop.odometer}} km
</td>
<td>
{% if pitstop.distance %}{{pitstop.distance}}{% else %} --{% endif %} km
</td>
<td>
{{pitstop.litres}} l
</td>
<td>
{% if pitstop.average %}{{pitstop.average}}{% else %} --{% endif %} l/100km
</td>
</tr>
{% endfor %}
</table>
{% endblock %}