forgot to add some files
This commit is contained in:
parent
cf9fcfbad3
commit
eba3fc5f07
11 changed files with 374 additions and 0 deletions
28
app/admin.py
Normal file
28
app/admin.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from flask import url_for, redirect
|
||||||
|
from flask.ext.admin import Admin, BaseView, expose
|
||||||
|
from flask.ext.admin.contrib.sqla import ModelView
|
||||||
|
from flask.ext import login
|
||||||
|
|
||||||
|
|
||||||
|
from app import app, db
|
||||||
|
from models import User
|
||||||
|
from utils import send_command
|
||||||
|
|
||||||
|
|
||||||
|
class ModelBaseView(ModelView):
|
||||||
|
|
||||||
|
def is_accessible(self):
|
||||||
|
if login.current_user.is_anonymous():
|
||||||
|
return False
|
||||||
|
|
||||||
|
return login.current_user.is_admin()
|
||||||
|
|
||||||
|
|
||||||
|
class UserAdminModel(ModelBaseView):
|
||||||
|
column_searchable_list = ('username',)
|
||||||
|
inline_models = None
|
||||||
|
form_columns = ('username', 'admin')
|
||||||
|
|
||||||
|
admin = Admin(app, name='FoodBot', url='/foodbot/admin', template_mode='bootstrap3')
|
||||||
|
|
||||||
|
admin.add_view(UserAdminModel(User, db.session))
|
13
app/app.py
Normal file
13
app/app.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from flask import Flask
|
||||||
|
from flask.ext.sqlalchemy import SQLAlchemy
|
||||||
|
from werkzeug.contrib.cache import SimpleCache
|
||||||
|
|
||||||
|
|
||||||
|
from logbook import Logger
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object('config.Configuration')
|
||||||
|
|
||||||
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
logger = Logger('FoodBot-Web')
|
13
app/config.example.py
Normal file
13
app/config.example.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# config
|
||||||
|
|
||||||
|
|
||||||
|
class Configuration(object):
|
||||||
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///foodbot.db'
|
||||||
|
DEBUG = True
|
||||||
|
SECRET_KEY = '<change>'
|
||||||
|
SLACK_WEBHOOK = '<add url>'
|
||||||
|
PROCESS = 'python test.py'
|
||||||
|
LOGFILE = 'slotmachien.log'
|
||||||
|
ZEUS_KEY = '<fill in>'
|
||||||
|
ZEUS_SECRET = '<fill in>'
|
||||||
|
SLACK_TOKEN = '<fill in>'
|
13
app/config.py
Normal file
13
app/config.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# config
|
||||||
|
|
||||||
|
|
||||||
|
class Configuration(object):
|
||||||
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///foodbot.db'
|
||||||
|
DEBUG = True
|
||||||
|
SECRET_KEY = '<change>'
|
||||||
|
SLACK_WEBHOOK = ''
|
||||||
|
PROCESS = 'python test.py'
|
||||||
|
LOGFILE = 'slotmachien.log'
|
||||||
|
ZEUS_KEY = 'tomtest'
|
||||||
|
ZEUS_SECRET = 'blargh'
|
||||||
|
SLACK_TOKEN = 'xoxp-2484654576-2486580711-4114448516-f21087'
|
18
app/create_database.py
Normal file
18
app/create_database.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from models import *
|
||||||
|
from app import db
|
||||||
|
|
||||||
|
db.drop_all()
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
feli = User()
|
||||||
|
feli.configure("feliciaan", True, True)
|
||||||
|
db.session.add(feli)
|
||||||
|
|
||||||
|
don = User()
|
||||||
|
don.configure("don", True, True)
|
||||||
|
db.session.add(don)
|
||||||
|
|
||||||
|
# To future developers, add yourself here
|
||||||
|
|
||||||
|
# commit all the things
|
||||||
|
db.session.commit()
|
34
app/login.py
Normal file
34
app/login.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from flask import redirect, request, url_for, abort, session
|
||||||
|
from flask.ext.login import LoginManager, current_user, logout_user
|
||||||
|
from flask_oauthlib.client import OAuth
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from app import app, db, logger, cache
|
||||||
|
from models import User
|
||||||
|
from zeus import oauth, zeus_login
|
||||||
|
|
||||||
|
login_manager = LoginManager()
|
||||||
|
login_manager.init_app(app)
|
||||||
|
|
||||||
|
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(userid):
|
||||||
|
return User.query.filter_by(id=userid).first()
|
||||||
|
|
||||||
|
@app.route('/foodbot/login')
|
||||||
|
def login():
|
||||||
|
return zeus_login()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/foodbot/logout')
|
||||||
|
def logout():
|
||||||
|
if 'zeus_token' in session:
|
||||||
|
session.pop('zeus_token', None)
|
||||||
|
logout_user()
|
||||||
|
return redirect(url_for('admin.index'))
|
||||||
|
|
||||||
|
|
||||||
|
def before_request():
|
||||||
|
if current_user.is_anonymous() or not current_user.is_allowed():
|
||||||
|
abort(401)
|
103
app/models.py
Normal file
103
app/models.py
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import uuid
|
||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
|
||||||
|
# Create database models
|
||||||
|
class User(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
username = db.Column(db.String(80), unique=True)
|
||||||
|
admin = db.Column(db.Boolean)
|
||||||
|
bias = db.Column(db.Integer)
|
||||||
|
courrier = db.relationship('Courrier', backref='courrier', lazy='dynamic')
|
||||||
|
logactions = db.relationship('LogAction', backref='user', lazy='dynamic')
|
||||||
|
|
||||||
|
def configure(self, username, allowed, admin, bias):
|
||||||
|
self.username = username
|
||||||
|
self.allowed = allowed
|
||||||
|
self.admin = admin
|
||||||
|
self.bias = bias
|
||||||
|
|
||||||
|
def is_authenticated(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_admin(self):
|
||||||
|
return self.admin
|
||||||
|
|
||||||
|
def is_anonymous(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_id(self):
|
||||||
|
try:
|
||||||
|
return unicode(self.id) # python 2
|
||||||
|
except NameError:
|
||||||
|
return str(self.id) # python 3
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s' % self.username
|
||||||
|
|
||||||
|
|
||||||
|
class Location(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.String(120))
|
||||||
|
address = db.Column(db.String(254))
|
||||||
|
website = db.Column(db.String(120))
|
||||||
|
food = db.relationship('Food', backref='location', lazy='dynamic')
|
||||||
|
|
||||||
|
def configure(self, name, address, website):
|
||||||
|
self.name = name
|
||||||
|
self.address = address
|
||||||
|
self.website = website
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s: %s' % (self.name, self.address)
|
||||||
|
|
||||||
|
class Food(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
|
||||||
|
name = db.Column(db.String(120))
|
||||||
|
price = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def configure(self, location, name, price):
|
||||||
|
self.location = location
|
||||||
|
self.name = name
|
||||||
|
self.price = price
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s' % self.name
|
||||||
|
|
||||||
|
class Order(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
courrier_id = db.Column(db.Integer, db.ForeignKey('user.id'))
|
||||||
|
location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
|
||||||
|
starttime = db.Column(db.DateTime)
|
||||||
|
stoptime = db.Column(db.DateTime)
|
||||||
|
orders = db.relationship('OrdreItem', backref='order', lazy='dynamic')
|
||||||
|
|
||||||
|
|
||||||
|
def configure(self, courrier, location, starttime, stoptime):
|
||||||
|
self.courrier = courrier
|
||||||
|
self.location = location
|
||||||
|
self.starttime = starttime
|
||||||
|
self.stoptime = stoptime
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'Order'
|
||||||
|
|
||||||
|
class OrderItem(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
|
||||||
|
order_id = db.Column(db.Integer, db.ForeignKey('order.id'))
|
||||||
|
food_id = db.Column(db.Integer, db.ForeignKey('food.id'))
|
||||||
|
|
||||||
|
def configure(self, user, order, food):
|
||||||
|
self.user = user
|
||||||
|
self.order = order
|
||||||
|
self.food = food
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'OrderItem'
|
16
app/requirements.txt
Normal file
16
app/requirements.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
Flask==0.10.1
|
||||||
|
Flask-Admin==1.0.9
|
||||||
|
Flask-Login==0.2.11
|
||||||
|
Flask-SQLAlchemy==2.0
|
||||||
|
Flask-WTF==0.10.3
|
||||||
|
Jinja2==2.7.2
|
||||||
|
Logbook==0.8.1
|
||||||
|
MarkupSafe==0.23
|
||||||
|
SQLAlchemy==0.9.8
|
||||||
|
WTForms==2.0
|
||||||
|
Werkzeug==0.9.6
|
||||||
|
flup==1.0.2
|
||||||
|
itsdangerous==0.24
|
||||||
|
requests==2.4.0
|
||||||
|
Flask-OAuthlib==0.8.0
|
||||||
|
oauthlib==0.7.2
|
43
app/views.py
Normal file
43
app/views.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
from flask import Blueprint, request, jsonify, redirect, url_for
|
||||||
|
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from login import before_request
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def home():
|
||||||
|
return render_template('home.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/about/')
|
||||||
|
def about():
|
||||||
|
return render_template('about.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/stats/')
|
||||||
|
def stats():
|
||||||
|
return render_template('stats.html')
|
||||||
|
|
||||||
|
|
||||||
|
if app.debug: # add route information
|
||||||
|
@app.route('/routes')
|
||||||
|
def list_routes(self):
|
||||||
|
import urllib
|
||||||
|
output = []
|
||||||
|
for rule in app.url_map.iter_rules():
|
||||||
|
options = {}
|
||||||
|
for arg in rule.arguments:
|
||||||
|
options[arg] = "[{0}]".format(arg)
|
||||||
|
|
||||||
|
methods = ','.join(rule.methods)
|
||||||
|
url = url_for(rule.endpoint, **options)
|
||||||
|
line = urllib.unquote(
|
||||||
|
"{:50s} {:20s} {}".format(rule.endpoint, methods, url))
|
||||||
|
output.append(line)
|
||||||
|
|
||||||
|
string = ''
|
||||||
|
for line in sorted(output):
|
||||||
|
string += line + "<br/>"
|
||||||
|
|
||||||
|
return string
|
93
app/zeus.py
Normal file
93
app/zeus.py
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
from flask import Flask, redirect, url_for, session, request, jsonify, flash, request
|
||||||
|
from flask.ext.login import LoginManager, login_user, current_user, logout_user
|
||||||
|
from flask.ext.admin import helpers
|
||||||
|
from flask_oauthlib.client import OAuth, OAuthException
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
from app import app, db
|
||||||
|
from models import User, Token
|
||||||
|
|
||||||
|
oauth = OAuth(app)
|
||||||
|
|
||||||
|
zeus = oauth.remote_app(
|
||||||
|
'zeus',
|
||||||
|
consumer_key=app.config['ZEUS_KEY'],
|
||||||
|
consumer_secret=app.config['ZEUS_SECRET'],
|
||||||
|
request_token_params={},
|
||||||
|
base_url='http://kelder.zeus.ugent.be/oauth/api/',
|
||||||
|
access_token_method='POST',
|
||||||
|
access_token_url='https://kelder.zeus.ugent.be/oauth/oauth2/token/',
|
||||||
|
authorize_url='https://kelder.zeus.ugent.be/oauth/oauth2/authorize/'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def zeus_login():
|
||||||
|
if app.debug:
|
||||||
|
return zeus.authorize(callback=url_for('authorized', _external=True))
|
||||||
|
else: # temporary solution because it otherwise gives trouble on the pi because of proxies and such
|
||||||
|
return zeus.authorize(callback='http://zeus.ugent.be/foodbot/login/zeus/authorized')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/slotmachien/login/zeus/authorized')
|
||||||
|
def authorized():
|
||||||
|
resp = zeus.authorized_response()
|
||||||
|
if resp is None:
|
||||||
|
return 'Access denied: reason=%s error=%s' % (
|
||||||
|
request.args['error'],
|
||||||
|
request.args['error_description']
|
||||||
|
)
|
||||||
|
if isinstance(resp, OAuthException):
|
||||||
|
return 'Access denied: %s' % resp.message + '<br>' + str(resp.data)
|
||||||
|
|
||||||
|
session['zeus_token'] = (resp['access_token'], '')
|
||||||
|
me = zeus.get('current_user/')
|
||||||
|
username = me.data.get('username', '').lower()
|
||||||
|
|
||||||
|
user = User.query.filter_by(username=username).first()
|
||||||
|
if len(username) > 0 and user:
|
||||||
|
return login_and_redirect_user(user)
|
||||||
|
elif len(username) > 0:
|
||||||
|
user = create_user(username)
|
||||||
|
return login_and_redirect_user(user)
|
||||||
|
|
||||||
|
flash("You're not allowed to enter, please contact a system administrator")
|
||||||
|
return redirect(url_for("admin.index"))
|
||||||
|
|
||||||
|
|
||||||
|
@zeus.tokengetter
|
||||||
|
def get_zeus_oauth_token():
|
||||||
|
return session.get('zeus_token')
|
||||||
|
|
||||||
|
|
||||||
|
def login_and_redirect_user(user):
|
||||||
|
login_user(user)
|
||||||
|
# add_token(resp['access_token'], user)
|
||||||
|
content_type = request.headers.get('Content-Type', None)
|
||||||
|
if content_type and content_type in 'application/json':
|
||||||
|
token = add_token(user)
|
||||||
|
return jsonify({'token': token.token})
|
||||||
|
return redirect(url_for("admin.index"))
|
||||||
|
|
||||||
|
|
||||||
|
def add_token(user):
|
||||||
|
token = Token()
|
||||||
|
token.configure(user)
|
||||||
|
db.session.add(token)
|
||||||
|
db.session.commit()
|
||||||
|
return token
|
||||||
|
|
||||||
|
|
||||||
|
def create_user(username):
|
||||||
|
user = User()
|
||||||
|
user.configure(username, False)
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
# EASTER EGG
|
||||||
|
text = 'Welcome ' + username + '!'
|
||||||
|
js = json.dumps({'text': text})
|
||||||
|
url = app.config['SLACK_WEBHOOK']
|
||||||
|
if len(url) > 0:
|
||||||
|
requests.post(url, data=js)
|
||||||
|
return user
|
Loading…
Reference in a new issue