add list selection players et match, need to move it on the side and use a icone

This commit is contained in:
Theouche 2024-08-01 17:26:14 +02:00
parent 8ed7cf6419
commit fb9c54c8df
10 changed files with 273 additions and 126 deletions

View File

@ -4,9 +4,9 @@ DEBUG=True
DJANGO_ALLOWED_HOSTS=['*'] DJANGO_ALLOWED_HOSTS=['*']
# PostgreSQL settings # PostgreSQL settings
POSTGRES_DB= POSTGRES_DB=players_db
POSTGRES_USER= POSTGRES_USER=42student
POSTGRES_PASSWORD= POSTGRES_PASSWORD=test
DB_HOST=db DB_HOST=db
DB_PORT=5432 DB_PORT=5432

View File

@ -0,0 +1,19 @@
# Generated by Django 5.0.7 on 2024-07-31 16:58
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('game', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='match',
name='winner',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='won_matches', to='game.player'),
),
]

View File

@ -37,7 +37,7 @@ class Match(models.Model):
player2 = models.ForeignKey('Player', related_name='match_as_player2', on_delete=models.CASCADE) player2 = models.ForeignKey('Player', related_name='match_as_player2', on_delete=models.CASCADE)
score_player1 = models.PositiveSmallIntegerField() score_player1 = models.PositiveSmallIntegerField()
score_player2 = models.PositiveSmallIntegerField() score_player2 = models.PositiveSmallIntegerField()
winner = models.ForeignKey('Player', related_name='won_matches',on_delete=models.CASCADE) winner = models.ForeignKey('Player', related_name='won_matches',on_delete=models.CASCADE, null=True)
nbr_ball_touch_p1 = models.PositiveIntegerField() nbr_ball_touch_p1 = models.PositiveIntegerField()
nbr_ball_touch_p2 = models.PositiveIntegerField() nbr_ball_touch_p2 = models.PositiveIntegerField()
duration = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) duration = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)

View File

