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