2 many templates

This commit is contained in:
EvilMuffinHa 2020-10-14 11:04:30 -04:00
parent 06b86d706e
commit 00cc143d6e
20 changed files with 542 additions and 123 deletions

2
.gitignore vendored
View File

@ -133,5 +133,5 @@ dmypy.json
# jetbrains folder
.idea/
qbBuzzer.iml
.env
test/

View File

@ -2,43 +2,38 @@ from flask import *
from random import randint as rint
from src.config import Config
from src.host import HostForm
from src.sec import gencode, dohash
from src.join import JoinForm
from src.sec import gencode, dohash, whitelist
from logging.config import dictConfig
import logging
from flask_socketio import SocketIO
from flask_socketio import SocketIO, emit, join_room, leave_room
import json
dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'handlers': {'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
}},
'root': {
'level': 'INFO',
'handlers': ['wsgi']
}
})
# Loading logging preferences
with open("logger.json", "r") as f:
dconf = json.load(f)
# Establishing logger
dictConfig(dconf)
# Loading flask app
app = Flask(__name__)
app.logger.info("Flask app loaded at " + __name__)
app.config.from_object(Config)
app.logger.setLevel(logging.DEBUG)
# Version allows css / js to load instead of taking hours to update even on run smh
version = rint(0, 300000000)
# games
games = {}
# home
@app.route('/')
def home():
return render_template('index.html', version=str(version))
# creating a room for players to join
@app.route("/host", methods=["GET", "POST"])
def host():
form = HostForm()
@ -46,7 +41,7 @@ def host():
hostcode = gencode(64)
hash = dohash(hostcode)
resp = redirect(url_for("play", hash=hash))
resp.set_cookie("_gid", str(hostcode), httponly=True, secure=True)
resp.set_cookie("_gid", str(hostcode))
with open("src/templates/games.json", "r") as f:
tmp = json.load(f)
games[hash] = tmp
@ -55,7 +50,6 @@ def host():
games[hash]["bonus"] = form.bonus.data
games[hash]["power"] = form.power.data
games[hash]["negs"] = form.negs.data
games[hash]["teams"] = form.teams.data
app.logger.debug("Game host at %s", hostcode)
app.logger.info("Game created at %s", hash)
return resp
@ -63,32 +57,136 @@ def host():
return render_template('host.html', title="Host Game", version=str(version), form=form, default=default)
# Inside the room itself
@app.route("/play/<hash>")
def play(hash):
if hash in games.keys():
return render_template('play.html', version=str(version))
if dohash(request.cookies.get('_gid')) == hash:
return render_template('gamehost.html', version=str(version), gamecode=hash)
else:
if "name" in request.cookies:
name = request.cookies.get("name")
return render_template('play.html', version=str(version), gamecode=hash, username=name)
else:
return render_template('please.html', version=str(version))
else:
abort(404)
@app.route("/join")
@app.route("/kick")
def kick():
return render_template('kick.html', version=str(version))
# When players attempt to join a room
@app.route("/join", methods=["GET", "POST"])
def join():
return "In progress!"
form = JoinForm()
if form.validate_on_submit():
wlist = whitelist()
if not all([a in wlist for a in form.name.data]):
return render_template('badname.html', title='Join Game', version=str(version))
hash = form.roomcode.data
if hash in games.keys():
if form.name.data in games[hash]["players"].keys():
return render_template('nametaken.html', title='Join Game', version=str(version))
games[hash]["players"][form.name.data] = 0
resp = redirect(url_for("play", hash=hash))
resp.set_cookie("_gid", "")
resp.set_cookie("name", form.name.data)
return resp
else:
return render_template('gamenotfound.html', title="Join Game", version=str(version))
return render_template('join.html', title="Join Game", version=str(version), form=form)
# If someone visits somethin stupid
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
# Connecting socketio for all socketio functions below
socketio = SocketIO(app)
# |
# V
@socketio.on('json')
def handle_json(json):
print('received message: ' + str(json))
emit('json', json)
# Checks when a player / host joins the room
@socketio.on('join')
def on_join(data):
room = data['room']
username = ""
if "username" in data.keys():
username = data['username']
else:
gid = data["_gid"]
if dohash(gid) == room:
username = "host"
join_room(str(room))
emit('player_join_event', games[room]["players"], room=room)
# When the host sends data to server
@socketio.on('host')
def host_msg(data):
room = data["room"]
gid = data["_gid"]
if dohash(gid) != room: # Check if the host is really the host
return
msg = data["data"]
if "lock" in msg.keys():
pass # lock buzzers
elif "kick" in msg.keys():
msg["url"] = url_for('kick')
username = msg["kick"]
del games[room]["players"][username]
emit("player_kick_event", msg, room=room)
elif "tossup" in msg.keys():
pass # give player points
elif "bonus" in msg.keys():
pass # give player points
elif "power" in msg.keys():
pass # give player points
elif "negs" in msg.keys():
pass # give player points
elif "amount" in msg.keys():
pass # give player points
# When the player buzzes
@socketio.on('buzz')
def buzz(data):
room = data["room"]
emit("buzz", data, room=room) # Just send it back
# When a player / host leaves
@socketio.on('leave')
def on_leave(data):
print("player leave")
room = data['room']
username = ""
if "username" in data.keys():
username = data['username']
else:
gid = data["_gid"]
if dohash(gid) == room:
username = "host"
del games[room]["players"][username]
leave_room(room)
emit('player_leave_event', {"player": username}, room=room)
# Run the thing lol
if __name__ == "__main__":
socketio.run(app)
socketio.run(app, host="0.0.0.0", port=25565)
# app.run(host="127.0.0.1", port=25565)