@ -1,8 +1,13 @@
# /pong/game/urls.py # /pong/game/urls.py
from django.urls import path from django.urls import path, include
from . import views from . import views
from .views import player_list, tournoi_list, match_list from .views import player_list, tournoi_list, match_list
from rest_framework.routers import DefaultRouter
from .views import match_list_json
from .views import player_list_json
urlpatterns = [ urlpatterns = [
path('', views.index, name='index'), path('', views.index, name='index'),
@ -12,4 +17,6 @@ urlpatterns = [
path('players/', player_list, name='player_list'), path('players/', player_list, name='player_list'),
path('matches/', match_list, name='match_list'), path('matches/', match_list, name='match_list'),
path('tournois/', tournoi_list, name='tournoi_list'), path('tournois/', tournoi_list, name='tournoi_list'),
path('api/match_list/', match_list_json, name='match_list_json'),
path('api/player_list/', player_list_json, name='player_list_json'),
] ]

View File

@ -12,6 +12,9 @@ from django.http import JsonResponse
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
""" from .serializers import MatchSerializer """
from rest_framework import viewsets
import json import json
import uuid import uuid
@ -69,124 +72,6 @@ def get_or_create_token(user):
####################### THEOUCHE PART ############################ ####################### THEOUCHE PART ############################
@csrf_exempt
def create_player_view(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
name = data.get('name')
# Vérifier que le nom est présent
if not name:
return JsonResponse({'error': 'Name is required'}, status=400)
# Appeler la fonction create_player et traiter les exceptions
player = create_player(
name=name,
total_match=data.get('total_match', 0),
total_win=data.get('total_win', 0),
p_win=data.get('p_win'),
m_score_match=data.get('m_score_match'),
m_score_adv_match=data.get('m_score_adv_match'),
best_score=data.get('best_score', 0),
m_nbr_ball_touch=data.get('m_nbr_ball_touch'),
total_duration=data.get('total_duration'),
m_duration=data.get('m_duration'),
num_participated_tournaments=data.get('num_participated_tournaments', 0),
num_won_tournaments=data.get('num_won_tournaments', 0)
)
return JsonResponse({'id': player.id, 'name': player.name})
except ValueError as e:
# Erreur spécifique à la validation
return JsonResponse({'error': str(e)}, status=400)
except json.JSONDecodeError:
# Erreur de décodage JSON
return JsonResponse({'error': 'Invalid JSON format'}, status=400)
except Exception as e:
# Erreur générale
return JsonResponse({'error': 'An unexpected error occurred', 'details': str(e)}, status=500)
# Méthode HTTP non supportée
return JsonResponse({'error': 'Invalid HTTP method'}, status=405)
@csrf_exempt
def create_tournoi_view(request):
if request.method == 'POST':
data = json.loads(request.body)
name = data.get('name')
nbr_player = data.get('nbr_player')
date = data.get('date')
winner_id = data.get('winner_id')
if not (name and nbr_player and date):
return JsonResponse({'error': 'Name, number of players, and date are required'}, status=400)
winner = None
if winner_id:
try:
winner = Player.objects.get(id=winner_id)
except Player.DoesNotExist:
return JsonResponse({'error': 'Winner not found'}, status=404)
tournoi = create_tournoi(name, nbr_player, date, winner)
return JsonResponse({
'id': tournoi.id,
'name': tournoi.name,
'nbr_player': tournoi.nbr_player,
'date': tournoi.date.isoformat(),
'winner': winner.id if winner else None
})
return JsonResponse({'error': 'Invalid HTTP method'}, status=405)
@csrf_exempt
def create_match_view(request):
if request.method == 'POST':
data = json.loads(request.body)
player1_id = data.get('player1_id')
player2_id = data.get('player2_id')
score_player1 = data.get('score_player1', 0)
score_player2 = data.get('score_player2', 0)
nbr_ball_touch_p1 = data.get('nbr_ball_touch_p1', 0)
nbr_ball_touch_p2 = data.get('nbr_ball_touch_p2', 0)
duration = data.get('duration')
is_tournoi = data.get('is_tournoi', False)
tournoi_id = data.get('tournoi_id')
if not (player1_id and player2_id and duration):
return JsonResponse({'error': 'Player IDs and duration are required'}, status=400)
try:
player1 = Player.objects.get(id=player1_id)
player2 = Player.objects.get(id=player2_id)
except Player.DoesNotExist:
return JsonResponse({'error': 'One or both players not found'}, status=404)
tournoi = None
if tournoi_id:
try:
tournoi = Tournoi.objects.get(id=tournoi_id)
except Tournoi.DoesNotExist:
return JsonResponse({'error': 'Tournoi not found'}, status=404)
match = create_match(player1, player2, score_player1, score_player2, nbr_ball_touch_p1, nbr_ball_touch_p2, duration, is_tournoi, tournoi)
return JsonResponse({
'id': match.id,
'player1': match.player1.id,
'player2': match.player2.id,
'score_player1': match.score_player1,
'score_player2': match.score_player2,
'nbr_ball_touch_p1': match.nbr_ball_touch_p1,
'nbr_ball_touch_p2': match.nbr_ball_touch_p2,
'duration': str(match.duration),
'is_tournoi': match.is_tournoi,
'tournoi': match.tournoi.id if match.tournoi else None
})
return JsonResponse({'error': 'Invalid HTTP method'}, status=405)
def player_list(request): def player_list(request):
players = Player.objects.all() players = Player.objects.all()
return render(request, 'pong/player_list.html', {'players': players}) return render(request, 'pong/player_list.html', {'players': players})
@ -199,4 +84,35 @@ def tournoi_list(request):
tournois = Tournoi.objects.select_related('winner').all() tournois = Tournoi.objects.select_related('winner').all()
return render(request, 'pong/tournoi_list.html', {'tournois': tournois}) return render(request, 'pong/tournoi_list.html', {'tournois': tournois})
from django.http import JsonResponse
def match_list_json(request):
matches = Match.objects.select_related('player1', 'player2', 'winner', 'tournoi').all()
data = {
'matches': list(matches.values(
'id', 'player1__name', 'player2__name', 'score_player1', 'score_player2',
'winner__name', 'nbr_ball_touch_p1', 'nbr_ball_touch_p2', 'duration', 'date',
'is_tournoi', 'tournoi__name'
))
}
return JsonResponse(data)
def player_list_json(request):
# Récupère tous les joueurs
players = Player.objects.all()
# Crée un dictionnaire avec les informations des joueurs
data = {
'players': list(players.values(
'id', 'name', 'total_match', 'total_win', 'p_win',
'm_score_match', 'm_score_adv_match', 'best_score',
'm_nbr_ball_touch', 'total_duration', 'm_duration',
'num_participated_tournaments', 'num_won_tournaments'
))
}
# Renvoie les données en JSON
return JsonResponse(data)
####################### THEOUCHE PART ############################ ####################### THEOUCHE PART ############################

View File

@ -36,6 +36,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'channels', # Add Django Channels 'channels', # Add Django Channels
'pong.game', # Your game app 'pong.game', # Your game app
'rest_framework'
] ]
MIDDLEWARE = [ MIDDLEWARE = [

View File

@ -11,6 +11,9 @@ document.addEventListener('DOMContentLoaded', () => {
const loginForm = document.getElementById('login-form'); const loginForm = document.getElementById('login-form');
const registerForm = document.getElementById('register-form'); const registerForm = document.getElementById('register-form');
const formBlock = document.getElementById('block-form'); const formBlock = document.getElementById('block-form');
const viewSelector = document.getElementById('view-selector');
const playerList = document.getElementById('player-list');
const matchList = document.getElementById('match-list');
let socket; let socket;
@ -241,4 +244,92 @@ document.addEventListener('DOMContentLoaded', () => {
player2Score.textContent = gameState.player2_score; player2Score.textContent = gameState.player2_score;
} }
viewSelector.addEventListener('change', function() {
const selectedView = this.value;
// Masquer les deux listes par défaut
playerList.style.display = 'none';
matchList.style.display = 'none';
// Afficher la liste sélectionnée
if (selectedView === 'player-list') {
playerList.style.display = 'block';
fetchPlayers();
} else if (selectedView === 'match-list') {
matchList.style.display = 'block';
fetchMatches();
}
})
function fetchMatches() {
fetch('/api/match_list/')
.then(response => response.json())
.then(data => {
if (data.matches) {
displayMatches(data.matches);
}
})
.catch(error => console.error('Error fetching match data:', error));
}
function fetchPlayers(){
fetch('/api/player_list/')
.then(response => response.json())
.then(data => {
if (data.players) {
displayPlayers(data.players);
}
})
.catch(error => console.error('Error fetching match data:', error));
}
function displayMatches(matches) {
const matchListBody = document.querySelector('#match-list tbody');
matchListBody.innerHTML = '';
matches.forEach(match => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${match.id}</td>
<td>${match.player1__name}</td>
<td>${match.player2__name}</td>
<td>${match.score_player1}</td>
<td>${match.score_player2}</td>
<td>${match.winner__name}</td>
<td>${match.nbr_ball_touch_p1}</td>
<td>${match.nbr_ball_touch_p2}</td>
<td>${match.duration}</td>
<td>${match.date}</td>
<td>${match.is_tournoi}</td>
<td>${match.tournoi__name}</td>
`;
matchListBody.appendChild(row);
});
}
function displayPlayers(players) {
const playersListBody = document.querySelector('#player-list tbody');
playersListBody.innerHTML = '';
players.forEach(player => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${player.id}</td>
<td>${player.name}</td>
<td>${player.total_match}</td>
<td>${player.total_win}</td>
<td>${player.p_win}</td>
<td>${player.m_score_match}</td>
<td>${player.m_score_adv_match}</td>
<td>${player.best_score}</td>
<td>${player.m_nbr_ball_touch}</td>
<td>${player.total_duration}</td>
<td>${player.m_duration}</td>
<td>${player.num_participated_tournaments}</td>
<td>${player.num_won_tournaments}</td>
`;
playersListBody.appendChild(row);
});
}
}); });

