#!/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//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//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/') @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//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/', 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//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//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//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 )