444 lines
14 KiB
Python
444 lines
14 KiB
Python
# -*- coding: utf8 -*
|
|
|
|
from flask import Flask, request, g, redirect, url_for, \
|
|
abort, render_template, flash
|
|
|
|
from functools import wraps
|
|
from contextlib import closing
|
|
import sqlite3
|
|
import MySQLdb
|
|
from time import time, localtime, strftime
|
|
import locale
|
|
import random
|
|
import json
|
|
|
|
# configuration
|
|
DEBUG = True
|
|
SECRET_KEY = "\xf3'\xd2\xf7\xa4[.h\x8e\x11|\xda\x00\x9fyS\xfe\xb3(!\x91'6\x16"
|
|
USERNAME = 'admin'
|
|
PASSWORD = 'pipo'
|
|
ASSHOLES = []
|
|
|
|
SQLITE_FILENAME = '/var/roulette/players.db'
|
|
SQLITE_SCHEMA = 'schema.sql'
|
|
|
|
BAN_DURATION = 30. * 60.
|
|
|
|
IMMUNITY_FILE = '/var/roulette/immunity'
|
|
ASSHOLES_FILE = '/var/roulette/assholes'
|
|
STATE_FILE = '/var/roulette/state'
|
|
|
|
STATE = 'down'
|
|
#Actualisation de l'etat de la roulette
|
|
with open(STATE_FILE, 'r') as f:
|
|
STATE = f.read()
|
|
|
|
|
|
app = Flask(__name__)
|
|
app.config.from_object(__name__)
|
|
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)
|
|
|
|
def connect_sql():
|
|
return MySQLdb.connect(host="localhost", # your host, usually localhost
|
|
user="root", # your username
|
|
passwd="F5XUaZmkWaWp3GDnT73WuEGZqAN5hMF3", # your password
|
|
db="roulette") # name of the data base
|
|
|
|
def init_db():
|
|
# Initialisation de la base SQLite
|
|
pass
|
|
|
|
def duration_format(seconds):
|
|
hours = seconds // 3600
|
|
seconds -= 3600*hours
|
|
minutes = seconds // 60
|
|
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_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select id,firstname,name,ban_end from players
|
|
where id=%i"""% player_id)
|
|
|
|
row = cur.fetchone()
|
|
con.close()
|
|
|
|
return {'id': row[0], 'firstname': row[1], 'name': row[2], 'ban_end': row[3]}
|
|
|
|
def get_player_from_ip(ip):
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select players.id,players.firstname,players.name,
|
|
machines.id,machines.ip,players.ban_end
|
|
from players
|
|
inner join machines on players.id=machines.player_id
|
|
where machines.ip=\"%s\""""% ip)
|
|
|
|
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]}
|
|
|
|
return user
|
|
|
|
def get_player_from_full_name(firstname, name):
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select players.id,players.firstname,players.name,
|
|
machines.id,machines.ip,players.ban_end
|
|
from players
|
|
inner join machines on players.id=machines.player_id
|
|
where players.firstname=\"%s\" and players.name=\"%s\""""% (firstname, name))
|
|
|
|
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]}
|
|
|
|
return user
|
|
|
|
def is_banned(user_id):
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select ban_end from players where id=%i"""% user_id)
|
|
|
|
ban_end = cur.fetchone()[0]
|
|
con.close()
|
|
|
|
return time() < ban_end
|
|
|
|
def playable_required(f):
|
|
@wraps(f)
|
|
def decorated_function(*args, **kwargs):
|
|
ip=get_ip()
|
|
user = get_player_from_ip(ip)
|
|
|
|
if not user:
|
|
return render_template('not_subscribed.html',stats=statistiques())
|
|
|
|
# Un utilisateur banni ne peut pas jouer
|
|
elif is_banned(user['id']) and ('up' in STATE):
|
|
return banned()
|
|
|
|
return f(*args, **kwargs)
|
|
return decorated_function
|
|
|
|
def get_players_not_banned():
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select id,firstname,name from players
|
|
where %f > ban_end """% time())
|
|
|
|
rows = cur.fetchall()
|
|
con.close()
|
|
|
|
not_banned = [{'id': row[0], 'firstname': row[1], 'name': row[2]} for row in rows]
|
|
|
|
# Ensuite on applique les règles d'immunité
|
|
result = []
|
|
for user in not_banned:
|
|
result.append(user)
|
|
return result
|
|
|
|
def cheat(player_id, target_id):
|
|
success = random.choice([True, False])
|
|
with open(IMMUNITY_FILE, 'r') as f:
|
|
immunity = f.read()
|
|
with open(ASSHOLES_FILE, 'r') as f:
|
|
assholes = f.read()
|
|
ok = [line.split(' ') for line in immunity.split('\n') if line]
|
|
ok = [get_player_from_full_name(names[0], names[1])['id'] for names in ok]
|
|
|
|
ko_names = [line.split(' ') for line in assholes.split('\n') if line]
|
|
ko = []
|
|
for names in ko_names:
|
|
p = get_player_from_full_name(names[0], names[1])
|
|
if p:
|
|
ko.append(p['id'])
|
|
if target_id in ko:
|
|
success = True
|
|
elif player_id in ko:
|
|
success = False
|
|
elif target_id in ok:
|
|
success = False
|
|
elif player_id in ok:
|
|
success = True
|
|
|
|
|
|
return success
|
|
|
|
|
|
def ban(player_id, target_id, success):
|
|
player = get_player(player_id)
|
|
target = get_player(target_id)
|
|
|
|
banned_player = success and target or player
|
|
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select id,ban_end from players
|
|
where id=%i"""% banned_player['id'])
|
|
|
|
ban_end = cur.fetchone()[0]
|
|
ban_end = time() + BAN_DURATION
|
|
|
|
cur.execute("""update players set ban_end=%f
|
|
where id=%i"""% (ban_end, banned_player['id']))
|
|
requete = """insert into bans (player_id,target_id,success,time) values (%i,%i,%i,%f)"""% (player['id'], target['id'],success and 1 or 0, time())
|
|
cur.execute(requete)
|
|
if DEBUG:
|
|
print(requete)
|
|
con.commit()
|
|
con.close()
|
|
|
|
|
|
def unban(player_id):
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""update players set ban_end=%f
|
|
where id=%i"""% (time() - BAN_DURATION, player_id))
|
|
|
|
con.commit()
|
|
con.close()
|
|
|
|
def get_bans(player_id):
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
# Bannissements concernant le joueur :
|
|
cur.execute("""select player_id,target_id,success,time from bans where target_id=%i or player_id=%i""" % (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())
|
|
if DEBUG:
|
|
print(player,'is banned and tries to play')
|
|
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'])
|
|
explanation = u'Tu t\'es fait trancher par %s %s.' \
|
|
% (source['firstname'], source['name'])
|
|
else:
|
|
explanation = u'Tu t\'es tranché toi-même, pas de chance...'
|
|
|
|
timeleft = int(player['ban_end'] - time())
|
|
|
|
return render_template('banned.html', \
|
|
explanation=explanation, timeleft=timeleft, stats=statistiques())
|
|
|
|
def statistiques():
|
|
#Calcul des statistiques
|
|
con = connect_sql()
|
|
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
|
|
|
|
return (tranchés,n_tranchés)
|
|
|
|
|
|
@app.route('/banned_ip')
|
|
def banned_ip():
|
|
#Actualisation de l'etat de la roulette
|
|
with open(STATE_FILE, 'r') as f:
|
|
global STATE
|
|
STATE = f.read()
|
|
if DEBUG :
|
|
print(STATE)
|
|
|
|
# Liste des ip pour récupération par babel et plop
|
|
if not DEBUG:
|
|
if get_ip() not in ['10.7.0.254']:
|
|
abort(403)
|
|
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
|
|
cur.execute("""select machines.ip from players
|
|
inner join machines on players.id=machines.player_id
|
|
where players.ban_end>%f"""% time())
|
|
|
|
rows = cur.fetchall()
|
|
con.close()
|
|
|
|
return '\n'.join([row[0] for row in rows])
|
|
|
|
@app.route('/')
|
|
@playable_required
|
|
def home():
|
|
player = get_player_from_ip(get_ip())
|
|
if DEBUG:
|
|
print(player, 'arrived and the site is',STATE)
|
|
with open(IMMUNITY_FILE, 'r') as f:
|
|
immunity = f.read()
|
|
ok = [line.split(' ') for line in immunity.split('\n') if line]
|
|
ok = [get_player_from_full_name(names[0], names[1])['id'] for names in ok]
|
|
player_has_immunity = player['id'] in ok
|
|
|
|
bans = sorted(get_bans(player['id']), \
|
|
key=lambda ban: ban['time'], \
|
|
reverse=True)
|
|
|
|
bans_hist = []
|
|
for banned_user in bans:
|
|
date = strftime('%Hh%M (%A)', localtime(banned_user['time']))
|
|
source = get_player(banned_user['player_id'])
|
|
target = get_player(banned_user['target_id'])
|
|
|
|
if target['id'] == player['id']:
|
|
if banned_user['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 banned_user['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)
|
|
|
|
if "down" in STATE:
|
|
return render_template('down.html', user=player, stats=statistiques(), bans_hist=bans_hist)
|
|
elif "up" in STATE or player_has_immunity:
|
|
return render_template('home.html', bans_hist=bans_hist, stats=statistiques())
|
|
else:
|
|
return render_template('precampagne.html', user=player,stats=statistiques())
|
|
|
|
@app.route('/jouer', methods=['GET', 'POST'])
|
|
@playable_required
|
|
def play():
|
|
ip = get_ip()
|
|
player = get_player_from_ip(ip)
|
|
with open(IMMUNITY_FILE, 'r') as f:
|
|
immunity = f.read()
|
|
ok = [line.split(' ') for line in immunity.split('\n') if line]
|
|
ok = [get_player_from_full_name(names[0], names[1])['id'] for names in ok]
|
|
player_has_immunity = player['id'] in ok
|
|
if "down" in STATE:
|
|
bans = sorted(get_bans(player['id']), \
|
|
key=lambda ban: ban['time'], \
|
|
reverse=True)
|
|
|
|
bans_hist = []
|
|
for banned_user in bans:
|
|
date = strftime('%Hh%M (%A)', localtime(banned_user['time']))
|
|
source = get_player(banned_user['player_id'])
|
|
target = get_player(banned_user['target_id'])
|
|
|
|
if target['id'] == player['id']:
|
|
if banned_user['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 banned_user['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)
|
|
return render_template('down.html', user=player,stats=statistiques())
|
|
|
|
elif "up" in STATE or player_has_immunity:
|
|
# Traitement de la requête de bannissement
|
|
if request.method == 'POST':
|
|
target_id = int(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.')
|
|
else:
|
|
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)
|
|
|
|
return render_template('play.html', players=players, stats=statistiques())
|
|
else:
|
|
return render_template('precampagne.html', user=player,stats=statistiques())
|
|
|
|
|
|
@app.route('/complete')
|
|
def complete():
|
|
v = request.args['v']
|
|
con = connect_sql()
|
|
cur = con.cursor()
|
|
cur.execute("""select id, firstname, name from players where
|
|
name like "{value}%" or firstname like "{value}%";""".format(value=v))
|
|
rows = [[i[0], i[1]+' '+i[2]] for i in cur.fetchall()]
|
|
con.close()
|
|
return json.dumps(rows)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.run()
|