View File

@ -1,10 +1,9 @@
from flask_wtf import FlaskForm
from wtforms import IntegerField, SubmitField, BooleanField
from wtforms import IntegerField, SubmitField
from wtforms.validators import DataRequired
class HostForm(FlaskForm):
tossup = IntegerField('Tossup Points', validators=[DataRequired()])
bonus = IntegerField('Bonus Points', validators=[DataRequired()])
power = IntegerField('Power Points', validators=[DataRequired()])
negs = IntegerField('Neg Points [Positive]', validators=[DataRequired()])
teams = BooleanField('Teams? ')
create = SubmitField('Create Room')

View File

@ -1,6 +1,7 @@
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, BooleanField
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class JoinForm(FlaskForm):
roomcode = StringField('Room Code', validators=[DataRequired()])
name = StringField('Name', validators=[DataRequired()])
create = SubmitField('Join Room')

15
src/logger.json Normal file
View File

@ -0,0 +1,15 @@
{
"version": 1,
"formatters": {"default": {
"format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s"
}},
"handlers": {"wsgi": {
"class": "logging.StreamHandler",
"stream": "ext://flask.logging.wsgi_errors_stream",
"formatter": "default"
}},
"root": {
"level": "DEBUG",
"handlers": ["wsgi"]
}
}

View File

@ -20,6 +20,10 @@ def sha3256(val):
return ho.digest()
def whitelist():
return list(ascii_letters + digits)
def hexdigest(val):
return hexlify(val).decode('utf-8')

BIN
src/static/buzz.mp3 Normal file

Binary file not shown.

View File

