Import depuis le home de lhark
2
README
Normal file
|
@ -0,0 +1,2 @@
|
|||
Le serveur a besoin des droits en écriture sur la base SQLite3 et le répertoire
|
||||
la contenant.
|
2
assholes
Normal file
|
@ -0,0 +1,2 @@
|
|||
Luc Absil
|
||||
Louis-Guillaume Dubois
|
6
immunity
Normal file
|
@ -0,0 +1,6 @@
|
|||
Goulven Kermarec
|
||||
Lazare Olivry
|
||||
Brieuc Lacroix
|
||||
Cyriaque Millot
|
||||
Juliette Tibayrenc
|
||||
Siqi Liu
|
BIN
players.db
Normal file
BIN
players.db.bak
Normal file
417
roulette.py
Normal file
|
@ -0,0 +1,417 @@
|
|||
# -*- coding: utf8 -*
|
||||
|
||||
from flask import Flask, request, session, g, redirect, url_for, \
|
||||
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'
|
||||
PASSWORD = 'pipo'
|
||||
|
||||
SQLITE_FILENAME = '/var/www/roulette/players.db'
|
||||
SQLITE_SCHEMA = 'schema.sql'
|
||||
|
||||
MYSQL_HOST = 'mysql.rez'
|
||||
MYSQL_USER = 'rezo_admin_ro'
|
||||
MYSQL_PASSWORD = 'rezopaspipo'
|
||||
MYSQL_DB = 'rezo_admin'
|
||||
|
||||
BAN_DURATION = 30. * 60.
|
||||
|
||||
IMMUNITY_FILE = '/var/www/roulette/immunity'
|
||||
ASSHOLES_FILE = '/var/www/roulette/assholes'
|
||||
|
||||
IMMUNITY = [
|
||||
'Lazare Olivry',
|
||||
'Brieuc Lacroix',
|
||||
'Elliot Butty',
|
||||
'Jean-Christophe Carli',
|
||||
'Juliette Tibayrenc',
|
||||
'Elise Laurent',
|
||||
'Goulven Kermarec',
|
||||
'Siqi Liu',
|
||||
]
|
||||
|
||||
ASSHOLES = []
|
||||
|
||||
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 init_db():
|
||||
# Initialisation de la base SQLite
|
||||
with closing(connect_sqlite()) as con_sqlite:
|
||||
with app.open_resource('schema.sql') as f:
|
||||
con_sqlite.cursor().executescript(f.read())
|
||||
con_sqlite.commit()
|
||||
|
||||
# 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()
|
||||
for row in rows:
|
||||
if row['prenom'] + ' ' + row['nom'] 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()
|
||||
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()
|
||||
|
||||
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_sqlite()
|
||||
cur = con.cursor()
|
||||
|
||||
cur.execute("""select id,firstname,name,ban_end from players
|
||||
where id=(?)""", [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_sqlite()
|
||||
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=(?)""", [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_sqlite()
|
||||
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=(?) and players.name=(?)""", [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_sqlite()
|
||||
cur = con.cursor()
|
||||
|
||||
cur.execute("""select ban_end from players where id=(?)""", [user_id])
|
||||
|
||||
ban_end = cur.fetchone()[0]
|
||||
con.close()
|
||||
|
||||
return time() < ban_end
|
||||
|
||||
def playable_required(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
user = get_player_from_ip(get_ip())
|
||||
|
||||
# Attention : un utilisateur inscrit ne peut pas être forcé à être
|
||||
# désinscrit s'il n'enlève pas son cookie de session. On évite la
|
||||
# réexécution de la requête.
|
||||
if 'subscribed' not in session or not session['subscribed']:
|
||||
session['subscribed'] = user is not None
|
||||
if not session['subscribed']:
|
||||
return render_template('not_subscribed.html')
|
||||
|
||||
# Un utilisateur banni ne peut pas jouer
|
||||
if user and is_banned(user['id']):
|
||||
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()])
|
||||
|
||||
rows = cur.fetchall()
|
||||
con.close()
|
||||
|
||||
return [{'id': row[0], 'firstname': row[1], 'name': row[2]} for row in rows]
|
||||
|
||||
def cheat(player_id, target_id):
|
||||
success = random.choice([True, False])
|
||||
try:
|
||||
ok = [line.strip().partition(' ') for line in IMMUNITY]
|
||||
ok = [get_player_from_full_name(names[0], names[2])['id'] for names in ok]
|
||||
|
||||
ko = [line.strip().partition(' ') for line in ASSHOLES]
|
||||
ko = [get_player_from_full_name(names[0], names[2])['id'] for names in ko]
|
||||
|
||||
if target_id in ko:
|
||||
success = True
|
||||
elif player_id in ko:
|
||||
success = False
|
||||
elif target_id in ok:
|
||||
success = False
|
||||
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
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_sqlite()
|
||||
cur = con.cursor()
|
||||
|
||||
cur.execute("""select id,ban_end from players
|
||||
where id=(?)""", [banned_player['id']])
|
||||
|
||||
ban_end = cur.fetchone()[0]
|
||||
ban_end = time() + BAN_DURATION
|
||||
|
||||
cur.execute("""update players set ban_end=(?)
|
||||
where id=(?)""", [ban_end, banned_player['id']])
|
||||
|
||||
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=(?)
|
||||
where id=(?)""", [time() - BAN_DURATION, player_id])
|
||||
|
||||
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())
|
||||
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 bannir par %s %s.' \
|
||||
% (source['firstname'], source['name'])
|
||||
else:
|
||||
explanation = u'Tu t\'es banni toi-même, pas de chance...'
|
||||
|
||||
timeleft = duration_format(int(player['ban_end'] - time()))
|
||||
|
||||
return render_template('banned.html', \
|
||||
explanation=explanation, timeleft=timeleft)
|
||||
|
||||
|
||||
@app.route('/banned_ip')
|
||||
def banned_ip():
|
||||
# Liste des ip pour récupération par babel et plop
|
||||
if get_ip() not in ['10.7.0.39', '10.7.0.254' ,'10.13.0.1', '10.69.8.5' ,'10.69.2.219']:
|
||||
abort(403)
|
||||
|
||||
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()])
|
||||
|
||||
rows = cur.fetchall()
|
||||
con.close()
|
||||
|
||||
return '\n'.join([row[0] for row in rows])
|
||||
|
||||
@app.route('/')
|
||||
@playable_required
|
||||
def home():
|
||||
ip = get_ip()
|
||||
player = get_player_from_ip(ip)
|
||||
|
||||
#if ip not in ['10.69.8.5', '10.69.8.202']:
|
||||
# abort(403)
|
||||
|
||||
if session.get('logged_in'):
|
||||
pass
|
||||
|
||||
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 bannir, en vain.' \
|
||||
% (date, source['firstname'], source['name']))
|
||||
else:
|
||||
if ban['success']:
|
||||
entry = ('ok', u'%s : Tu as banni %s %s avec succès.' \
|
||||
% (date, target['firstname'], target['name']))
|
||||
else:
|
||||
entry = ('ban', u'%s : Tu as échoué en voulant bannir %s %s.' \
|
||||
% (date, target['firstname'], target['name']))
|
||||
|
||||
bans_hist.append(entry)
|
||||
|
||||
return render_template('home.html', bans_hist=bans_hist)
|
||||
|
||||
@app.route('/jouer', methods=['GET', 'POST'])
|
||||
@playable_required
|
||||
def play():
|
||||
ip = get_ip()
|
||||
player = get_player_from_ip(ip)
|
||||
|
||||
# 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à banni, 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)
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
error = None
|
||||
if request.method == 'POST':
|
||||
if request.form['username'] != app.config['USERNAME']:
|
||||
error = 'Invalid username'
|
||||
elif request.form['password'] != app.config['PASSWORD']:
|
||||
error = 'Invalid password'
|
||||
else:
|
||||
session['logged_in'] = True
|
||||
flash('You were logged in')
|
||||
return redirect(url_for('home'))
|
||||
return render_template('login.html', error=error)
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
session.pop('logged_in', None)
|
||||
flash('You were logged out')
|
||||
return redirect(url_for('home'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
4
roulette.wsgi
Normal file
|
@ -0,0 +1,4 @@
|
|||
import sys
|
||||
sys.path.insert(0, '/var/www/roulette')
|
||||
|
||||
from roulette import app as application
|
23
schema.sql
Normal file
|
@ -0,0 +1,23 @@
|
|||
drop table if exists players;
|
||||
create table players (
|
||||
id integer primary key autoincrement,
|
||||
firstname text not null,
|
||||
name text not null,
|
||||
ban_end float not null
|
||||
);
|
||||
|
||||
drop table if exists machines;
|
||||
create table machines (
|
||||
id integer primary key autoincrement,
|
||||
player_id integer not null,
|
||||
ip text not null
|
||||
);
|
||||
|
||||
drop table if exists bans;
|
||||
create table bans (
|
||||
id integer primary key autoincrement,
|
||||
player_id integer not null,
|
||||
target_id integer not null,
|
||||
success integer not null,
|
||||
time float not null
|
||||
);
|
BIN
static/favicon.ico
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
static/img/asocial_metzwork_v1.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
static/img/corner_bottomleft.png
Normal file
After Width: | Height: | Size: 773 B |
BIN
static/img/corner_bottomright.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
static/img/corner_topleft.png
Normal file
After Width: | Height: | Size: 770 B |
BIN
static/img/corner_topright.png
Normal file
After Width: | Height: | Size: 754 B |
BIN
static/img/k6lqsh.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/img_red/asocial_metzwork_v1.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
static/img_red/corner_bottomleft.png
Normal file
After Width: | Height: | Size: 651 B |
BIN
static/img_red/corner_bottomright.png
Normal file
After Width: | Height: | Size: 405 B |
BIN
static/img_red/corner_topleft.png
Normal file
After Width: | Height: | Size: 412 B |
BIN
static/img_red/corner_topright.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
static/img_red/k6lqsh.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
188
static/style.css
Normal file
|
@ -0,0 +1,188 @@
|
|||
body {
|
||||
background: #3b5998;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-family: helvetica, sans;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
#body_bis {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 90%;
|
||||
max-width: 1300px;
|
||||
min-width: 550px;
|
||||
}
|
||||
|
||||
#banner {
|
||||
height: 101px;
|
||||
background: center center url('img/asocial_metzwork_v1.png') no-repeat;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
#content_container {
|
||||
margin-left: 200px;
|
||||
margin-right: 200px;
|
||||
position: relative;
|
||||
background: white;
|
||||
color: black;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#content_container div.corner {
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
background-repeat: no-repeat;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#content_topleft {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-image: url('img/corner_topleft.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#content_topright {
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
background-image: url('img/corner_topright.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#content_bottomleft {
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
background-image: url('img/corner_bottomleft.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
#content_bottomright {
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
background-image: url('img/corner_bottomright.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
#content {
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
/* Contenu */
|
||||
|
||||
#content h1 {
|
||||
margin-top: 5px;
|
||||
padding-left: 50px;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
#content h2, #content p {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#content h2 {
|
||||
margin-top:0px;
|
||||
font-size: 100%;
|
||||
margin-bottom: 5px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
#content p {
|
||||
text-indent: 2em;
|
||||
margin-top: 0px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
#content ul#history {
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
#content li.events {
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
#content li .normal {
|
||||
color: black;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#content li.ban {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#content li.warn {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#content li.ok {
|
||||
color: #1D1;
|
||||
}
|
||||
|
||||
#content_container #footer {
|
||||
margin-top: 4em;
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
p#play {
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin-top: 1.6em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
p#play a {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
background: #2E2;
|
||||
padding: .5em 2em;
|
||||
border: 1px solid #191;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
p#play a:hover {
|
||||
background: #191;
|
||||
}
|
||||
|
||||
form#select {
|
||||
width: 500px;
|
||||
margin: 1em auto;
|
||||
background: #FA0;
|
||||
border-radius: 1em;
|
||||
border: 1px solid #C70;
|
||||
padding: 1em 0em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.flashes {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
width: 90%;
|
||||
margin: .5em auto;
|
||||
}
|
||||
|
||||
ul.flashes li {
|
||||
background: #2E2;
|
||||
border: 1px solid #191;
|
||||
border-radius: .6em;
|
||||
margin-bottom: 1em;
|
||||
padding: .4em .7em;
|
||||
}
|
188
static/style_red.css
Normal file
|
@ -0,0 +1,188 @@
|
|||
body {
|
||||
background: #3b5998;
|
||||
color: red;
|
||||
text-align: center;
|
||||
font-family: helvetica, sans;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
#body_bis {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 90%;
|
||||
max-width: 1300px;
|
||||
min-width: 550px;
|
||||
}
|
||||
|
||||
#banner {
|
||||
height: 101px;
|
||||
background: center center url('img_red/asocial_metzwork_v1.png') no-repeat;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
#content_container {
|
||||
margin-left: 200px;
|
||||
margin-right: 200px;
|
||||
position: relative;
|
||||
background: red;
|
||||
color: white;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#content_container div.corner {
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
background-repeat: no-repeat;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#content_topleft {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-image: url('img_red/corner_topleft.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#content_topright {
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
background-image: url('img_red/corner_topright.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#content_bottomleft {
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
background-image: url('img_red/corner_bottomleft.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
#content_bottomright {
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
background-image: url('img_red/corner_bottomright.png');
|
||||
background-color: #3b5998;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
#content {
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
/* Contenu */
|
||||
|
||||
#content h1 {
|
||||
margin-top: 5px;
|
||||
padding-left: 50px;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
#content h2, #content p {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#content h2 {
|
||||
margin-top:0px;
|
||||
font-size: 100%;
|
||||
margin-bottom: 5px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
#content p {
|
||||
text-indent: 2em;
|
||||
margin-top: 0px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
#content ul#history {
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
#content li.events {
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
#content li .normal {
|
||||
color: black;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#content li.ban {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#content li.warn {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#content li.ok {
|
||||
color: #1D1;
|
||||
}
|
||||
|
||||
#content_container #footer {
|
||||
margin-top: 4em;
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
p#play {
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin-top: 1.6em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
p#play a {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
background: #2E2;
|
||||
padding: .5em 2em;
|
||||
border: 1px solid #191;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
p#play a:hover {
|
||||
background: #191;
|
||||
}
|
||||
|
||||
form#select {
|
||||
width: 500px;
|
||||
margin: 1em auto;
|
||||
background: #FA0;
|
||||
border-radius: 1em;
|
||||
border: 1px solid #C70;
|
||||
padding: 1em 0em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.flashes {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
width: 90%;
|
||||
margin: .5em auto;
|
||||
}
|
||||
|
||||
ul.flashes li {
|
||||
background: #2E2;
|
||||
border: 1px solid #191;
|
||||
border-radius: .6em;
|
||||
margin-bottom: 1em;
|
||||
padding: .4em .7em;
|
||||
}
|
16
templates/banned.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "layout_banned.html" %}
|
||||
{% block content %}
|
||||
<h1>Tu es tranché</h1>
|
||||
<p>
|
||||
{{ explanation }}
|
||||
</p>
|
||||
<p>
|
||||
Rétablissement de la connexion externe dans approximativement :
|
||||
</p>
|
||||
<p style="text-align: center">
|
||||
<strong>{{ timeleft }}</strong>.
|
||||
</p>
|
||||
<p>
|
||||
(redémarrer le navigateur peut être nécessaire une fois ce délai écoulé)
|
||||
</p>
|
||||
{% endblock %}
|
27
templates/home.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<h1>24 heures</h1>
|
||||
<h2>Toi aussi, joue au rézoman !</h2>
|
||||
<p>
|
||||
Jusqu'à samedi 11h, tu peux essayer de trancher tes
|
||||
camarades pour 30 min.
|
||||
</p>
|
||||
<p id="play" style="text-align: center; font-size: 1.5em">
|
||||
<a href="{{url_for('play')}}">Jouer</a>
|
||||
</p>
|
||||
<h2>Historique personnel</h2>
|
||||
|
||||
{% if bans_hist != [] %}
|
||||
<ul id="history">
|
||||
{% for entry in bans_hist %}
|
||||
<li class="{{ entry[0] }}" class="events">
|
||||
<span class="normal"> {{ entry[1] }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>
|
||||
Rien pour l'instant
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
27
templates/home.html~
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<h1>24 heures</h1>
|
||||
<h2>Toi aussi, joue au rézoman !</h2>
|
||||
<p>
|
||||
Jusqu'à mercredi 9h, tu peux essayer de trancher tes
|
||||
camarades pour 30 min.
|
||||
</p>
|
||||
<p id="play" style="text-align: center; font-size: 1.5em">
|
||||
<a href="{{url_for('play')}}">Jouer</a>
|
||||
</p>
|
||||
<h2>Historique personnel</h2>
|
||||
|
||||
{% if bans_hist != [] %}
|
||||
<ul id="history">
|
||||
{% for entry in bans_hist %}
|
||||
<li class="{{ entry[0] }}" class="events">
|
||||
<span class="normal"> {{ entry[1] }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>
|
||||
Rien pour l'instant
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
43
templates/layout.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>asocial metzwork - 24h</title>
|
||||
<meta http-equiv="content-type"
|
||||
content="text/html;charset=utf-8" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" />
|
||||
<link rel="shortcut icon" type="image/x-icon"
|
||||
href="{{ url_for('static', filename='favicon.ico') }}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="body_bis">
|
||||
<div id="banner">
|
||||
</div>
|
||||
|
||||
<div id="content_container">
|
||||
<div id="content_topleft" class="corner">
|
||||
</div>
|
||||
<div id="content_topright" class="corner">
|
||||
</div>
|
||||
<div id="content">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<ul class=flashes>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<div id="content_bottomleft" class="corner">
|
||||
</div>
|
||||
<div id="content_bottomright" class="corner">
|
||||
</div>
|
||||
<div id="footer">contact technique : goulven.kermarec@supelec.fr</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
44
templates/layout_banned.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>asocial metzwork - 24h</title>
|
||||
<meta http-equiv="content-type"
|
||||
content="text/html;charset=utf-8" />
|
||||
<meta http-equiv="refresh" content="20">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style_red.css') }}" />
|
||||
<link rel="shortcut icon" type="image/x-icon"
|
||||
href="{{ url_for('static', filename='favicon.ico') }}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="body_bis">
|
||||
<div id="banner">
|
||||
</div>
|
||||
|
||||
<div id="content_container">
|
||||
<div id="content_topleft" class="corner">
|
||||
</div>
|
||||
<div id="content_topright" class="corner">
|
||||
</div>
|
||||
<div id="content">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<ul class=flashes>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<div id="content_bottomleft" class="corner">
|
||||
</div>
|
||||
<div id="content_bottomright" class="corner">
|
||||
</div>
|
||||
<div id="footer">contact technique : goulven.kermarec@supelec.fr</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
15
templates/login.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<h1>Login</h1>
|
||||
{% if error %}<p class=error><strong>Error:</strong> {{ error }}{% endif %}
|
||||
<form action="{{ url_for('login') }}" method=post>
|
||||
|
||||
<dl>
|
||||
<dt>Identifiant :
|
||||
<dd><input type=text name=username>
|
||||
<dt>Mot de passe :
|
||||
<dd><input type=password name=password>
|
||||
<dd><input type=submit value=Login>
|
||||
</dl>
|
||||
</form>
|
||||
{% endblock %}
|
9
templates/not_subscribed.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<h1>Vous n'êtes pas inscrit</h1>
|
||||
<p>
|
||||
Si vous désirez participer malgré les risques que le jeu comporte, veuillez
|
||||
envoyer un email à goulven.kermarec@supelec.fr .
|
||||
(Vous ne pouvez pas jouer depuis Supélec)
|
||||
</p>
|
||||
{% endblock %}
|
9
templates/not_subscribed.html~
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<h1>Vous n'êtes pas inscrits</h1>
|
||||
<p>
|
||||
Si vous désirez participer malgré les risques que le jeu comporte, veuillez
|
||||
envoyer un email à goulven.kermarec@supelec.fr .
|
||||
(Vous ne pouvez pas jouer depuis Supélec)
|
||||
</p>
|
||||
{% endblock %}
|
23
templates/play.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<h1>24 heures</h1>
|
||||
<h2>Trancher un joueur</h2>
|
||||
<p>
|
||||
Ta cible sera notifiée quelle que soit l'issue de ta tentative. Question
|
||||
chance, c'est 50-50.
|
||||
</p>
|
||||
<form id="select" action="" method="post">
|
||||
<select name="target_id">
|
||||
<p><option value="none">(sélectionner un joueur)</option>
|
||||
{% for player in players %}
|
||||
<option value="{{ player.id }}">
|
||||
{{ "%s %s" % (player.firstname, player.name) }}
|
||||
</option></p>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="submit" value="Tchak !" />
|
||||
</form>
|
||||
<p>
|
||||
<a href="{{ url_for('home') }}">« retour à l'accueil</a>
|
||||
</p>
|
||||
{% endblock %}
|