progress
This commit is contained in:
parent
3ae7b05b9b
commit
691d54ee3e
|
@ -59,9 +59,9 @@ ENV PATH $PYENV_ROOT/bin:$PATH
|
|||
## Python
|
||||
#######################################################################33
|
||||
RUN pyenv install $PYTHON_VERSION && \
|
||||
pyenv global $PYTHON_VERISON && \
|
||||
pip3 install pipenv
|
||||
pyenv global $PYTHON_VERISON
|
||||
|
||||
RUN ls $PYENV_ROOT/bin/
|
||||
#######################################################################33
|
||||
## Install Deps
|
||||
#######################################################################33
|
||||
|
|
4
Makefile
4
Makefile
|
@ -1,4 +1,6 @@
|
|||
export PYTHONPATH =: $(PWD)
|
||||
export DOCKER_HOST := ssh://datavi.be
|
||||
export PYTHONPATH := $(PWD)
|
||||
export SQLITE_FILENAME := ./db.sqlite
|
||||
|
||||
default: docker
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ from sqlalchemy.ext.declarative import declarative_base
|
|||
from bottle.ext import sqlalchemy
|
||||
from pprint import pprint
|
||||
from sqlalchemy import create_engine
|
||||
import urllib.parse
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
|
@ -25,7 +26,7 @@ PORT = os.environ.get('PORT', 8080)
|
|||
DEBUG = os.environ.get('DEBUG', False)
|
||||
SQLITE_FILENAME = os.environ.get('SQLITE_FILENAME','/data/db.sqlite')
|
||||
DATABASE_URL = os.environ.get('DATABASE_URL','sqlite:///' + SQLITE_FILENAME)
|
||||
ADMINPSK = os.environ.get('ADMINPSK','hunter2')
|
||||
ADMIN_PSK = os.environ.get('ADMIN_PSK','hunter2')
|
||||
|
||||
# sorry for global
|
||||
SQLBASE = declarative_base()
|
||||
|
@ -109,22 +110,57 @@ def serve():
|
|||
# FIXME make this use sessions instead of just storing PSK in a cookie
|
||||
# https://bottlepy.org/docs/dev/recipes.html
|
||||
@app.get('/admin')
|
||||
def adminpage():
|
||||
c = request.get_cookie("adminpw")
|
||||
def adminpage(db):
|
||||
c = request.get_cookie("psk")
|
||||
if not c:
|
||||
redirect('/login')
|
||||
return
|
||||
if c != ADMIN_PSK:
|
||||
redirect('/logout')
|
||||
return
|
||||
tvs = db.query(TV).order_by(TV.lastSeen)
|
||||
return template('adminpanel', tvs=tvs, version=VERSION)
|
||||
|
||||
# FIXME check their 'adminpw' cookie here, redirect to /loign
|
||||
return "Hello World!"
|
||||
|
||||
# here we ask for a password and cookie them and bounce them back to /admin
|
||||
@app.get('/login')
|
||||
def checklogin():
|
||||
@app.post('/admin')
|
||||
def savesettings():
|
||||
c = request.get_cookie("psk")
|
||||
if not c:
|
||||
redirect('/login')
|
||||
return
|
||||
if c != ADMIN_PSK:
|
||||
redirect('/logout')
|
||||
return
|
||||
raise NotImplementedError()
|
||||
#response.set_cookie("adminpw", whatever)
|
||||
redirect('/login')
|
||||
|
||||
@app.get('/logut')
|
||||
# here we ask for a password:
|
||||
@app.get('/login')
|
||||
def loginform():
|
||||
msg = request.GET.msg
|
||||
return template('loginform', version=VERSION, msg=msg)
|
||||
|
||||
@app.post('/checklogin')
|
||||
def checklogin():
|
||||
attemptedPass = request.forms.get('password')
|
||||
if not attemptedPass:
|
||||
redirect(
|
||||
'/login?msg=' +
|
||||
urllib.parse.quote_plus(u"Incorrect password.")
|
||||
)
|
||||
return
|
||||
if attemptedPass != ADMIN_PSK:
|
||||
redirect(
|
||||
'/login?msg=' +
|
||||
urllib.parse.quote_plus(u"Incorrect password.")
|
||||
)
|
||||
return
|
||||
# password is right, cookie them:
|
||||
response.set_cookie("psk", attemptedPass)
|
||||
redirect('/admin')
|
||||
return
|
||||
|
||||
@app.get('/logout')
|
||||
def logout():
|
||||
response.set_cookie("adminpw", "")
|
||||
response.set_cookie("psk", "")
|
||||
redirect('/login')
|
||||
|
||||
app.run(host='0.0.0.0', port=PORT, debug=DEBUG)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
% rebase('base.tpl', refresh=None, title='tvid administration')
|
||||
|
||||
|
||||
<p><small>Powered by tvid v{{version}}</small></p>
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ get('title','tvid') }}</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
% if defined('refresh'):
|
||||
<meta http-equiv="refresh" content="{{ get('refresh',60) }}">
|
||||
% end
|
||||
% include('htmlheader.tpl')
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
{{!base}}
|
||||
</body>
|
||||
</html>
|
|
@ -1,20 +1,12 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>tv info page</title>
|
||||
<meta http-equiv="refresh" content="60">
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<p>
|
||||
<i>Display ID:</i>
|
||||
</p>
|
||||
<h1>{{id}}</h1>
|
||||
% rebase('base.tpl', refresh='60')
|
||||
<div id="main">
|
||||
<p>
|
||||
<i>Display ID:</i>
|
||||
</p>
|
||||
<h1>{{id}}</h1>
|
||||
|
||||
<small>(They're only letters. I like India, O like
|
||||
Oscar.)</small>
|
||||
<small>(They're only letters. I like India, O like
|
||||
Oscar.)</small>
|
||||
|
||||
<p><small>Powered by tvid v{{version}}</small></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<p><small>Powered by tvid v{{version}}</small></p>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
% rebase('base.tpl', refresh=None, title=None)
|
||||
|
||||
% if defined('msg') and msg:
|
||||
<div class="card card-body bg-light">{{msg}}</div>
|
||||
% end
|
||||
|
||||
<div class="wrapper fadeInDown">
|
||||
<div id="formContent">
|
||||
<!-- Tabs Titles -->
|
||||
|
||||
<div class="fadeIn first">
|
||||
<h2>tvid administration</h2>
|
||||
</div>
|
||||
|
||||
<!-- Login Form -->
|
||||
<form action="/checklogin" method="post">
|
||||
<input type="password" id="password" class="fadeIn third"
|
||||
name="password" placeholder="password">
|
||||
<input type="submit" class="fadeIn fourth" value="Log In">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p><small>Powered by tvid v{{version}}</small></p>
|
|
@ -1,10 +1,2 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>tv info page</title>
|
||||
<meta http-equiv="refresh" content="60; url=/">
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Please enable cookies, they're required.</h1>
|
||||
</body>
|
||||
</html>
|
||||
% rebase('base.tpl', refresh='60')
|
||||
<h1>Please enable cookies, they're required.</h1>
|
||||
|
|
246
views/style.tpl
246
views/style.tpl
|
@ -8,3 +8,249 @@ body {
|
|||
h1 {
|
||||
font-size: 48pt;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #92badd;
|
||||
display:inline-block;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
display:inline-block;
|
||||
margin: 40px 8px 10px 8px;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
|
||||
/* STRUCTURE */
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#formContent {
|
||||
-webkit-border-radius: 10px 10px 10px 10px;
|
||||
border-radius: 10px 10px 10px 10px;
|
||||
background: #fff;
|
||||
padding: 30px;
|
||||
width: 90%;
|
||||
max-width: 450px;
|
||||
position: relative;
|
||||
padding: 0px;
|
||||
-webkit-box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3);
|
||||
box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#formFooter {
|
||||
background-color: #f6f6f6;
|
||||
border-top: 1px solid #dce8f1;
|
||||
padding: 25px;
|
||||
text-align: center;
|
||||
-webkit-border-radius: 0 0 10px 10px;
|
||||
border-radius: 0 0 10px 10px;
|
||||
}
|
||||
|
||||
|
||||
/* TABS */
|
||||
|
||||
h2.inactive {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
h2.active {
|
||||
color: #0d0d0d;
|
||||
border-bottom: 2px solid #5fbae9;
|
||||
}
|
||||
|
||||
|
||||
/* FORM TYPOGRAPHY*/
|
||||
|
||||
input[type=button], input[type=submit], input[type=reset] {
|
||||
background-color: #56baed;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 15px 80px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
-webkit-box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4);
|
||||
box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4);
|
||||
-webkit-border-radius: 5px 5px 5px 5px;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
margin: 5px 20px 40px 20px;
|
||||
-webkit-transition: all 0.3s ease-in-out;
|
||||
-moz-transition: all 0.3s ease-in-out;
|
||||
-ms-transition: all 0.3s ease-in-out;
|
||||
-o-transition: all 0.3s ease-in-out;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
input[type=button]:hover, input[type=submit]:hover, input[type=reset]:hover {
|
||||
background-color: #39ace7;
|
||||
}
|
||||
|
||||
input[type=button]:active, input[type=submit]:active, input[type=reset]:active {
|
||||
-moz-transform: scale(0.95);
|
||||
-webkit-transform: scale(0.95);
|
||||
-o-transform: scale(0.95);
|
||||
-ms-transform: scale(0.95);
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
input[type=text], input[type=password] {
|
||||
background-color: #f6f6f6;
|
||||
border: none;
|
||||
color: #0d0d0d;
|
||||
padding: 15px 32px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 5px;
|
||||
width: 85%;
|
||||
border: 2px solid #f6f6f6;
|
||||
-webkit-transition: all 0.5s ease-in-out;
|
||||
-moz-transition: all 0.5s ease-in-out;
|
||||
-ms-transition: all 0.5s ease-in-out;
|
||||
-o-transition: all 0.5s ease-in-out;
|
||||
transition: all 0.5s ease-in-out;
|
||||
-webkit-border-radius: 5px 5px 5px 5px;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
}
|
||||
|
||||
input[type=text]:focus {
|
||||
background-color: #fff;
|
||||
border-bottom: 2px solid #5fbae9;
|
||||
}
|
||||
|
||||
input[type=text]:placeholder {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
/* ANIMATIONS */
|
||||
|
||||
/* Simple CSS3 Fade-in-down Animation */
|
||||
.fadeInDown {
|
||||
-webkit-animation-name: fadeInDown;
|
||||
animation-name: fadeInDown;
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeInDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple CSS3 Fade-in Animation */
|
||||
@-webkit-keyframes fadeIn { from { opacity:0; } to { opacity:1; } }
|
||||
@-moz-keyframes fadeIn { from { opacity:0; } to { opacity:1; } }
|
||||
@keyframes fadeIn { from { opacity:0; } to { opacity:1; } }
|
||||
|
||||
.fadeIn {
|
||||
opacity:0;
|
||||
-webkit-animation:fadeIn ease-in 1;
|
||||
-moz-animation:fadeIn ease-in 1;
|
||||
animation:fadeIn ease-in 1;
|
||||
|
||||
-webkit-animation-fill-mode:forwards;
|
||||
-moz-animation-fill-mode:forwards;
|
||||
animation-fill-mode:forwards;
|
||||
|
||||
-webkit-animation-duration:1s;
|
||||
-moz-animation-duration:1s;
|
||||
animation-duration:1s;
|
||||
}
|
||||
|
||||
.fadeIn.first {
|
||||
-webkit-animation-delay: 0.4s;
|
||||
-moz-animation-delay: 0.4s;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.fadeIn.second {
|
||||
-webkit-animation-delay: 0.6s;
|
||||
-moz-animation-delay: 0.6s;
|
||||
animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
.fadeIn.third {
|
||||
-webkit-animation-delay: 0.8s;
|
||||
-moz-animation-delay: 0.8s;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.fadeIn.fourth {
|
||||
-webkit-animation-delay: 1s;
|
||||
-moz-animation-delay: 1s;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
/* Simple CSS3 Fade-in Animation */
|
||||
.underlineHover:after {
|
||||
display: block;
|
||||
left: 0;
|
||||
bottom: -10px;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background-color: #56baed;
|
||||
content: "";
|
||||
transition: width 0.2s;
|
||||
}
|
||||
|
||||
.underlineHover:hover {
|
||||
color: #0d0d0d;
|
||||
}
|
||||
|
||||
.underlineHover:hover:after{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* OTHERS */
|
||||
|
||||
*:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#icon {
|
||||
width:60%;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue