|
|
|
from flask import Flask, redirect, flash, render_template, session, g, request, get_flashed_messages
|
|
|
|
from wtforms import Form, BooleanField, StringField, PasswordField, validators, SubmitField, IntegerField, DateTimeField
|
|
|
|
from wtforms.validators import ValidationError
|
|
|
|
from flask_wtf import FlaskForm
|
|
|
|
from flask_bootstrap import Bootstrap
|
|
|
|
import time
|
|
|
|
from datetime import datetime
|
|
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
|
|
from sqlalchemy import exc, update
|
|
|
|
import hashlib
|
|
|
|
import bcrypt
|
|
|
|
import os
|
|
|
|
import werkzeug.exceptions
|
|
|
|
import wtforms
|
|
|
|
from wtforms.fields import EmailField
|
|
|
|
from wtforms.widgets import NumberInput
|
|
|
|
|
|
|
|
import hra.config as config
|
|
|
|
import hra.web.html as html
|
|
|
|
import hra.db as db
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
logging.basicConfig()
|
|
|
|
logging.getLogger('sqlalchemy.engine').setLevel(logging.ERROR)
|
|
|
|
|
|
|
|
static_dir = os.path.abspath('static')
|
|
|
|
app = Flask(__name__, static_folder=static_dir)
|
|
|
|
|
|
|
|
app.config.from_object(config)
|
|
|
|
Bootstrap(app)
|
|
|
|
|
|
|
|
db.flask_db = SQLAlchemy(app, metadata=db.metadata)
|
|
|
|
|
|
|
|
|
|
|
|
class NeedLoginError(werkzeug.exceptions.Forbidden):
|
|
|
|
description = 'Need to log in'
|
|
|
|
|
|
|
|
|
|
|
|
class MenuItem:
|
|
|
|
url: str
|
|
|
|
name: str
|
|
|
|
|
|
|
|
def __init__(self, url: str, name: str):
|
|
|
|
self.url = url
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
|
|
|
|
def init_request():
|
|
|
|
path = request.path
|
|
|
|
# XXX: Když celá aplikace běží v adresáři, request.path je relativní ke kořeni aplikace, ne celého webu
|
|
|
|
if path.startswith('/static/') or path.startswith('/assets/'):
|
|
|
|
# Pro statické soubory v development nasazení nepotřebujeme nastavovat
|
|
|
|
# nic dalšího (v ostrém nasazení je servíruje uwsgi)
|
|
|
|
return
|
|
|
|
|
|
|
|
user = None
|
|
|
|
g.user = None
|
|
|
|
g.org = False
|
|
|
|
if path.startswith('/api/'):
|
|
|
|
token = request.args.get('token')
|
|
|
|
if token is not None:
|
|
|
|
user = db.get_session().query(db.User).filter_by(token=token).first()
|
|
|
|
if user is None:
|
|
|
|
raise werkzeug.exceptions.Forbidden("Wrong token.")
|
|
|
|
|
|
|
|
else:
|
|
|
|
if 'uid' in session:
|
|
|
|
user = db.get_session().query(db.User).filter_by(id=session['uid']).first()
|
|
|
|
path = request.path
|
|
|
|
if path.startswith('/org/'):
|
|
|
|
if not user or not user.org:
|
|
|
|
raise werkzeug.exceptions.Forbidden()
|
|
|
|
g.user = user
|
|
|
|
g.org = g.user and g.user.org
|
|
|
|
|
|
|
|
g.menu = [
|
|
|
|
MenuItem('/', "Domů"),
|
|
|
|
]
|
|
|
|
if g.org:
|
|
|
|
g.menu += [
|
|
|
|
MenuItem(app.url_for(pages.web_org_games.__name__), "Hry"),
|
|
|
|
MenuItem(app.url_for(pages.web_org_users.__name__), "Uživatelé"),
|
|
|
|
MenuItem(app.url_for(pages.web_org_logs.__name__)+"#main_table" , "Logy"),
|
|
|
|
]
|
|
|
|
else:
|
|
|
|
g.menu += [
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.before_request(init_request)
|
|
|
|
|
|
|
|
|
|
|
|
@app.errorhandler(werkzeug.exceptions.HTTPException)
|
|
|
|
def handle_exception(e):
|
|
|
|
path = request.path
|
|
|
|
if path.startswith('/api/'):
|
|
|
|
ses = db.get_session()
|
|
|
|
ses.rollback()
|
|
|
|
response = e.get_response()
|
|
|
|
response.data = json.dumps({
|
|
|
|
"status": "error",
|
|
|
|
"description": e.description,
|
|
|
|
"http-code": e.code,
|
|
|
|
"http-name": e.name,
|
|
|
|
})
|
|
|
|
response.content_type = "application/json"
|
|
|
|
x = db.Log(
|
|
|
|
source_ip=request.remote_addr,
|
|
|
|
user_id=g.user.id if g.user is not None else None,
|
|
|
|
endpoint=db.Endpoint.error,
|
|
|
|
status="http-error",
|
|
|
|
text=f"{e.code} ({e.name}): {e.description}",
|
|
|
|
url=request.path,
|
|
|
|
get=request.args,
|
|
|
|
time=datetime.now(),
|
|
|
|
)
|
|
|
|
ses.add(x)
|
|
|
|
ses.commit()
|
|
|
|
return response
|
|
|
|
else:
|
|
|
|
return e
|
|
|
|
|
|
|
|
import hra.web.pages as pages
|
|
|
|
import hra.web.api
|