add: game history
This commit is contained in:
parent
90ce697a3a
commit
d8e767405a
15
frontend/static/css/gameHistory.css
Normal file
15
frontend/static/css/gameHistory.css
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#game-list {
|
||||||
|
justify-content: flex-start;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#game-list .game-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 160px;
|
||||||
|
width: 160px;
|
||||||
|
margin: 10px;
|
||||||
|
border-radius: 5%;
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { Client } from "./Client.js";
|
import { Client } from "./Client.js";
|
||||||
|
import { Game } from "./game/Game.js";
|
||||||
|
|
||||||
class Profile
|
class Profile
|
||||||
{
|
{
|
||||||
@ -59,6 +60,36 @@ class Profile
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {[Game]}
|
||||||
|
*/
|
||||||
|
async getGameHistory()
|
||||||
|
{
|
||||||
|
let response = await this.client._get(`/api/games/history/${this.id}`);
|
||||||
|
let response_data = await response.json();
|
||||||
|
|
||||||
|
let games = [];
|
||||||
|
|
||||||
|
response_data.forEach(game_data => {
|
||||||
|
games.push(new Game(this.client,
|
||||||
|
game_data.id,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
game_data.winner_id,
|
||||||
|
game_data.state,
|
||||||
|
game_data.started,
|
||||||
|
game_data.finished,
|
||||||
|
game_data.players,
|
||||||
|
game_data.start_timestamp,
|
||||||
|
game_data.stop_timestamp
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
|
||||||
async getBlock() {
|
async getBlock() {
|
||||||
let block_response = await this.client._get("/api/profiles/block");
|
let block_response = await this.client._get("/api/profiles/block");
|
||||||
|
|
||||||
|
@ -42,6 +42,11 @@ class Profiles
|
|||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Number} id
|
||||||
|
* @returns {Profile}
|
||||||
|
*/
|
||||||
async getProfileId(id)
|
async getProfileId(id)
|
||||||
{
|
{
|
||||||
let profile = new Profile(this.client, undefined, id);
|
let profile = new Profile(this.client, undefined, id);
|
||||||
|
@ -13,8 +13,16 @@ class Game
|
|||||||
* @param {CallableFunction} goal_handler
|
* @param {CallableFunction} goal_handler
|
||||||
* @param {CallableFunction} finish_handler
|
* @param {CallableFunction} finish_handler
|
||||||
* @param {CallableFunction} disconnect_handler
|
* @param {CallableFunction} disconnect_handler
|
||||||
|
* @param {Boolean} finished
|
||||||
|
* @param {Number} id
|
||||||
|
* @param {[Object]} players_data
|
||||||
|
* @param {Number} start_timestamp
|
||||||
|
* @param {Number} stop_timestamp
|
||||||
|
* @param {Boolean} started
|
||||||
|
* @param {Number} winner_id
|
||||||
|
* @param {String} state
|
||||||
*/
|
*/
|
||||||
constructor(client, id, disconnect_handler, goal_handler, finish_handler)
|
constructor(client, id, disconnect_handler, goal_handler, finish_handler, winner_id, state, started, finished, players_data, start_timestamp, stop_timestamp)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @type {Client}
|
* @type {Client}
|
||||||
@ -40,6 +48,50 @@ class Game
|
|||||||
* @type {CallableFunction}
|
* @type {CallableFunction}
|
||||||
*/
|
*/
|
||||||
this.disconnect_handler = disconnect_handler;
|
this.disconnect_handler = disconnect_handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.state = state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Boolean}
|
||||||
|
*/
|
||||||
|
this.started = started;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Boolean}
|
||||||
|
*/
|
||||||
|
this.finished = finished;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
this.winner_id = this.finished ? winner_id : undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
this.start_timestamp = start_timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
this.stop_timestamp = stop_timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {[Player]}
|
||||||
|
*/
|
||||||
|
this.players = [];
|
||||||
|
|
||||||
|
players_data.forEach(player_data => {
|
||||||
|
this.players.push(new Player(this,
|
||||||
|
player_data.player_id,
|
||||||
|
player_data.username,
|
||||||
|
player_data.score
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,9 +107,6 @@ class Game
|
|||||||
|
|
||||||
let response_data = await response.json();
|
let response_data = await response.json();
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {[Player]}
|
|
||||||
*/
|
|
||||||
this.players = [];
|
this.players = [];
|
||||||
|
|
||||||
response_data.players.forEach(player_data => {
|
response_data.players.forEach(player_data => {
|
||||||
@ -69,34 +118,14 @@ class Game
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
this.state = response_data.state;
|
this.state = response_data.state;
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
this.started = response_data.started;
|
this.started = response_data.started;
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
this.finished = response_data.finished;
|
this.finished = response_data.finished;
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Number}
|
|
||||||
*/
|
|
||||||
this.winner_id = this.finished ? response_data.winner_id : undefined;
|
this.winner_id = this.finished ? response_data.winner_id : undefined;
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Number}
|
|
||||||
*/
|
|
||||||
this.start_timestamp = response_data.start_timestamp;
|
this.start_timestamp = response_data.start_timestamp;
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Number}
|
|
||||||
*/
|
|
||||||
this.stop_timestamp = response_data.stop_timestamp;
|
this.stop_timestamp = response_data.stop_timestamp;
|
||||||
|
|
||||||
if (this.finished === true)
|
if (this.finished === true)
|
||||||
|
@ -19,6 +19,7 @@ import TournamentsView from "./views/tournament/TournamentsListView.js";
|
|||||||
import TournamentCreateView from "./views/tournament/TournamentCreateView.js";
|
import TournamentCreateView from "./views/tournament/TournamentCreateView.js";
|
||||||
import AuthenticationView from "./views/accounts/AuthenticationView.js";
|
import AuthenticationView from "./views/accounts/AuthenticationView.js";
|
||||||
import TicTacToeView from "./views/TicTacToeView.js";
|
import TicTacToeView from "./views/TicTacToeView.js";
|
||||||
|
import GameHistoryView from "./views/GameHistoryView.js";
|
||||||
|
|
||||||
let client = new Client(location.origin);
|
let client = new Client(location.origin);
|
||||||
let lang = client.lang;
|
let lang = client.lang;
|
||||||
@ -77,6 +78,7 @@ const router = async(uri) => {
|
|||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: "/", view: Dashboard },
|
{ path: "/", view: Dashboard },
|
||||||
|
{ path: "/profiles/:id/history", view: GameHistoryView },
|
||||||
{ path: "/profiles/:username", view: ProfilePageView },
|
{ path: "/profiles/:username", view: ProfilePageView },
|
||||||
{ path: "/tournaments/create", view: TournamentCreateView },
|
{ path: "/tournaments/create", view: TournamentCreateView },
|
||||||
{ path: "/tournaments/:id", view: TournamentPageView },
|
{ path: "/tournaments/:id", view: TournamentPageView },
|
||||||
|
66
frontend/static/js/views/GameHistoryView.js
Normal file
66
frontend/static/js/views/GameHistoryView.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { client, lang } from "../index.js";
|
||||||
|
import AbstractAuthenticatedView from "./abstracts/AbstractAuthenticatedView.js";
|
||||||
|
|
||||||
|
export default class extends AbstractAuthenticatedView
|
||||||
|
{
|
||||||
|
constructor(params)
|
||||||
|
{
|
||||||
|
super(params, 'homeWindowTitle');
|
||||||
|
this.id = params.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async postInit()
|
||||||
|
{
|
||||||
|
this.profile = await client.profiles.getProfileId(this.id);
|
||||||
|
|
||||||
|
if (this.profile === null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
await this.fillHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fillHistory()
|
||||||
|
{
|
||||||
|
let games = await this.profile.getGameHistory();
|
||||||
|
|
||||||
|
let game_list = document.getElementById("game-list");
|
||||||
|
|
||||||
|
games.forEach(game => {
|
||||||
|
|
||||||
|
let a = document.createElement("a");
|
||||||
|
a.href = `/games/${game.id}/0`;
|
||||||
|
a.setAttribute("data-link", true);
|
||||||
|
|
||||||
|
let game_item = document.createElement("div");
|
||||||
|
game_item.className = "game-item";
|
||||||
|
game_item.style.backgroundColor = "grey";
|
||||||
|
if (game.started)
|
||||||
|
game_item.style.backgroundColor = "yellow";
|
||||||
|
if (game.finished)
|
||||||
|
game_item.style.backgroundColor = this.profile.id === game.winner_id ? "green" : "red";
|
||||||
|
|
||||||
|
game.players.forEach(player => {
|
||||||
|
let player_score = document.createElement("a");
|
||||||
|
|
||||||
|
player_score.href = `/profiles/${player.username}`;
|
||||||
|
player_score.innerText = `${player.username}: ${player.score.length}`;
|
||||||
|
player_score.setAttribute("data-link", true);
|
||||||
|
|
||||||
|
game_item.appendChild(player_score);
|
||||||
|
});
|
||||||
|
|
||||||
|
a.appendChild(game_item);
|
||||||
|
game_list.appendChild(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getHtml()
|
||||||
|
{
|
||||||
|
return /* HTML */ `
|
||||||
|
<link rel="stylesheet" href="/static/css/gameHistory.css">
|
||||||
|
<h1>Game History</h1>
|
||||||
|
<div id="game-list">
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
27
games/GameHistoryView.py
Normal file
27
games/GameHistoryView.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import permissions, status
|
||||||
|
|
||||||
|
from django.http import HttpRequest
|
||||||
|
|
||||||
|
from .models import GameMembersModel, GameModel
|
||||||
|
from .serializers import GameSerializer
|
||||||
|
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
class GameHistoryView(APIView):
|
||||||
|
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, pk: int = None):
|
||||||
|
|
||||||
|
member_game_model_list: list[GameMembersModel] = GameMembersModel.objects.filter(player_id = pk)
|
||||||
|
|
||||||
|
game_model_list: list[GameModel] = []
|
||||||
|
|
||||||
|
for member_game_model in member_game_model_list:
|
||||||
|
game_model_list.append(GameModel.objects.get(pk = member_game_model.game_id))
|
||||||
|
|
||||||
|
games_data: list[dict] = [GameSerializer(game_model).data for game_model in game_model_list]
|
||||||
|
|
||||||
|
return Response(games_data)
|
@ -3,9 +3,11 @@ from django.conf import settings
|
|||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
from .GameViewSet import GameViewSet
|
from .GameViewSet import GameViewSet
|
||||||
|
from .GameHistoryView import GameHistoryView
|
||||||
from .GameConfigView import GameConfigView
|
from .GameConfigView import GameConfigView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("<int:pk>", GameViewSet.as_view({"get": "retrieve"}), name="game_page"),
|
path("<int:pk>", GameViewSet.as_view({"get": "retrieve"}), name="game_page"),
|
||||||
|
path("history/<int:pk>", GameHistoryView.as_view(), name="history_page"),
|
||||||
path("", GameConfigView.as_view(), name = "game_config")
|
path("", GameConfigView.as_view(), name = "game_config")
|
||||||
]
|
]
|
Loading…
Reference in New Issue
Block a user