roulette/roulette.py

460 lines
14 KiB
Python
Raw Normal View History

2017-01-26 22:32:27 +00:00
# -*- coding: utf8 -*
2017-01-27 09:49:01 +00:00
from flask import Flask, request, g, redirect, url_for, \
2017-01-26 22:32:27 +00:00
abort, render_template, flash
from functools import wraps
from contextlib import closing
import sqlite3
import MySQLdb as mdb
from time import time, localtime, strftime
import locale
import random
# configuration
DEBUG = True
SECRET_KEY = "\xf3'\xd2\xf7\xa4[.h\x8e\x11|\xda\x00\x9fyS\xfe\xb3(!\x91'6\x16"
USERNAME = 'admin'
2017-01-26 22:32:27 +00:00
PASSWORD = 'pipo'
2017-01-29 23:05:29 +00:00
ASSHOLES = []
2017-01-26 22:32:27 +00:00
SQLITE_FILENAME = '/var/roulette/players.db'
2017-01-26 22:32:27 +00:00
SQLITE_SCHEMA = 'schema.sql'
MYSQL_HOST = 'mysql.rez'
MYSQL_USER = 'rezo_admin_ro'
MYSQL_PASSWORD = 'rezopaspipo'
MYSQL_DB = 'rezo_admin'
2017-01-26 22:32:27 +00:00
BAN_DURATION = 30. * 60.
2017-01-29 16:00:21 +00:00
IMMUNITY_FILE = '/var/roulette/immunity'
2017-01-29 18:54:55 +00:00
ASSHOLES_FILE = '/var/roulette/assholes'
STATE_FILE = '/var/roulette/state'
2017-01-26 22:32:27 +00:00
2017-01-29 23:05:29 +00:00
STATE = 'down'
2017-01-26 22:32:27 +00:00
2017-01-28 15:40:27 +00:00
app = Flask(__name__)
app.config.from_object(__name__)
2017-01-26 22:32:27 +00:00
app.secret_key = SECRET_KEY
random.seed(time())
locale.setlocale(locale.LC_ALL, 'fr_FR.utf8')
# Utilisation de la base SQLite
def connect_sqlite():
return sqlite3.connect(SQLITE_FILENAME)
2017-01-26 22:32:27 +00:00
def init_db():
# Initialisation de la base SQLite
with closing(connect_sqlite()) as con_sqlite:
2017-01-26 23:58:05 +00:00
with app.open_resource('schema.sql') as f:
con_sqlite.cursor().executescript(f.read().decode("utf-8"))
2017-01-26 23:58:32 +00:00
con_sqlite.commit()
2017-01-26 22:32:27 +00:00
# Connexion à la base SQLite locale
con_sqlite = connect_sqlite()
cur_sqlite = con_sqlite.cursor()
# Connexion à la base MySQL sur babel
con_mysql = mdb.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB, \
charset='utf8', use_unicode=True)
cur_mysql = con_mysql.cursor(mdb.cursors.DictCursor)
# Remplissage de la table players à partir de la table utilisateurs
cur_mysql.execute("""select id,prenom,nom from utilisateurs
where etat='STATE_ACTIVE' and ecole_id=1 and id<>1
and typeUtilisateur='membre'""")
rows = cur_mysql.fetchall()
print('players :')
for row in rows:
if row['prenom'] + ' ' + row['nom'] not in IMMUNITY:
print(row)
cur_sqlite.execute("""insert into players values (?,?,?,?)""", \
((row["id"]), row["prenom"], row["nom"], 0))
# Remplissage de la table ip à partir de la table equipements
cur_mysql.execute("""select equipements.id,utilisateurs.id,equipements.ip
from utilisateurs
inner join equipements on utilisateurs.id=equipements.utilisateur_id
where utilisateurs.ecole_id=1 and utilisateurs.id<>1
and utilisateurs.etat='STATE_ACTIVE' and equipements.etat='STATE_ACTIVE'
and utilisateurs.typeUtilisateur='membre'""")
rows = cur_mysql.fetchall()
print('machines :')
for row in rows:
print(row)
cur_sqlite.execute("""insert into machines values (?,?,?)""", \
(row["id"], row["utilisateurs.id"], row["ip"]))
con_sqlite.commit()
cur_sqlite.close()
cur_mysql.close()
2017-01-26 22:32:27 +00:00
def duration_format(seconds):
hours = seconds // 3600
2017-01-26 22:32:27 +00:00
seconds -= 3600*hours
minutes = seconds // 60
2017-01-26 22:32:27 +00:00
seconds -= 60*minutes
s_str = seconds <= 1 and 'seconde' or 'secondes'
m_str = minutes <= 1 and 'minute' or 'minutes'
h_str = hours <= 1 and 'heure' or 'heures'
if hours == 0:
if minutes == 0:
return '%01d %s' % (seconds, s_str)
return '%01d %s et %01d %s' % (minutes, m_str, seconds, s_str)
return '%01d %s, %01d %s et %01d %s' % (hours, h_str, minutes, m_str, seconds, s_str)
def get_ip():
return request.remote_addr
def get_player(player_id):
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select id,firstname,name,ban_end from players
2017-01-26 22:32:27 +00:00
where id=(?)""", [player_id])
row = cur.fetchone()
con.close()
return {'id': row[0], 'firstname': row[1], 'name': row[2], 'ban_end': row[3]}
2017-01-26 22:32:27 +00:00
def get_player_from_ip(ip):
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select players.id,players.firstname,players.name,
machines.id,machines.ip,players.ban_end
2017-01-26 22:32:27 +00:00
from players
inner join machines on players.id=machines.player_id
where machines.ip=(?)""", [ip])
row = cur.fetchone()
con.close()
2017-01-29 16:00:21 +00:00
print("last good line")
2017-01-26 22:32:27 +00:00
user = None
if row is not None:
user = {'id': row[0], 'firstname': row[1], 'name': row[2], \
'machine_id': row[3], 'ip': row[4], 'ban_end': row[5]}
2017-01-26 22:32:27 +00:00
return user
def get_player_from_full_name(firstname, name):
2017-01-26 22:32:27 +00:00
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select players.id,players.firstname,players.name,
machines.id,machines.ip,players.ban_end
2017-01-26 22:32:27 +00:00
from players
inner join machines on players.id=machines.player_id
where players.firstname=(?) and players.name=(?)""", [firstname, name])
2017-01-26 22:32:27 +00:00
row = cur.fetchone()
con.close()
user = None
if row is not None:
user = {'id': row[0], 'firstname': row[1], 'name': row[2], \
'machine_id': row[3], 'ip': row[4], 'ban_end': row[5]}
2017-01-26 22:32:27 +00:00
return user
def is_banned(user_id):
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select ban_end from players where id=(?)""", [user_id])
2017-01-26 22:32:27 +00:00
ban_end = cur.fetchone()[0]
2017-01-26 22:32:27 +00:00
con.close()
return time() < ban_end
2017-01-26 22:32:27 +00:00
def playable_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
2017-01-27 08:35:18 +00:00
ip=get_ip()
2017-01-28 15:07:34 +00:00
user = get_player_from_ip(ip)
2017-01-27 08:35:18 +00:00
2017-01-27 09:49:01 +00:00
if not user:
2017-01-30 08:44:35 +00:00
return render_template('not_subscribed.html',stats=statistiques())
2017-01-26 22:32:27 +00:00
# Un utilisateur banni ne peut pas jouer
2017-01-27 09:49:01 +00:00
elif is_banned(user['id']):
2017-01-26 22:32:27 +00:00
return banned()
return f(*args, **kwargs)
return decorated_function
def get_players_not_banned():
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select id,firstname,name from players
where (?) > ban_end """, [time()])
2017-01-26 22:32:27 +00:00
rows = cur.fetchall()
con.close()
2017-01-28 16:12:13 +00:00
not_banned = [{'id': row[0], 'firstname': row[1], 'name': row[2]} for row in rows]
2017-01-29 16:29:26 +00:00
2017-01-28 16:12:13 +00:00
# Ensuite on applique les règles d'immunité
with open(IMMUNITY_FILE, 'r') as f:
immunity = f.read()
result = []
for user in not_banned:
2017-01-29 16:00:21 +00:00
if user['firstname']+' '+user['name'] not in immunity:
2017-01-28 16:12:13 +00:00
result.append(user)
return result
2017-01-26 22:32:27 +00:00
def cheat(player_id, target_id):
success = random.choice([True, False])
try:
2017-01-28 16:12:13 +00:00
# ok = [line.strip().partition(' ') for line in IMMUNITY]
# ok = [get_player_from_full_name(names[0], names[2])['id'] for names in ok]
2017-01-26 22:32:27 +00:00
ko = [line.strip().partition(' ') for line in ASSHOLES]
ko = [get_player_from_full_name(names[0], names[2])['id'] for names in ko]
2017-01-26 22:32:27 +00:00
if target_id in ko:
success = True
elif player_id in ko:
success = False
2017-01-28 16:12:13 +00:00
# elif target_id in ok:
# success = False
2017-01-26 22:32:27 +00:00
except TypeError:
2017-01-26 22:44:28 +00:00
pass
2017-01-26 22:32:27 +00:00
return success
2017-01-26 22:32:27 +00:00
def ban(player_id, target_id, success):
player = get_player(player_id)
target = get_player(target_id)
2017-01-26 22:32:27 +00:00
banned_player = success and target or player
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select id,ban_end from players
2017-01-26 22:32:27 +00:00
where id=(?)""", [banned_player['id']])
ban_end = cur.fetchone()[0]
ban_end = time() + BAN_DURATION
2017-01-26 22:32:27 +00:00
cur.execute("""update players set ban_end=(?)
where id=(?)""", [ban_end, banned_player['id']])
2017-01-26 22:32:27 +00:00
cur.execute("""insert into bans (player_id,target_id,success,time)
values (?,?,?,?)""", [player['id'], target['id'], \
success and 1 or 0, time()])
con.commit()
con.close()
def unban(player_id):
con = connect_sqlite()
cur = con.cursor()
cur.execute("""update players set ban_end=(?)
2017-01-26 22:32:27 +00:00
where id=(?)""", [time() - BAN_DURATION, player_id])
2017-01-26 22:32:27 +00:00
con.commit()
con.close()
def get_bans(player_id):
con = connect_sqlite()
cur = con.cursor()
# Bannissements concernant le joueur :
cur.execute("""select player_id,target_id,success,time from bans
where target_id=(?)
or player_id=(?)""", [player_id, player_id])
rows = cur.fetchall()
con.close()
return [{'player_id': row[0], 'target_id': row[1], \
'success': row[2], 'time': row[3]} for row in rows]
def banned():
player = get_player_from_ip(get_ip())
2017-01-27 00:10:29 +00:00
if DEBUG:
print(player,'is banned and tries to play')
2017-01-26 22:32:27 +00:00
last_ban = sorted(get_bans(player['id']), key=lambda p: p['time'], \
reverse=False)[-1]
if last_ban['target_id'] == player['id'] and last_ban['success'] == 1:
source = get_player(last_ban['player_id'])
2017-01-29 16:29:26 +00:00
explanation = u'Tu t\'es fait trancher par %s %s.' \
% (source['firstname'], source['name'])
2017-01-26 22:32:27 +00:00
else:
2017-01-29 16:29:26 +00:00
explanation = u'Tu t\'es tranché toi-même, pas de chance...'
2017-01-26 22:32:27 +00:00
2017-01-30 08:44:35 +00:00
timeleft = int(player['ban_end'] - time())
return render_template('banned.html', \
explanation=explanation, timeleft=timeleft, stats=statistiques())
def statistiques():
#Calcul des statistiques
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select firstname,name,ban_end from players""")
rows = cur.fetchall()
con.close()
tranchés = 0
n_tranchés = 0
with open(IMMUNITY_FILE, 'r') as f:
immunity = f.read()
for row in rows:
if row[0]+' '+row[1] not in immunity:
if row[2] > time():
tranchés += 1
else:
n_tranchés += 1
stats = (tranchés,n_tranchés)
2017-01-30 08:44:35 +00:00
return stats
2017-01-26 22:32:27 +00:00
@app.route('/banned_ip')
def banned_ip():
2017-01-29 18:54:55 +00:00
#Actualisation de l'etat de la roulette
with open(STATE_FILE, 'r') as f:
global STATE
2017-01-29 18:54:55 +00:00
STATE = f.read()
2017-01-29 23:05:29 +00:00
if DEBUG :
print(STATE)
2017-01-26 22:32:27 +00:00
# Liste des ip pour récupération par babel et plop
2017-01-27 00:06:04 +00:00
if not DEBUG:
2017-01-27 08:35:18 +00:00
if get_ip() not in ['10.7.0.254']:
2017-01-27 00:06:04 +00:00
abort(403)
2017-01-26 22:32:27 +00:00
con = connect_sqlite()
cur = con.cursor()
cur.execute("""select machines.ip from players
inner join machines on players.id=machines.player_id
where players.ban_end>(?)""", [time()])
2017-01-26 22:32:27 +00:00
rows = cur.fetchall()
con.close()
return '\n'.join([row[0] for row in rows])
@app.route('/')
@playable_required
def home():
2017-01-27 09:49:01 +00:00
player = get_player_from_ip(get_ip())
2017-01-29 23:05:29 +00:00
if DEBUG:
print(STATE)
2017-01-30 09:30:26 +00:00
if DEBUG:
print(player, 'arrived')
bans = sorted(get_bans(player['id']), \
key=lambda ban: ban['time'], \
reverse=True)
bans_hist = []
for ban in bans:
date = strftime('%Hh%M (%A)', localtime(ban['time']))
source = get_player(ban['player_id'])
target = get_player(ban['target_id'])
if target['id'] == player['id']:
if ban['success']:
entry = ('ban', u'%s : %s %s a réussi à t\'avoir.' \
% (date, source['firstname'], source['name']))
else:
entry = ('warn', u'%s : %s %s a essayé de te trancher, en vain.' \
% (date, source['firstname'], source['name']))
else:
if ban['success']:
entry = ('ok', u'%s : Tu as tranché %s %s avec succès.' \
% (date, target['firstname'], target['name']))
else:
entry = ('ban', u'%s : Tu as échoué en voulant trancher %s %s.' \
% (date, target['firstname'], target['name']))
bans_hist.append(entry)
2017-01-29 23:05:29 +00:00
if "down" in STATE:
2017-01-30 09:30:26 +00:00
return render_template('down.html', user=player, stats=statistiques(), bans_hist=bans_hist)
2017-01-29 23:05:29 +00:00
elif "up" in STATE:
2017-01-30 09:30:26 +00:00
return render_template('home.html', bans_hist=bans_hist, stats=statistiques())
else:
return render_template('precampagne.html', user=player,stats=statistiques())
2017-01-29 18:54:55 +00:00
2017-01-30 09:30:26 +00:00
@app.route('/jouer', methods=['GET', 'POST'])
@playable_required
def play():
ip = get_ip()
player = get_player_from_ip(ip)
if "down" in STATE:
2017-01-29 18:54:55 +00:00
bans = sorted(get_bans(player['id']), \
key=lambda ban: ban['time'], \
reverse=True)
bans_hist = []
for ban in bans:
date = strftime('%Hh%M (%A)', localtime(ban['time']))
source = get_player(ban['player_id'])
target = get_player(ban['target_id'])
if target['id'] == player['id']:
if ban['success']:
entry = ('ban', u'%s : %s %s a réussi à t\'avoir.' \
% (date, source['firstname'], source['name']))
else:
entry = ('warn', u'%s : %s %s a essayé de te trancher, en vain.' \
% (date, source['firstname'], source['name']))
2017-01-26 22:32:27 +00:00
else:
2017-01-29 18:54:55 +00:00
if ban['success']:
entry = ('ok', u'%s : Tu as tranché %s %s avec succès.' \
% (date, target['firstname'], target['name']))
else:
entry = ('ban', u'%s : Tu as échoué en voulant trancher %s %s.' \
% (date, target['firstname'], target['name']))
bans_hist.append(entry)
2017-01-30 08:44:35 +00:00
return render_template('down.html', user=player,stats=statistiques())
2017-01-30 09:30:26 +00:00
2017-01-30 01:02:12 +00:00
elif "up" in STATE:
2017-01-29 18:54:55 +00:00
# Traitement de la requête de bannissement
if request.method == 'POST':
target_id = request.form['target_id']
if target_id != 'none':
if is_banned(target_id):
flash(u'Utilisateur déjà tranché, il faut en choisir un autre.')
2017-01-26 22:32:27 +00:00
else:
2017-01-29 18:54:55 +00:00
success = cheat(player['id'], target_id)
if success:
target = get_player(target_id)
ban(player['id'], target_id, True)
flash(u'Trop cool, %s a été tranché pour un bon moment.' \
% target['firstname'])
else:
ban(player['id'], target_id, False)
return banned()
# Liste des joueurs non bannis, triée dans l'ordre croissant ou décroissant
players = sorted(get_players_not_banned(), \
key=lambda player: player['firstname'], \
reverse = random.choice([True, False]))
# sans le joueur actuel
players = filter(lambda p: p['id'] != player['id'], players)
2017-01-30 08:44:35 +00:00
return render_template('play.html', players=players, stats=statistiques())
2017-01-29 18:55:54 +00:00
else:
2017-01-30 08:44:35 +00:00
return render_template('precampagne.html', user=player,stats=statistiques())
2017-01-26 22:32:27 +00:00
2017-01-28 15:40:27 +00:00
if __name__ == '__main__':
2017-01-26 22:32:27 +00:00
app.run()