from flask import Flask , redirect , flash , 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
from hra . web import app
import hra . web . jinja_mac as jinja_mac
from hra . util import hash_passwd
@html . WrapAfterBuilder_decorator
def BasePage ( b , content ) :
b . current_tag = html . Tag ( b , " html " , [ ] )
b . root_tag = b . current_tag
with b . head ( ) :
b . title ( ) ( " KSP hra " )
b . meta ( name = " viewport " , content = " width=device-width, initial-scale=1.0 " )
b . link ( rel = " stylesheet " , href = app . url_for ( ' static ' , filename = ' bootstrap.min.css ' ) , type = ' text/css ' , media = " all " )
b . link ( rel = " stylesheet " , href = app . url_for ( ' static ' , filename = ' ksp-mhd.css ' ) , type = ' text/css ' , media = " all " )
b . link ( rel = " icon " , type = " image/png " , sizes = " 16x16 " , href = " static/favicon.ico " )
b . link ( rel = " shortcut icon " , href = app . url_for ( ' static ' , filename = ' img/favicon.ico ' ) )
with b . body ( ) as body :
with b . header ( _class = f " flavor- { config . WEB_FLAVOR } " ) :
with b . div ( _class = " content " ) :
with b . a ( href = " / " , title = " Na hlavní stránku " ) :
b . img ( src = app . url_for ( ' static ' , filename = ' hippo.png ' ) , style = " width: 60px;height: auto; " , alt = " KSP " )
b . h1 ( ) ( " Hra na soustředění KSP " )
with b . div ( id = " nav-wrapper " ) :
with b . nav ( id = " main-menu " , _class = " content " ) :
for item in g . menu :
b . a ( href = item . url ) ( item . name )
if g . user :
b . a ( _class = " right " , href = " / " ) ( f " Přihlášen: { g . user . username } " )
b . a ( _class = " right " , href = " /logout " ) ( f " Odhlásit " )
else :
b . a ( _class = " right " , href = " /login " ) ( f " Přihlásit " )
b . a ( _class = " right " , href = " /registration " ) ( f " Registrovat " )
with b . main ( ) :
messages = get_flashed_messages ( with_categories = True )
if messages :
for category , message in messages :
if category == " message " :
category = " warning "
b . div ( _class = f " alert alert- { category } " , role = " alert " ) ( message )
b ( * content )
class OptionalIntField ( wtforms . IntegerField ) :
widget = NumberInput ( )
def process_formdata ( self , valuelist ) :
self . data = None
if valuelist :
if valuelist [ 0 ] :
try :
self . data = int ( valuelist [ 0 ] )
except ValueError :
raise wtforms . ValidationError ( ' Nejedná se o číslo. ' )
def user_link ( user ) :
b = html . Builder ( )
with b . line ( ) :
if user is None :
b ( " - " )
else :
if g . org :
b . a ( href = app . url_for ( web_org_user . __name__ , user_id = user . id ) ) ( user . username )
else :
b ( user . username )
return b . root_tag
class RegistrationForm ( FlaskForm ) :
username = StringField ( ' Jméno týmu ' , [ validators . Length ( min = 2 , max = 25 ) , validators . DataRequired ( ) ] )
captcha = StringField ( ' Captcha ' , validators = [ validators . DataRequired ( ) ] )
passwd = PasswordField ( ' Heslo ' , [
validators . DataRequired ( ) ,
validators . EqualTo ( ' confirm ' , message = ' Passwords must match ' )
] )
confirm = PasswordField ( ' Heslo znovu ' , validators = [ validators . DataRequired ( ) ] )
submit = SubmitField ( " Založit " )
def validate_captcha ( form , field ) :
if field . data != config . CAPTCHA :
raise ValidationError ( " Chyba! " )
class LoginForm ( FlaskForm ) :
username = StringField ( ' Jméno týmu ' , [ validators . DataRequired ( ) ] )
passwd = PasswordField ( ' Heslo ' , [ validators . DataRequired ( ) ] )
submit = SubmitField ( " Přihlásit " )
@app . route ( " /registration " , methods = [ ' GET ' , ' POST ' ] )
def registration ( ) :
f = RegistrationForm ( )
if f . validate_on_submit ( ) :
u = db . User ( org = False , username = f . username . data , passwd = hash_passwd ( f . passwd . data ) )
u . gen_token ( )
try :
db . get_session ( ) . add ( u )
db . get_session ( ) . commit ( )
except exc . IntegrityError :
flash ( " Uživatelské jméno již existuje " )
else :
flash ( " Přidán nový uživatel. " , ' success ' )
return redirect ( " login " )
b = BasePage ( )
b ( jinja_mac . quick_form ( f , form_type = ' horizontal ' ) )
return b . print_file ( )
@app . route ( " /login " , methods = [ ' GET ' , ' POST ' ] )
def login ( ) :
f = LoginForm ( )
if f . validate_on_submit ( ) :
p_hash = hash_passwd ( f . passwd . data )
user = db . get_session ( ) . query ( db . User ) . filter_by ( username = f . username . data ) . one_or_none ( )
print ( user , p_hash )
if user and user . passwd == p_hash :
session . clear ( )
session [ ' uid ' ] = user . id
flash ( " Přihlášení hotovo. " , ' success ' )
return redirect ( " / " )
flash ( " Chybné jméno nebo heslo. " , ' danger ' )
b = BasePage ( )
b ( jinja_mac . quick_form ( f , form_type = ' horizontal ' ) )
return b . print_file ( )
@app . route ( " /logout " )
def logout ( ) :
session . clear ( )
return redirect ( ' / ' )
@app . template_filter ( )
def none_as_minus ( x ) :
return x if x is not None else ' - '
@app . template_filter ( )
def round_points ( x ) :
if x is None :
return None
return round ( x , 3 )
@app . template_filter ( )
def print_time ( t ) :
if t == None :
return " - "
return ( " - " if t < 0 else " " ) + str ( abs ( t ) / / 1000 / / 60 ) + " : " + ( " 00 {0:d} " . format ( abs ( t ) / / 1000 % 60 ) ) [ - 2 : ]
@app . route ( " / " , methods = [ ' GET ' , ' POST ' ] )
def web_index ( ) :
b = BasePage ( )
if g . user :
with b . p ( ) :
b ( f " Váš token je: { g . user . token } " )
return b . print_file ( )
@app . route ( " /game/<int:game_id> " , methods = [ ' GET ' ] )
def web_game ( game_id ) :
ses = db . get_session ( )
game = ses . query ( db . Game ) . filter_by ( game_id = game_id ) . one_or_none ( )
teams = ses . query ( db . Team ) . filter_by ( game_id = game_id ) . order_by ( db . Team . team_id ) . all ( )
if game is None :
raise werkzeug . exceptions . NotFound ( )
b = BasePage ( )
with b . p ( ) . table ( _class = " data full " ) :
with b . thead ( ) :
b . line ( ) . th ( ) ( " Id " )
b . line ( ) . th ( ) ( " User " )
if g . org :
b . line ( ) . th ( ) ( " Akce " )
for team in teams :
with b . tr ( ) :
b . line ( ) . td ( ) ( team . team_id )
b . line ( ) . td ( ) ( user_link ( team . user ) , " : " , team . name )
if g . org :
with b . td ( ) :
with b . div ( _class = " btn-group " , role = " group " ) :
b . a ( _class = " btn btn-xs btn-primary " , href = app . url_for ( web_org_game_userchange . __name__ , game_id = game . game_id , team_id = team . team_id ) ) ( " Změnit uživatele " )
#b.a(_class="btn btn-xs btn-primary", href=app.url_for(web_game.__name__, game_id=g.game_id))("Detail")
return b . print_file ( )
@app . route ( " /org/games " )
def web_org_games ( ) :
games = db . get_session ( ) . query ( db . Game ) . order_by ( db . Game . game_id ) . all ( )
b = BasePage ( )
with b . p ( ) . table ( _class = " data full " ) :
with b . thead ( ) :
b . line ( ) . th ( ) ( " Id " )
b . line ( ) . th ( ) ( " Kolo " )
b . line ( ) . th ( ) ( " Akce " )
for g in games :
with b . tr ( ) :
b . line ( ) . td ( ) ( g . game_id )
with b . line ( ) . td ( ) :
if g . working_on_next_state :
b . b ( ) ( g . current_round , " ++ " )
else :
b ( g . current_round )
with b . td ( ) :
b . a ( _class = " btn btn-xs btn-primary " , href = app . url_for ( web_game . __name__ , game_id = g . game_id ) ) ( " Detail " )
return b . print_file ( )
class GameUserchangeForm ( FlaskForm ) :
name = StringField ( " Jméno hry z pohledu týmu " )
set_no_user = SubmitField ( " Bez uživatele " )
submit_no_change = wtforms . SubmitField ( " Bez změny " , render_kw = { " style " : " display: none " } )
@app . route ( " /org/game/<int:game_id>/team/<int:team_id>/change_user " , methods = [ ' GET ' , ' POST ' ] )
def web_org_game_userchange ( game_id , team_id ) :
ses = db . get_session ( )
game = ses . query ( db . Game ) . filter_by ( game_id = game_id ) . one_or_none ( )
team_to_edit = ses . query ( db . Team ) . filter_by ( game_id = game_id , team_id = team_id ) . one_or_none ( )
teams = ses . query ( db . Team ) . filter_by ( game_id = game_id ) . order_by ( db . Team . team_id ) . all ( )
users = db . get_session ( ) . query ( db . User ) . order_by ( db . User . id ) . all ( )
if game is None or team_to_edit is None :
raise werkzeug . exceptions . NotFound ( )
teams_by_user = { u . id : [ ] for u in users }
for t in teams :
if t . user_id is not None :
teams_by_user [ t . user_id ] . append ( t )
form = GameUserchangeForm ( obj = team_to_edit )
if form . validate_on_submit ( ) :
team_to_edit . name = form . name . data
if " submit_no_change " not in request . form :
team_to_edit . user_id = None
for u in users :
if f " set_user_ { u . id } " in request . form :
team_to_edit . user_id = u . id
try :
ses . commit ( )
except exc . IntegrityError :
flash ( " Duplicitní přiřazení " , ' danger ' )
ses . rollback ( )
else :
flash ( " Uživatel změněn " , ' success ' )
return redirect ( app . url_for ( web_game . __name__ , game_id = game_id ) )
b = BasePage ( )
with b . form ( action = " " , method = " POST " , _class = " form form-horizontal " , role = " form " ) :
b ( form . csrf_token )
b ( form . submit_no_change )
with b . div ( _class = " form-row " ) :
b ( jinja_mac . form_field ( form . name , size = 8 ) )
with b . p ( ) . table ( _class = " data full " ) :
with b . thead ( ) :
b . line ( ) . th ( ) ( " Username " )
b . line ( ) . th ( ) ( " Přiřazení " )
b . line ( ) . th ( ) ( " Akce " )
for u in users :
with b . tr ( ) :
b . line ( ) . td ( user_link ( u ) )
with b . td ( ) :
if len ( teams_by_user [ u . id ] ) :
with b . ul ( ) :
for t in teams_by_user [ u . id ] :
b . li ( f " { t . team_id } -> { t . name } " )
b . line ( ) . td ( ) . input ( _class = " btn btn-danger " if u . id == team_to_edit . user_id else " btn btn-primary " , _id = " set_participation_state " , name = f " set_user_ { u . id } " , type = " submit " , value = " Nastavit stav účasti " )
b ( jinja_mac . form_field ( form . set_no_user ) )
return b . print_file ( )
@app . route ( " /org/users " )
def web_org_users ( ) :
users = db . get_session ( ) . query ( db . User ) . order_by ( db . User . id ) . all ( )
b = BasePage ( )
with b . p ( ) . table ( _class = " data full " ) :
with b . thead ( ) :
b . line ( ) . th ( ) ( " Username " )
b . line ( ) . th ( ) ( " Hry " )
b . line ( ) . th ( ) ( " Akce " )
for u in users :
with b . tr ( ) :
b . line ( ) . td ( ) ( u . username )
b . line ( ) . td ( )
with b . td ( ) :
with b . div ( _class = " btn-group " , role = " group " ) :
b . a ( _class = " btn btn-xs btn-primary " , href = app . url_for ( web_org_user . __name__ , user_id = u . id ) ) ( " Detail " )
return b . print_file ( )
@app . route ( " /org/user/<int:user_id> " , methods = [ ' GET ' , ' POST ' ] )
def web_org_user ( user_id ) :
user = db . get_session ( ) . query ( db . User ) . filter_by ( id = user_id ) . one_or_none ( )
if not user :
raise werkzeug . exceptions . NotFound ( )
b = BasePage ( )
b . line ( ) . h2 ( " Uživatel " , user . username )
with b . div ( _class = " btn-group " , role = " group " ) :
with b . form ( method = " POST " , _class = " btn-group " , action = app . url_for ( web_org_user_su . __name__ , user_id = user . id ) ) :
b . button ( _class = " btn btn-default " , type = " submit " , name = " su " , value = " yes " ) ( " Převtělit " )
return b . print_file ( )
@app . route ( " /org/user/<int:user_id>/su " , methods = [ ' POST ' ] )
def web_org_user_su ( user_id ) :
user = db . get_session ( ) . query ( db . User ) . filter_by ( id = user_id ) . one_or_none ( )
session [ ' uid ' ] = user . id
flash ( " Uživatel vtělen! " )
return redirect ( ' / ' )