Skip to content

Commit

Permalink
Merge pull request #28 from jrsmth/feature/ui-revamp/main
Browse files Browse the repository at this point in the history
Feature/UI revamp/main
  • Loading branch information
jrsmth authored Dec 2, 2023
2 parents d5c46dd + 1569bc9 commit eb47513
Show file tree
Hide file tree
Showing 57 changed files with 1,984 additions and 393 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
# Releases
<!-- @LatestFirst -->

## [0.6.0] - 02/12/23
- UMA-37: Create star field background
- UMA-38: Restyle login screen
- UMA-39: Restyle game screen

## [0.5.3] - 28/11/23
- UMA-33: Allow for parallel games through game-specific websocket channels

Expand Down Expand Up @@ -95,4 +100,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[0.5.0]: https://github.com/jrsmth/ultima/compare/0.4.1...0.5.0
[0.5.1]: https://github.com/jrsmth/ultima/compare/0.5.0...0.5.1
[0.5.2]: https://github.com/jrsmth/ultima/compare/0.5.1...0.5.2
[0.5.3]: https://github.com/jrsmth/ultima/compare/0.5.2...0.5.3
[0.5.3]: https://github.com/jrsmth/ultima/compare/0.5.2...0.5.3
[0.6.0]: https://github.com/jrsmth/ultima/compare/0.5.3...0.6.0
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![python](https://img.shields.io/badge/Python-3.9-3776AB.svg?style=flat&logo=python&logoColor=white)](https://www.python.org)
[![test-and-release](https://github.com/jrsmth/ultima/actions/workflows/main.yaml/badge.svg)](https://github.com/jrsmth/ultima/actions/workflows/main.yaml)

# <img src="https://github.com/jrsmth/ultima/assets/34093915/b67d641d-1963-48cd-b110-b13e6d3537d8" width="28" alt="Logo"> Ultima
# <img src="./src/resources/static/img/badge.png" width="28" alt="Logo"> Ultima
<!-- TODO :: Private repo whilst under development, publicise upon submission -->
[ultima.jrsmth.io](https://ultima.jrsmth.io)

Expand Down
28 changes: 28 additions & 0 deletions src/app/admin/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from flask import Blueprint, Response, current_app
from werkzeug.security import generate_password_hash, check_password_hash


# Admin Logic
def construct_blueprint(auth, redis):
admin_page = Blueprint('admin_page', __name__)
username = current_app.config["USERNAME"]
password = current_app.config["PASSWORD"]

users = {
username: generate_password_hash(password),
}

@auth.verify_password
def verify_password(user, pwd):
if user in users and check_password_hash(users.get(user), pwd):
return user

@admin_page.route("/flood")
@auth.login_required
def destroy_all_games():
print("[destroy_all_games] Request to wipe data requested by: " + auth.current_user())
redis.clear()
return Response(status=204, response="The flood is over, Noah")

# Blueprint return
return admin_page
Empty file added src/app/admin/admin.test.py
Empty file.
18 changes: 14 additions & 4 deletions src/app/app.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import os

from flask import Flask
from flask_httpauth import HTTPBasicAuth
from flask_socketio import SocketIO

from src.app.admin import admin
from src.app.config.config import Config, DevConfig, ProductionConfig
from src.app.game import game
from src.app.login import login
from src.app.socket import socket
from src.app.util.messages import Messages
from src.app.util.redis import Redis


# Initialise app
templates = os.path.abspath("../resources/templates")
statics = "../resources/static"
app = Flask(__name__, template_folder=templates, static_folder=statics)
socketio = SocketIO(app)
auth = HTTPBasicAuth()


# Initialise config
env = os.environ.get("FLASK_ENV")
Expand All @@ -28,20 +31,27 @@
elif env == "prod":
app.config.from_object(ProductionConfig())
print(f"Starting app in [{env}] mode")
app.app_context().push()


# Initialise redis client
redis = Redis(app)


# Initialise message bundle
messages = Messages('../resources/messages.properties')


# Register routes
app.register_blueprint(login.construct_blueprint(messages, socketio, redis))
app.register_blueprint(game.construct_blueprint(messages, socketio, redis))
app.register_blueprint(admin.construct_blueprint(auth, redis))
app.register_blueprint(login.construct_blueprint(messages, redis))
app.register_blueprint(game.construct_blueprint(messages, redis, socketio))


# Register events
app.register_blueprint(socket.construct_blueprint(socketio))


# Let's go!
if __name__ == "__main__":
socketio.run(app, debug=True, host='localhost', port=8080) # FixMe :: extract
3 changes: 3 additions & 0 deletions src/app/config/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
class Config(object):
APP_URL = "http://localhost:8080"
REDIS_URL = "redis://@localhost:6379/0"
USERNAME = "noah"
PASSWORD = "ark"
# Note :: Security risk - ideally would store creds as env-var in some sort of trust store and inject at runtime


class DevConfig(Config):
Expand Down
4 changes: 1 addition & 3 deletions src/app/game/game.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import json
import random

from flask import render_template, Blueprint, Response, current_app

from src.app.model.board.board import map_to_symbol
from src.app.model.board.threeboard import ThreeBoard
from src.app.model.combos import get_wins
Expand All @@ -16,7 +14,7 @@


# Game Logic
def construct_blueprint(messages, socket, redis):
def construct_blueprint(messages, redis, socket):
game_page = Blueprint('game_page', __name__)

@game_page.route("/game/<game_id>/<user_id>")
Expand Down
35 changes: 28 additions & 7 deletions src/app/login/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


# Login Logic
def construct_blueprint(messages, socket, redis):
def construct_blueprint(messages, redis):
login_page = Blueprint('login_page', __name__)

@login_page.route('/', methods=['GET', 'POST'])
Expand Down Expand Up @@ -35,23 +35,44 @@ def login():
return redirect(url_for("game_page.game", game_id=game_id, user_id=user_id))

elif has_valid_game_id(request.form["gameId"]):
game = redis.get_complex(game_id)
print("Testing playMode [" + request.form["playerMode"] + "]")
if redis.get("playerMode") == "SINGLE":
if game["player_mode"] == "SINGLE":
print("Player Mode set to [SINGLE] for game id [" + redis.get("playerMode") + "]")
error = messages.load("login.error.single-player-only")

else:
game = redis.get_complex(game_id)
game['player_two']['name'] = request.form["name"] # TODO :: marshal dict into Game obj
game['player_two']['name'] = request.form["name"]
print("[login] Setting game object: " + str(game))
# print("[login] Setting game object: " + game.to_string())
redis.set_complex(game_id, game)
return redirect(url_for("game_page.game", game_id=game_id, user_id=user_id))

else:
error = messages.load("login.error.invalid-game-id")

return render_template("login.html", error=error)
return render_template("login.html", error=error, games=get_game_info(redis))

# Blueprint return
return login_page


def get_game_info(redis):
game_info = []
for key in redis.get_client().scan_iter():
game = redis.get_complex(key)
print("[get_game_info] Found game: " + str(game)) # TRACE
game_id = game["game_id"]
owner = ''
player_two = ''
try:
owner = game["player_one"]["name"]
except KeyError:
print("[get_game_info] No owner found for game with id: " + str(game_id)) # TRACE
try:
player_two = game["player_two"]["name"]
except KeyError:
print("[get_game_info] No second player found for game with id: " + str(game_id)) # TRACE
if player_two == '':
game_info.append((game_id, owner))

print("[get_game_info] Available games: " + str(game_info))
return game_info
3 changes: 2 additions & 1 deletion src/app/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ zipp~=3.17.0
gevent
flask_socketio
shortuuid
jsons
jsons
Flask-HTTPAuth
8 changes: 8 additions & 0 deletions src/app/util/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Redis:
def __init__(self, app):
self.client = FlaskRedis(app)

def get_client(self):
return self.client

# Get an element by its key and decode in utf-8 format
def get(self, key):
return self.client.get(key).decode('utf-8')
Expand All @@ -31,6 +34,11 @@ def get_complex(self, key):
except JSONDecodeError:
raise Exception("[get_complex] Error parsing retrieved object: " + str(json_value))

# Remove all entries held in Redis
def clear(self):
for key in self.client.scan_iter():
self.client.delete(key)


# Standardises a JSON string for conversion into a python dict
def standardise(value): # FixMe :: bit dodgy
Expand Down
Binary file modified src/resources/static/favicon/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/resources/static/favicon/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/resources/static/favicon/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/resources/static/favicon/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/resources/static/favicon/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/resources/static/favicon/favicon.ico
Binary file not shown.
Binary file modified src/resources/static/img/badge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/resources/static/img/logo-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/resources/static/img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions src/resources/static/scripts/dropdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//Multiple options dropdown
//https://codepen.io/gatoledo1/pen/QWmpWjK

const optionMenu = document.querySelector(".game-dropdown"),
selectBtn = optionMenu.querySelector(".select-btn"),
options = optionMenu.querySelectorAll(".option"),
sBtn_text = optionMenu.querySelector(".select-btn-text");

selectBtn.addEventListener("click", () =>
optionMenu.classList.toggle("active")
);

options.forEach((option) => {
option.addEventListener("click", () => {
selectBtn.classList.remove("touched")
const newOption = option.querySelector(".option-text").innerText;
const radio = $('.radio');
let gameId;

if (newOption === 'New Game') {
radio.removeClass("hide");
gameId = '';
} else {
radio.addClass("hide");
gameId = newOption;
}

$('#game-id')[0].value = gameId;
sBtn_text.innerText = newOption;

optionMenu.classList.remove("active");
selectBtn.classList.add("touched")
});
});
14 changes: 14 additions & 0 deletions src/resources/static/scripts/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ async function init(gameId) {
if (gameState['game_mode'] === "standard") initStandardBoard(userId, thisPlayer['symbol'], gameState['board']);
if (gameState['game_mode'] === "ultimate") initUltimateBoard(userId, thisPlayer['symbol'], gameState['board']);

toggleGameLoad(false);
}

function initUserInfo(thisPlayer) {
Expand Down Expand Up @@ -268,4 +269,17 @@ function allowedToPlace(outer, inner) {
gameState['board'][outer] !== 0 :
gameState['board'][outer][inner] !== 0;
return gameStarted && gameIncomplete && isUserTurn() && !alreadyPlayed;
}

function toggleGameLoad(loading) {
const mainBar = $('.main-bar')[0];
const gameLoader = $('#game-loader')[0];

if (loading) {
gameLoader.style.display = 'block';
mainBar.style.display = 'none';
} else {
gameLoader.style.display = 'none';
mainBar.style.display = 'block';
}
}
19 changes: 19 additions & 0 deletions src/resources/static/scripts/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,22 @@ $(document).ready(function() {

});

function login() {
if ($('#player-name')[0].value === '' ||
$('#game-id')[0].value === '-1') return;

const delay = 500;
setVelocity(1);
setDensity(10000);
setBrightness(10);
makeStars();

$('#login-button')[0].style.display = 'none';
$('#login-loader')[0].style.display = 'block';

setTimeout(() => {
$('#login-form')[0].submit();
}, delay);

}

Loading

0 comments on commit eb47513

Please sign in to comment.