dockerized it
This commit is contained in:
		
							parent
							
								
									a8b6789295
								
							
						
					
					
						commit
						e64f94cfd9
					
				
							
								
								
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| FROM debian8_python3 | ||||
| 
 | ||||
| ADD app /app | ||||
| RUN pip3 install -r /app/requirements.txt | ||||
| RUN (cd /app; python3 init.py) | ||||
| ENTRYPOINT python3 /app/main.py | ||||
							
								
								
									
										3
									
								
								app/init.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/init.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| from main import init_db | ||||
| 
 | ||||
| init_db() | ||||
							
								
								
									
										95
									
								
								app/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								app/main.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| 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 | ||||
| from contextlib import closing | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| def init_db(): | ||||
|     with closing(connect_db()) as db: | ||||
|         with app.open_resource('schema.sql', mode='r') as f: | ||||
|             db.cursor().executescript(f.read()) | ||||
|         db.commit() | ||||
| 
 | ||||
| @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) | ||||
| 
 | ||||
| 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.strftime(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, host='0.0.0.0') | ||||
							
								
								
									
										2
									
								
								app/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| #db-sqlite3 | ||||
| Flask | ||||
							
								
								
									
										7
									
								
								app/schema.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/schema.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| 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 | ||||
| ); | ||||
							
								
								
									
										
											BIN
										
									
								
								app/static/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.9 KiB | 
							
								
								
									
										4
									
								
								app/static/jquery-1.11.2.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								app/static/jquery-1.11.2.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										19
									
								
								app/static/main.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/static/main.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										1
									
								
								app/static/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/main.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| 
 | ||||
							
								
								
									
										11
									
								
								app/static/modernizr-2.8.3-respond-1.4.2.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/static/modernizr-2.8.3-respond-1.4.2.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								app/static/normalize.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/normalize.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| /*! 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} | ||||
							
								
								
									
										5
									
								
								app/templates/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/templates/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| {% extends "layout.html" %} | ||||
| {% block body %} | ||||
| 	<a href='{{ url_for('getPitStops') }}'>Pitstop List</a> | ||||
| 	<a href='{{ url_for('createPitStopForm') }}'>Create Pitstop</a> | ||||
| {% endblock %}	 | ||||
							
								
								
									
										61
									
								
								app/templates/layout.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								app/templates/layout.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| <!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"> | ||||
| 
 | ||||
|             <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> | ||||
| 		<!-- 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> | ||||
| 
 | ||||
							
								
								
									
										56
									
								
								app/templates/newPitStopForm.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								app/templates/newPitStopForm.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| {% 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> | ||||
| {% 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 %}	 | ||||
							
								
								
									
										53
									
								
								app/templates/pitstops.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								app/templates/pitstops.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| {% 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> | ||||
| {% 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 %}	 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Joachim Lusiardi
						Joachim Lusiardi