View File

@ -10,7 +10,6 @@
<div class="logo"> <div class="logo">
<img src="{% static 'logo-42-perpignan.png' %}" alt="Logo"> <img src="{% static 'logo-42-perpignan.png' %}" alt="Logo">
</div> </div>
</head> </head>
<body> <body>
@ -46,6 +45,14 @@
</div> </div>
</div> </div>
<div class="menu">
<select id="view-selector">
<option value="none">-- Select View --</option>
<option value="player-list">Players</option>
<option value="match-list">Matches</option>
</select>
</div>
<div id="game1" style="display: none;"> <div id="game1" style="display: none;">
<div id="gameCode" class="game-code">Game Code : </div> <div id="gameCode" class="game-code">Game Code : </div>
<div id="player1-name" class="name">Player 1</div> <div id="player1-name" class="name">Player 1</div>
@ -58,6 +65,97 @@
<div id="ball"></div> <div id="ball"></div>
</div> </div>
</div> </div>
<div id="match-list" style="display: none;">
<h1>Matches List</h1>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>Player 1</th>
<th>Player 2</th>
<th>Score Player 1</th>
<th>Score Player 2</th>
<th>Winner</th>
<th>Ball Touches Player 1</th>
<th>Ball Touches Player 2</th>
<th>Duration</th>
<th>Date</th>
<th>Is Tournament</th>
<th>Tournament</th>
</tr>
</thead>
<tbody>
{% for match in matches %}
<tr>
<td>{{ match.id }}</td>
<td>{{ match.player1.name }}</td>
<td>{{ match.player2.name }}</td>
<td>{{ match.score_player1 }}</td>
<td>{{ match.score_player2 }}</td>
<td>{{ match.winner.name }}</td>
<td>{{ match.nbr_ball_touch_p1 }}</td>
<td>{{ match.nbr_ball_touch_p2 }}</td>
<td>{{ match.duration }}</td>
<td>{{ match.date }}</td>
<td>{{ match.is_tournoi }}</td>
<td>{{ match.tournoi.name }}</td>
</tr>
{% empty %}
<tr>
<td colspan="12">No matches found.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div id="player-list" style="display: none;">
<h1>Players List</h1>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Total Matches</th>
<th>Total Wins</th>
<th>Win Percentage</th>
<th>Average Match Score</th>
<th>Average Opponent Score</th>
<th>Best Score</th>
<th>Average Ball Touches</th>
<th>Total Duration</th>
<th>Average Duration</th>
<th>Participated Tournaments</th>
<th>Won Tournaments</th>
</tr>
</thead>
<tbody>
{% for player in players %}
<tr>
<td>{{ player.id }}</td>
<td>{{ player.name }}</td>
<td>{{ player.total_match }}</td>
<td>{{ player.total_win }}</td>
<td>{{ player.p_win }}</td>
<td>{{ player.m_score_match }}</td>
<td>{{ player.m_score_adv_match }}</td>
<td>{{ player.best_score }}</td>
<td>{{ player.m_nbr_ball_touch }}</td>
<td>{{ player.total_duration }}</td>
<td>{{ player.m_duration }}</td>
<td>{{ player.num_participated_tournaments }}</td>
<td>{{ player.num_won_tournaments }}</td>
</tr>
{% empty %}
<tr>
<td colspan="13">No players found.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script src="{% static 'game.js' %}"></script> <script src="{% static 'game.js' %}"></script>
<script> <script>
const starsContainer = document.getElementById('stars'); const starsContainer = document.getElementById('stars');
@ -73,7 +171,8 @@
} }
setInterval(createTrail, 100); setInterval(createTrail, 100);
</script> </script>
</body> </body>
</html> </html>

View File

@ -250,4 +250,17 @@ button:hover {
position: relative; position: relative;
z-index: 10; z-index: 10;
max-width: 80%; max-width: 80%;
}
.menu {
margin-top: 20px;
text-align: center;
}
select#view-selector {
padding: 10px;
font-size: 16px;
border-radius: 5px;
border: 1px solid #ccc;
cursor: pointer;
} }

View File

@ -2,4 +2,5 @@ Django
psycopg2 psycopg2
python-dotenv python-dotenv
channels channels
daphne daphne
djangorestframework