@ -1,7 +1,74 @@
var socket = io();
test = function() {
console.log("h");
socket.emit('json', {data: 'I\'m connected!'});
code = document.getElementById("code").value;
name = document.getElementById("name").value;
kickurl = document.getElementById("kick").value;
function removeAllChildren(e) {
var child = e.lastElementChild;
while (child) {
e.removeChild(child);
child = e.lastElementChild;
}
}
socket.on("connect", function() {
// when client first connects to a game
socket.emit("join", {"username": name, "room": code, "_gid": ""});
})
socket.on("player_join_event", function(data) {
div = document.getElementById("sidebar");
removeAllChildren(div);
if (Object.keys(data).length == 0) {
var keepSidebarOpen = document.createElement("input");
keepSidebarOpen.setAttribute("type", "hidden");
div.appendChild(keepSidebarOpen);
return
}
var keys = Object.keys(data);
for (var key in keys) {
var playerDisplay = document.createElement("div");
playerDisplay.setAttribute("id", keys[key]);
playerDisplay.setAttribute("class", "playertag");
var playerLink = document.createElement("p");
playerLink.appendChild(document.createTextNode(keys[key]));
playerDisplay.appendChild(playerLink);
playerDisplay.appendChild(document.createElement("br"));
div.appendChild(playerDisplay);
}
});
socket.on("player_leave_event", function(data) {
var element = document.getElementById(data["player"]);
element.parentNode.removeChild(element);
});
socket.on("player_kick_event", function(data) {
if (data["kick"] == name) {
window.location = kickurl;
} else {
var element = document.getElementById(data["kick"]);
element.parentNode.removeChild(element);
}
})
function buzz() {
// when client hits buzz
socket.emit("buzz", {"username": name, "room": code, "_gid": ""});
}
$(document).on('keypress', function(e) {
if (e.key === ' ' || e.key === 'Spacebar') {
e.preventDefault();
buzz();
}
})
window.onbeforeunload = function leave() {
// when client leaves
console.log("leave")
socket.emit("leave", {"username": name, "room": code, "_gid": ""});
}
// div id = game (that's where the game goes)

90
src/static/host.js Normal file
View File

@ -0,0 +1,90 @@
var socket = io();
code = document.getElementById("copycode").value;
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
gid = readCookie("_gid");
copycode = function() {
var copyText = document.getElementById("copycode")
copyText.select();
copyText.setSelectionRange(0, 99999);
document.execCommand("copy")
}
function send(data) {
socket.emit("host", {"room": code, "_gid": gid, "data": data});
}
function removeAllChildren(e) {
var child = e.lastElementChild;
while (child) {
e.removeChild(child);
child = e.lastElementChild;
}
}
socket.on("connect", function() {
socket.emit("join", {"room": code, "_gid": gid});
});
window.onbeforeunload = function leave() {
socket.emit("leave", {"room": code, "_gid": gid});
}
socket.on("player_join_event", function(data) {
div = document.getElementById("sidebar");
removeAllChildren(div);
if (Object.keys(data).length == 0) {
var keepSidebarOpen = document.createElement("input");
keepSidebarOpen.setAttribute("type", "hidden");
div.appendChild(keepSidebarOpen);
return
}
var keys = Object.keys(data);
for (var key in keys) {
var playerDisplay = document.createElement("div");
playerDisplay.setAttribute("id", keys[key]);
playerDisplay.setAttribute("class", "playertag");
var playerLink = document.createElement("p");
playerLink.appendChild(document.createTextNode(keys[key]));
var removeLink = document.createElement("a");
removeLink.setAttribute("onclick", "removePlayer('" + keys[key] + "');");
removeLink.appendChild(document.createTextNode("Kick"));
playerDisplay.appendChild(playerLink);
playerDisplay.appendChild(removeLink);
playerDisplay.appendChild(document.createElement("br"));
div.appendChild(playerDisplay);
}
});
socket.on("player_leave_event", function(data) {
var element = document.getElementById(data["player"]);
element.parentNode.removeChild(element);
});
socket.on("player_kick_event", function(data) {
var element = document.getElementById(data["kick"]);
element.parentNode.removeChild(element);
})
function removePlayer(playername) {
send({"kick": playername});
}
socket.on("buzz", function(message) {
var audio = new Audio('/static/buzz.mp3');
audio.play();
})

View File

@ -92,6 +92,63 @@ body {
margin-left: 5px;
}
.copycode {
text-align: center;
}
.form {
text-align: center;
}
.form input {
text-align: center;
}
.sidebar {
height: 100%; /* Full-height: remove this if you want "auto" height */
font-size: 25px;
position: fixed; /* Fixed Sidebar (stay in place on scroll) */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
left: 0;
background-color: #e2e27c;
padding-top: 20px;
padding-left: 10px;
padding-right: 20px;
}
/* The navigation menu links */
.sidebar a {
padding: 6px 8px 6px 8px;
text-decoration: none;
font-size: 14px;
color: #ea2a2d;
display: inline;
}
.sidebar p {
padding: 6px 8px 6px 6px;
text-decoration: none;
font-size: 25px;
color: #818181;
display: inline;
}
/* When you mouse over the navigation links, change their color */
.sidebar a:hover {
color: #f1f1f1;
}
/* Style page content */
.game {
padding: 0px 10px;
}
/* On smaller screens, where height is less than 450px, change the style of the sidebar (less padding and a smaller font size) */
@media screen and (max-height: 450px) {
.sidebar {padding-top: 15px;}
.sidebar a {font-size: 18px;}
}
@font-face {
font-family: 'Abberancy-Regular';

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block content %}
<div class="button top">
<a href="{{ url_for('join') }}">Back</a>
</div>
<div class="title">
<h1> Bad Name </h1>
</div>
<div class="text">
<center>
<p>Names can only be alphanumeric. </p>
</center>
</div>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block content %}
<div class="subttl">
<h1> Game! </h1>
</div>
<div class="sidebar" id="sidebar">
</div>
<div id="join">
<center>
<p>Click to copy the game code: </p>
<input id="copycode" class="copycode" name="copycode" value="{{ gamecode }}" type="text" size="32" readonly onclick="copycode();"/>
</center>
</div>
<div id="game">
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script src="/static/host.js?version={{ version }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<div class="button top">
<a href="{{ url_for('join') }}">Back</a>
</div>
<div class="title">
<h1> Game not found </h1>
</div>
{% endblock %}

