From 7b4f994b4ae69b966ce5f2bab3d5a4ea604c902b Mon Sep 17 00:00:00 2001 From: gavvahar Date: Mon, 16 Jun 2025 23:25:34 -0400 Subject: [PATCH 1/4] updating package version to work with python 3.12 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5807839..cad2e52 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ dnspython==1.16.0 eventlet==0.30.1 Flask==1.1.2 Flask-SocketIO==5.0.1 -greenlet==1.0.0 +greenlet itsdangerous==1.1.0 Jinja2==2.11.3 MarkupSafe==1.1.1 From d67ac6645b4ea7acaab714174a1ac12c69366ddf Mon Sep 17 00:00:00 2001 From: gavvahar Date: Mon, 16 Jun 2025 23:27:54 -0400 Subject: [PATCH 2/4] updating import since clock has been removed since python 3.8 --- clonenames.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clonenames.py b/clonenames.py index 28a2db6..7e2d42a 100644 --- a/clonenames.py +++ b/clonenames.py @@ -14,7 +14,7 @@ class Board(object): """docstring for Board""" def __init__(self, wordlist: str = u'codenames') -> None: # self.wordlist = wordlist - with open(u'wordlists/{wordlist}'.format(wordlist = wordlist), u'r') as text_file: + with open(u'wordlists/{wordlist}'.format(wordlist=wordlist), u'r') as text_file: self.source = [line for line in text_file.read().split(u'\n') if line != u''] def load_settings(self, teams: int = 2, size: int = 25) -> bool: @@ -48,8 +48,8 @@ def check_size(self, size: int) -> None: self.length = int(self.size ** 0.5) def load_words(self) -> None: - from time import clock - random.seed(clock()) + from time import perf_counter + random.seed(perf_counter()) self.COLORS = [u'red', u'blue', u'green', u'yellow'] random.shuffle(self.COLORS) From 087a8d6413fac7811a66146906eab2b446beed18 Mon Sep 17 00:00:00 2001 From: gavvahar Date: Wed, 18 Jun 2025 15:32:21 -0400 Subject: [PATCH 3/4] add .lh to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f8c1b9b..41aeb85 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ dmypy.json # Pyre type checker .pyre/ +.lh From 31371cd38dceb575902e9cca984c257cbc12be4f Mon Sep 17 00:00:00 2001 From: gavvahar Date: Wed, 18 Jun 2025 15:32:32 -0400 Subject: [PATCH 4/4] add Dockerfile, docker-compose.yml, and .dockerignore; refactor web.py for consistency --- .dockerignore | 10 ++++ Dockerfile | 21 +++++++ docker-compose.yml | 10 ++++ web.py | 135 ++++++++++++++++++++++++--------------------- 4 files changed, 112 insertions(+), 64 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a90a99f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +env/ +venv/ +.git +.gitignore +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..41cc008 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.12-slim + + +# Upgrade pip and system packages to reduce vulnerabilities +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --no-install-recommends gcc build-essential && \ + python3 -m pip install --upgrade pip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY requirements.txt ./ +RUN python3 -m pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 5000 + +CMD ["python3", "web.py"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..eff589f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3.12" + +services: + clonenames: + build: . + ports: + - "5000:5000" + environment: + - PYTHONUNBUFFERED=1 + restart: unless-stopped diff --git a/web.py b/web.py index 5c4bded..b432cad 100644 --- a/web.py +++ b/web.py @@ -21,77 +21,80 @@ games = dict() -@app.route(u'/') +@app.route("/") def home_page(): - return render_template(u'index.html') + return render_template("index.html") -@app.route(u'/start', methods = [u'GET', u'POST']) +@app.route("/start", methods=["GET", "POST"]) def start_page(): - if request.method == u'POST': - game = clonenames.Board(request.form.get(u'words')) + if request.method == "POST": + game = clonenames.Board(request.form.get("words")) success = game.load_settings( - teams = int(request.form.get(u'number')), - size = int(request.form.get(u'size'))) + teams=int(request.form.get("number")), size=int(request.form.get("size")) + ) if success: room = generate_room_code() games[room] = game - return redirect(url_for(u'game_page', room = room)) + return redirect(url_for("game_page", room=room)) else: return render_template( - u'start.html', - words = clonenames.wordlists, - alert = u'The word list selected must be played on a smaller game board... Sorry!') + "start.html", + words=clonenames.wordlists, + alert="The word list selected must be played on a smaller game board... Sorry!", + ) - elif request.method == u'GET': - return render_template(u'start.html', words = clonenames.wordlists) + elif request.method == "GET": + return render_template("start.html", words=clonenames.wordlists) -@app.route(u'/game', methods = [u'GET', u'POST']) +@app.route("/game", methods=["GET", "POST"]) def game_page(): - if request.args.get(u'room'): - room = request.args.get(u'room') + if request.args.get("room"): + room = request.args.get("room") return render_template( - u'game.html', - show_input = False, - room = room, - host = True, - words = games[room].table(), - start = games[room].order[0], - remnants = games[room].remnants) + "game.html", + show_input=False, + room=room, + host=True, + words=games[room].table(), + start=games[room].order[0], + remnants=games[room].remnants, + ) else: try: - if request.method == u'GET': - return render_template( - u'game.html', - show_input = True) + if request.method == "GET": + return render_template("game.html", show_input=True) - elif request.method == u'POST': - room = request.form.get(u'room', False).upper() + elif request.method == "POST": + room = request.form.get("room", False).upper() if check_room_code(room): return render_template( - u'game.html', - show_input = False, - room = room, - host = request.form.get(u'host', False) == u'on', - words = games[room].table(), - start = games[room].order[0], - remnants = games[room].remnants) + "game.html", + show_input=False, + room=room, + host=request.form.get("host", False) == "on", + words=games[room].table(), + start=games[room].order[0], + remnants=games[room].remnants, + ) else: return render_template( - u'game.html', - show_input = True, - alert = u'The room code you entered does not exist. Please try again!') + "game.html", + show_input=True, + alert="The room code you entered does not exist. Please try again!", + ) except AttributeError: - return redirect(url_for(u'home_page')) + return redirect(url_for("home_page")) + # @app.route(u'/statistics') # def stats_page(): @@ -99,38 +102,42 @@ def game_page(): # rooms = [games[game].statistics() for game in games]) -@socketio.on(u'join') +@socketio.on("join") def join(data): - join_room(data[u'room']) + join_room(data["room"]) -@socketio.on(u'clicked') +@socketio.on("clicked") def handle_host_click(json): - response = games[json[u'room']].get(json[u'id']) - socketio.emit(u'revealed', { - u'text': u'Host clicked on {word}'.format( - word = response[u'word']), - u'id': u'#{id}'.format(id = json[u'id']), - u'remnant': response[u'remnant'], - u'class': u'btn-{team}'.format( - team = response[u'team'])}, room = json['room']) - - -@socketio.on(u'ended_turn') + response = games[json["room"]].get(json["id"]) + socketio.emit( + "revealed", + { + "text": "Host clicked on {word}".format(word=response["word"]), + "id": "#{id}".format(id=json["id"]), + "remnant": response["remnant"], + "class": "btn-{team}".format(team=response["team"]), + }, + room=json["room"], + ) + + +@socketio.on("ended_turn") def handle_end_turn(json): - team = games[json[u'room']].advance_turn() + team = games[json["room"]].advance_turn() - alert = u'alert {team}-start alert-start'.format(team = team) - button = u'btn btn-{team} float-right'.format(team = team) + alert = "alert {team}-start alert-start".format(team=team) + button = "btn btn-{team} float-right".format(team=team) - socketio.emit(u'change_turn', { - u'alert': alert, - u'text': team, - u'button': button}, room = json[u'room']) + socketio.emit( + "change_turn", + {"alert": alert, "text": team, "button": button}, + room=json["room"], + ) def generate_room_code(): - letters = u''.join(random.sample(list(u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 5)) + letters = "".join(random.sample(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 5)) while letters in games.keys(): return generate_room_code() @@ -141,5 +148,5 @@ def check_room_code(code): return code in games.keys() -if __name__ == '__main__': - socketio.run(app, debug=True, host=u'0.0.0.0') +if __name__ == "__main__": + socketio.run(app, debug=False, host="0.0.0.0")