#!/usr/bin/env python3 # this is a quick hack, to be improved later. trying to do the simplest # thing that will possibly work. ## # TODO ## ## * put page content into templates/static files ## * clean up FIXME import bottle from bottle import route, run, request, response, redirect from bottle import HTTPError, template from sqlalchemy.ext.declarative import declarative_base from bottle.ext import sqlalchemy from pprint import pprint from sqlalchemy import create_engine import os import random import string from datetime import datetime VERSION = '0.0.1' 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') # sorry for global SQLBASE = declarative_base() # FIXME make this skip letters not in base58 def randomUpper(count): return ''.join(random.choice(string.ascii_uppercase) for _ in range(count)) # FIXME maybe make the IDs longer def genRandomTVID(): tvid = str(randomUpper(3) + "-" + randomUpper(3)) return tvid def serve(): app = bottle.Bottle() # pull in models from .db import TV engine = create_engine(DATABASE_URL, echo=True) plugin = sqlalchemy.Plugin( engine, # SQLAlchemy engine created with create_engine function. SQLBASE.metadata, # SQLAlchemy metadata, required only if create=True. keyword='db', # Keyword used to inject session database in a route (default 'db'). create=True, # If it is true, execute `metadata.create_all(engine)` when plugin is applied (default False). commit=True, # If it is true, plugin commit changes after route is executed (default True). use_kwargs=False ) app.install(plugin) # here we cookie them if they have no cookie, then redirect them to the # cookie'd value (whether preexisting or new). @app.get('/') def indexpage(): c = request.get_cookie("tvid") if c: # redirect redirect('/tv/' + c) else: newid = genRandomTVID() response.set_cookie("tvid", newid) redirect('/tv/' + newid) @app.get('/style.css') def stylesheet(): return template('style') # here we check to see if they have a redirect URL in the db. if they do # we send them there. if they don't, we display their ID really big, # reloading the page once per hour. @app.get('/tv/') def tvpage(db, displayid=None): # FIXME regex check id to make sure displayid is right format, # return error if not if id is None: return template('nocookie') # check db for tv id tv = db.query(TV).filter_by(displayid=displayid).first() if tv: tv.lastSeen = datetime.now() db.add(tv) if tv.target: redirect(tv.target) else: return template('displayid', id=displayid, version=VERSION) else: # otherwise, just show their display ID bigly and keep them # bouncing periodically until some admin configures them # a target: # update lastseen here: newtv = TV(displayid=displayid,lastSeen=datetime.now()) db.add(newtv) return template('displayid', id=displayid, version=VERSION) # here we display the administration list of TVs if logged in # if logged out then redirect to /login # 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") # 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(): raise NotImplementedError() #response.set_cookie("adminpw", whatever) redirect('/login') @app.get('/logut') def logout(): response.set_cookie("adminpw", "") redirect('/login') app.run(host='0.0.0.0', port=PORT, debug=DEBUG)