View File

@ -4,5 +4,6 @@
"bonus": 20,
"power": 15,
"negs": 5,
"teams": false
"teams": false,
"players": {}
}

View File

@ -7,10 +7,11 @@
<div class="subttl">
<h1> Host Game </h1>
</div>
<div class="form host">
<form action="" method="post" novalidate>
{{ form.csrf_token }}
{{ form.hidden_tag() }}
<p>
<center>
{{ form.tossup.label }}<br>
{{ form.tossup(size=32, value=default[0]) }}<br>
{% for error in form.tossup.errors %}
@ -35,13 +36,10 @@
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.teams() }} {{ form.teams.label }}<br>
{% for error in form.negs.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.create() }}
<br>
</center>
</p>
</form>
</div>
{% endblock %}

View File

@ -5,43 +5,26 @@
<a href="{{ url_for('home') }}">Back</a>
</div>
<div class="subttl">
<h1> Host Game </h1>
<h1> Join Game </h1>
</div>
<div class="form join">
<form action="" method="post" novalidate>
{{ form.csrf_token }}
{{ form.hidden_tag() }}
<p>
{{ form.tossup.label }}<br>
{{ form.tossup(size=32, value=default[0]) }}<br>
{% for error in form.tossup.errors %}
<p><center>
{{ form.roomcode.label }}<br>
{{ form.roomcode(size=32) }}<br>
{% for error in form.roomcode.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.bonus.label }}<br>
{{ form.bonus(size=32, value=default[1]) }}<br>
{% for error in form.bonus.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.power.label }}<br>
{{ form.power(size=32, value=default[2]) }}<br>
{% for error in form.power.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.negs.label }}<br>
{{ form.negs(size=32, value=default[3]) }}<br>
{% for error in form.negs.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.teams() }} {{ form.teams.label }}<br>
{% for error in form.negs.errors %}
{{ form.name.label }}<br>
{{ form.name(size=32) }}<br>
{% for error in form.name.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
<br>
{{ form.create() }}
<br>
</p>
<br> </center></p>
</form>
</div>
{% endblock %}

10
src/templates/kick.html Normal file
View File

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<div class="button top">
<a href="{{ url_for('join') }}">Back</a>
</div>
<div class="subttl">
<p>You have been kicked. </p>
</div>
{% endblock %}

View File

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<div class="button top">
<a href="{{ url_for('join') }}">Back</a>
</div>
<div class="subttl">
<p>Name is already taken.</p>
</div>
{% endblock %}

View File

@ -1,9 +1,42 @@
{% extends "base.html" %}
<!DOCTYPE html>
<html lang="en">
{% if title %}
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/static/index.css?version={{ version }}">
<title>{{ title }} - Buzzer! </title>
</head>
{% else %}
<head>
<title> Buzzer! </title>
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/static/index.css?version={{ version }}">
</head>
{% endif %}
<body class="wrap">
<div class="subttl">
<h1> Play! </h1>
</div>
{% block content %}
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script src="/static/game.js" type="text/javascript" charset="utf-8"></script>
<br><input type="hidden" id="code" name="code" value="{{ gamecode }}"><br>
<br><input type="hidden" id="name" name="name" value="{{ username }}">
<br><input type="hidden" id="kick" name="kick" value="{{ url_for('kick') }}">
<div class="sidebar" id="sidebar">
</div>
<div id="game">
<center>
<div class="form name">
</div>
{% endblock %}
<div class="button buzzer">
<a onclick="buzz();">BUZZ! [SPACE]</a>
</div>
</center>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script src="/static/game.js?version={{ version }}" type="text/javascript" charset="utf-8"></script>
</body>
</html>

View File

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<div class="button top">
<a href="{{ url_for('join') }}">Back</a>
</div>
<div class="title">
<h1> Please join using the Join page. </h1>
</div>
{% endblock %}