423 lines
16 KiB
Python
423 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import flask
|
|
from flask_socketio import SocketIO
|
|
import flask_login as fll
|
|
import datetime
|
|
from db import db, User, Game, Player, levels_users
|
|
from belote_jeu import N_TURN, N_PLAYERS
|
|
import belote_ws
|
|
import settings
|
|
|
|
login_manager = fll.LoginManager()
|
|
|
|
app = flask.Flask(__name__)
|
|
app.config.from_pyfile('settings.cfg')
|
|
|
|
#######################################################################
|
|
# Plugin management #
|
|
#######################################################################
|
|
|
|
# SocketIO
|
|
socketio = SocketIO(app, cors_allowed_origins=settings.PUBLIC_URL)
|
|
login_manager.init_app(app)
|
|
|
|
# Database management
|
|
db.app = app
|
|
db.init_app(app)
|
|
db.create_all()
|
|
db.session.commit()
|
|
|
|
# Insert admin if not exist
|
|
if User.query.limit(1).first() is None:
|
|
admin = User(login='admin', name='Admin', level=levels_users['Admin'])
|
|
admin.set_password('admin')
|
|
db.session.add(admin)
|
|
db.session.commit()
|
|
|
|
# Login management
|
|
@login_manager.user_loader
|
|
def load_user(user_id):
|
|
if user_id is None :
|
|
return None
|
|
return User.query.get(user_id)
|
|
|
|
@login_manager.unauthorized_handler
|
|
def unauthorized_callback():
|
|
return flask.redirect('/login?next=' + flask.request.path)
|
|
|
|
|
|
#######################################################################
|
|
# Global variables or fuctions #
|
|
#######################################################################
|
|
URL_DEFAULT = '/games'
|
|
namespaces_join = {}
|
|
namespaces = {}
|
|
|
|
def create_namespace(gid, join=False):
|
|
if(join):
|
|
namespace = belote_ws.CustomNamespaceJoin(gid)
|
|
namespaces_join[gid] = True
|
|
socketio.on_namespace(namespace)
|
|
else:
|
|
namespace = belote_ws.CustomNamespacePlay(gid)
|
|
namespaces[gid] = True
|
|
socketio.on_namespace(namespace)
|
|
|
|
|
|
@app.route('/')
|
|
def home():
|
|
user = fll.current_user
|
|
if not hasattr(user, 'level'):
|
|
user = None
|
|
return flask.render_template("index.html", user=user)
|
|
#######################################################################
|
|
# Login, logout #
|
|
#######################################################################
|
|
|
|
@app.route('/login', methods=['GET', 'POST'])
|
|
def login():
|
|
if fll.current_user.is_authenticated:
|
|
return flask.redirect(URL_DEFAULT)
|
|
if flask.request.method=="POST":
|
|
username = flask.request.form['username']
|
|
password = flask.request.form['password']
|
|
user = User.query.get(username)
|
|
if user and user.level > levels_users['Inactive'] and user.check_password(password):
|
|
fll.login_user(user)
|
|
user.last_login = datetime.datetime.utcnow()
|
|
next = flask.request.args.get('next')
|
|
if next is not None and next[0]=='/':
|
|
return flask.redirect(next)
|
|
else:
|
|
return flask.redirect(URL_DEFAULT)
|
|
else:
|
|
app.logger.warning('Login fail for user {} from {}'.format(user, flask.request.remote_addr))
|
|
flask.flash('Nom d\'utilisateur ou mot de passe incorrect')
|
|
return flask.render_template('login.html', user=None)
|
|
|
|
@app.route('/logout')
|
|
def logout():
|
|
fll.logout_user()
|
|
return flask.redirect('/')
|
|
|
|
#######################################################################
|
|
# Games : list #
|
|
#######################################################################
|
|
|
|
@app.route('/games')
|
|
@fll.login_required
|
|
def games():
|
|
games = Game.query.all()
|
|
mesjeux = []
|
|
joinable = []
|
|
for g in games:
|
|
if g.admin==fll.current_user.login:
|
|
mesjeux.append(g)
|
|
elif g.can_join(fll.current_user):
|
|
joinable.append(g)
|
|
cancreategames = fll.current_user.level >= levels_users['Can create games']
|
|
candeletegames = fll.current_user.level >= levels_users['Admin']
|
|
return flask.render_template('games.html', mesjeux=mesjeux, joinable=joinable, user=fll.current_user, \
|
|
cancreategames=cancreategames, candeletegames=candeletegames)
|
|
|
|
#######################################################################
|
|
# Create, join and play to a game #
|
|
#######################################################################
|
|
|
|
@app.route('/add_game', methods=['GET', 'POST'])
|
|
@fll.login_required
|
|
def game_add():
|
|
player = fll.current_user
|
|
if fll.current_user.level >= levels_users['Can create games']:
|
|
if flask.request.method=="POST":
|
|
name = flask.request.form['name']
|
|
if name is None or name == '':
|
|
return flask.redirect('/add_game')
|
|
game = Game(name=name, admin=player.login)
|
|
db.session.add(game)
|
|
db.session.commit()
|
|
game.join(fll.current_user)
|
|
db.session.commit()
|
|
return flask.redirect('/game/{}'.format(game.id))
|
|
return flask.render_template('game_add.html', user=fll.current_user)
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/game/<roomid>/join')
|
|
@fll.login_required
|
|
def game_page_join(roomid):
|
|
game = Game.query.get(roomid)
|
|
if game:
|
|
player = fll.current_user
|
|
if game.start:
|
|
return flask.redirect('/game/{}'.format(roomid))
|
|
if game.can_join(player):
|
|
if game.id not in namespaces_join:
|
|
create_namespace(game.id, join=True)
|
|
return flask.render_template('game_join.html', game=game, user=player, admin=game.admin)
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/game/<roomid>/start')
|
|
@fll.login_required
|
|
def game_page_start(roomid):
|
|
game = Game.query.get(roomid)
|
|
if game:
|
|
player = fll.current_user
|
|
if game.isadmin(player) and game.fixplayers and not game.start:
|
|
return flask.render_template('game_start.html', game=game, user=player)
|
|
return flask.redirect('/game/{}'.format(roomid))
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/game/<roomid>')
|
|
@fll.login_required
|
|
def game_page(roomid):
|
|
game = Game.query.get(roomid)
|
|
if game:
|
|
player = fll.current_user
|
|
if not game.start:
|
|
return flask.redirect('/game/{}/join'.format(roomid))
|
|
if game.authorized(player) :
|
|
if game.id not in namespaces:
|
|
create_namespace(game.id)
|
|
return flask.render_template('game.html', game=game, user=player)
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/game/<roomid>/del')
|
|
@fll.login_required
|
|
def delgame(roomid):
|
|
game = Game.query.get(roomid)
|
|
if game is not None and fll.current_user.login == game.admin:
|
|
confirm = flask.request.args.get('confirm')
|
|
if confirm is not None:
|
|
db.session.delete(game)
|
|
db.session.commit()
|
|
else:
|
|
return flask.render_template('game_del.html', game=game, user=fll.current_user)
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
#######################################################################
|
|
# Users management #
|
|
#######################################################################
|
|
@app.route('/admin/users')
|
|
@fll.login_required
|
|
def admin_users():
|
|
if fll.current_user.level < levels_users['Can manage simple users']:
|
|
return flask.redirect(URL_DEFAULT)
|
|
users = User.query.all()
|
|
return flask.render_template('admin_users.html', user=fll.current_user, users=users)
|
|
|
|
@app.route('/admin/users/<user>', methods=['GET', 'POST'])
|
|
@fll.login_required
|
|
def edituser(user):
|
|
new = user=='new'
|
|
user = User.query.get(user)
|
|
if not new and user is None:
|
|
return flask.redirect('/admin/users')
|
|
if fll.current_user.level >= levels_users['Admin'] or \
|
|
fll.current_user.level >= levels_users['Can manage simple users'] and \
|
|
fll.current_user.level > user.level:
|
|
if flask.request.method=="POST":
|
|
username = flask.request.form['username']
|
|
name = flask.request.form['name']
|
|
password = flask.request.form['password']
|
|
level = int(flask.request.form['level'])
|
|
if level not in levels_users.values():
|
|
flask.flash('Level unknown')
|
|
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
|
if fll.current_user.level < levels_users['Admin']:
|
|
if not level < fll.current_user.level:
|
|
flask.flash('Invalid level')
|
|
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
|
if len(password)<2 and new:
|
|
flask.flash('Mot de passe trop court')
|
|
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
|
if new and User.query.get(username) is not None:
|
|
flask.flash('Login déjà utilisé ! Choisissez un autre !')
|
|
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
|
if new:
|
|
usertoadd = User(login=username, name=name, level=level)
|
|
usertoadd.set_password(password)
|
|
db.session.add(usertoadd)
|
|
else:
|
|
user.name = name
|
|
if len(password)>=2:
|
|
user.set_password(password)
|
|
user.level = level
|
|
db.session.commit()
|
|
return flask.redirect('/admin/users')
|
|
else:
|
|
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/admin/users/<user>/del')
|
|
@fll.login_required
|
|
def deluser(user):
|
|
user = User.query.get(user)
|
|
if user is None:
|
|
return flask.redirect('/admin/users')
|
|
if fll.current_user.level >= levels_users['Admin'] or \
|
|
fll.current_user.level >= levels_users['Can manage simple users'] and \
|
|
fll.current_user.level > user.level:
|
|
confirm = flask.request.args.get('confirm')
|
|
if confirm is not None:
|
|
delete_game(user=user)
|
|
db.session.delete(user)
|
|
db.session.commit()
|
|
return flask.redirect('/admin/users')
|
|
return flask.render_template("admin_user_del.html", user=fll.current_user, useredit=user)
|
|
|
|
@app.route('/password', methods=['GET', 'POST'])
|
|
@fll.login_required
|
|
def change_password():
|
|
if flask.request.method=="POST":
|
|
password = flask.request.form['password']
|
|
if len(password) < 5:
|
|
flask.flash('Mot de passe trop court !')
|
|
else:
|
|
fll.current_user.set_password(password)
|
|
db.session.commit()
|
|
return flask.redirect(URL_DEFAULT)
|
|
return flask.render_template("password.html", user=fll.current_user)
|
|
|
|
#######################################################################
|
|
# Game managament #
|
|
#######################################################################
|
|
@app.route('/admin/games')
|
|
@fll.login_required
|
|
def admin_games():
|
|
if fll.current_user.level < levels_users['Can manage games']:
|
|
return flask.redirect(URL_DEFAULT)
|
|
games = Game.query.all()
|
|
return flask.render_template('admin_games.html', user=fll.current_user, games=games)
|
|
|
|
@app.route('/admin/games/<roomid>/del')
|
|
@fll.login_required
|
|
def admin_game_del(roomid):
|
|
game = Game.query.get(roomid)
|
|
if game is None:
|
|
return flask.redirect('/admin/games')
|
|
if fll.current_user.level >= levels_users['Can manage games']:
|
|
confirm = flask.request.args.get('confirm')
|
|
if confirm is not None:
|
|
delete_game(game=game)
|
|
return flask.redirect('/admin/games')
|
|
else:
|
|
return flask.render_template('game_del.html', user=fll.current_user, game=game)
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/game/<roomid>/see')
|
|
@fll.login_required
|
|
def see_game(roomid):
|
|
game = Game.query.get(roomid)
|
|
if game is None:
|
|
return flask.redirect('/games')
|
|
if fll.current_user.level >= levels_users['Can manage games'] or game.authorized(fll.current_user) and game.turn==N_TURN*N_PLAYERS:
|
|
#return game.serialize_state_anonymous()
|
|
return flask.render_template('game_see.html', user=fll.current_user, game=game, serialized=game.serialize_state_anonymous())
|
|
return flask.redirect(URL_DEFAULT)
|
|
|
|
@app.route('/admin/games/new', methods=['GET', 'POST'])
|
|
@fll.login_required
|
|
def admin_games_new():
|
|
if fll.current_user.level < levels_users['Can manage games']:
|
|
return flask.redirect(URL_DEFAULT)
|
|
if flask.request.method=="POST":
|
|
name = flask.request.form['name']
|
|
login0 = flask.request.form['player0']
|
|
login1 = flask.request.form['player1']
|
|
login2 = flask.request.form['player2']
|
|
login3 = flask.request.form['player3']
|
|
admin = flask.request.form['admin']
|
|
if 'fixplayers' in flask.request.form:
|
|
start = True
|
|
else:
|
|
start = False
|
|
|
|
try:
|
|
admin = int(admin)
|
|
except:
|
|
return 'Error'
|
|
if admin<0 or admin>3:
|
|
return 'Error'
|
|
|
|
adminn = -1
|
|
lusers = []
|
|
|
|
if login0 != '':
|
|
user0 = User.query.get(login0)
|
|
if user0 is None:
|
|
flask.flash('Utilisateur inconnu {}'.format(login0))
|
|
else:
|
|
lusers.append(user0)
|
|
if admin==0: adminn = 0
|
|
if login1 != '':
|
|
user1 = User.query.get(login1)
|
|
if user1 is None:
|
|
flask.flash('Utilisateur inconnu {}'.format(login1))
|
|
else:
|
|
if admin==1: adminn = len(lusers)
|
|
lusers.append(user1)
|
|
if login2 != '':
|
|
user2 = User.query.get(login2)
|
|
if user2 is None:
|
|
flask.flash('Utilisateur inconnu {}'.format(login2))
|
|
else:
|
|
if admin==2: adminn = len(lusers)
|
|
lusers.append(user2)
|
|
if login3 != '':
|
|
user3 = User.query.get(login3)
|
|
if user3 is None:
|
|
flask.flash('Utilisateur inconnu {}'.format(login3))
|
|
else:
|
|
if admin==3: adminn = len(lusers)
|
|
lusers.append(user3)
|
|
|
|
if adminn <0:
|
|
flask.flash('Vous devez définir un maitre du jeu (admin).')
|
|
elif len(name)<2:
|
|
flask.flash('Nom trop court !')
|
|
else:
|
|
game = Game(name=name, admin=lusers[adminn].login)
|
|
db.session.add(game)
|
|
db.session.commit()
|
|
ordered_players = []
|
|
for u in lusers:
|
|
ordered_players.append(u.login)
|
|
game.join(u)
|
|
db.session.commit()
|
|
|
|
if start and game.can_start():
|
|
game.fix_players()
|
|
game.start_game(ordered_players)
|
|
return flask.redirect('/admin/games')
|
|
return flask.render_template('admin_game_add.html', user=fll.current_user)
|
|
|
|
|
|
|
|
def delete_game(user=None, game=None):
|
|
if user is not None:
|
|
games = Game.query.filter_by(admin=user.login).all()
|
|
for g in games:
|
|
for p in g.players:
|
|
db.session.delete(p)
|
|
db.session.delete(g)
|
|
db.session.commit()
|
|
if isinstance(game, int):
|
|
g = Game.query.get(game)
|
|
if g is not None:
|
|
for p in g.players:
|
|
db.session.delete(p)
|
|
db.session.delete(g)
|
|
db.session.commit()
|
|
elif game is not None:
|
|
for p in game.players:
|
|
db.session.delete(p)
|
|
db.session.delete(game)
|
|
db.session.commit()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
socketio.run(app, debug=True, host='127.0.0.1', port=8080 )
|
|
|