diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a8727e7..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -venv/ -__pycache__/ -data/ -.env -makefile -logs/django.log diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 42ff94d..0000000 --- a/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:latest - -# Set environment variables -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 - -WORKDIR /transcendence - -RUN apt update && apt upgrade -y - -COPY requirements.txt . -COPY manage.py . - -RUN python3 -m venv venv -RUN venv/bin/pip3 install --upgrade pip -RUN venv/bin/pip3 install --no-cache-dir -r requirements.txt - -EXPOSE 8080 diff --git a/config/logstash.conf b/config/logstash.conf deleted file mode 100644 index 329a522..0000000 --- a/config/logstash.conf +++ /dev/null @@ -1,28 +0,0 @@ -input { - file { - path => "/usr/share/logstash/logs/django.log" - start_position => "beginning" - sincedb_path => "/dev/null" - codec => "json" - } -} - -filter { - json { - source => "message" - target => "json_message" - } -} - -output { - elasticsearch { - hosts => ["https://es01:9200"] - user => "elastic" - password => "${ELASTIC_PASSWORD}" - ssl_enabled => true - ssl_certificate_authorities => "/usr/share/logstash/certs/ca/ca.crt" - ssl_verification_mode => "full" - index => "django-logs-%{+YYYY.MM.dd}" - } - stdout { codec => rubydebug } - } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index c283dec..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,240 +0,0 @@ -services: - setup: - image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} - container_name: setup - user: "0" - volumes: - - certs:/usr/share/elasticsearch/config/certs - command: > - bash -c ' - if [ x${ELASTIC_PASSWORD} == x ]; then - echo "Set the ELASTIC_PASSWORD environment variable in the .env file"; - exit 1; - elif [ x${KIBANA_PASSWORD} == x ]; then - echo "Set the KIBANA_PASSWORD environment variable in the .env file"; - exit 1; - fi; - if [ ! -f config/certs/ca.zip ]; then - echo "Creating CA"; - bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip; - unzip config/certs/ca.zip -d config/certs; - fi; - if [ ! -f config/certs/certs.zip ]; then - echo "Creating certs"; - echo -ne \ - "instances:\n"\ - " - name: es01\n"\ - " dns:\n"\ - " - es01\n"\ - " - localhost\n"\ - " ip:\n"\ - " - 127.0.0.1\n"\ - " - name: kibana\n"\ - " dns:\n"\ - " - kibana\n"\ - " - localhost\n"\ - " ip:\n"\ - " - 127.0.0.1\n"\ - > config/certs/instances.yml; - - bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key; - unzip config/certs/certs.zip -d config/certs; - fi; - - echo "Setting file permissions" - chown -R root:root config/certs; - find . -type d -exec chmod 750 \{\} \;; - find . -type f -exec chmod 640 \{\} \;; - - echo "Waiting for Elasticsearch availability"; - until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done; - echo "Setting kibana_system password"; - until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done; - echo "All done!"; - ' - healthcheck: - test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"] - interval: 1s - timeout: 5s - retries: 120 - - backend: - build: - context: . - dockerfile: Dockerfile - image: backend - container_name: backend - restart: always - command: /bin/sh -c "sleep 5 && - venv/bin/python manage.py makemigrations --noinput && - venv/bin/python manage.py migrate --noinput && - venv/bin/python manage.py collectstatic --noinput && - venv/bin/daphne -b 0.0.0.0 -p 8080 pong.asgi:application" - volumes: - - pong:/transcendence/pong - - pong_django_logs:/transcendence/logs - ports: - - 8080:8080 - networks: - - app-network - environment: - DB_HOST: db - DB_PORT: 5432 - DB_NAME: ${POSTGRES_DB} - DB_USER: ${POSTGRES_USER} - DB_PASSWORD: ${POSTGRES_PASSWORD} - depends_on: - - db - healthcheck: - test: ["CMD-SHELL", "curl", "http://localhost:8080"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 10s - - db: - image: postgres:latest - container_name: postgres - restart: always - volumes: - - pong_pg_data:/var/lib/postgresql/data - ports: - - "5432:5432" - networks: - - app-network - environment: - POSTGRES_DB: ${POSTGRES_DB} - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] - interval: 10s - timeout: 5s - retries: 5 - - es01: - image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} - container_name: es01 - depends_on: - setup: - condition: service_healthy - volumes: - - certs:/usr/share/elasticsearch/config/certs:ro - - pong_es_data_01:/usr/share/elasticsearch/data - labels: - co.elastic.logs/module: elasticsearch - ports: - - 9200:9200 - environment: - - node.name=es01 - - cluster.name=${CLUSTER_NAME} - - discovery.type=single-node - - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - - bootstrap.memory_lock=true - - xpack.security.enabled=true - - xpack.security.http.ssl.enabled=true - - xpack.security.http.ssl.key=certs/es01/es01.key - - xpack.security.http.ssl.certificate=certs/es01/es01.crt - - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt - - xpack.security.transport.ssl.enabled=true - - xpack.security.transport.ssl.key=certs/es01/es01.key - - xpack.security.transport.ssl.certificate=certs/es01/es01.crt - - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt - - xpack.security.transport.ssl.verification_mode=certificate - - xpack.license.self_generated.type=${LICENSE} - healthcheck: - test: - [ - "CMD-SHELL", - "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", - ] - interval: 10s - timeout: 10s - retries: 120 - - kibana: - image: docker.elastic.co/kibana/kibana:${STACK_VERSION} - container_name: kibana - labels: - co.elastic.logs/module: kibana - depends_on: - es01: - condition: service_healthy - volumes: - - certs:/usr/share/kibana/config/certs:ro - - pong_kibana:/usr/share/kibana/data - ports: - - 5601:5601 - environment: - - SERVERNAME=kibana - - ELASTICSEARCH_HOSTS=https://es01:9200 - - ELASTICSEARCH_USERNAME=${KIBANA_USERNAME} - - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} - - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt - - XPACK_SECURITY_ENCRYPTIONKEY=${ENCRYPTION_KEY} - - XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${ENCRYPTION_KEY} - - XPACK_REPORTING_ENCRYPTIONKEY=${ENCRYPTION_KEY} - healthcheck: - test: - [ - "CMD-SHELL", - "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'" - ] - interval: 10s - timeout: 10s - retries: 120 - - logstash01: - image: docker.elastic.co/logstash/logstash:${STACK_VERSION} - container_name: logstash01 - labels: - co.elastic.logs/module: logstash - user: root - depends_on: - es01: - condition: service_healthy - kibana: - condition: service_healthy - volumes: - - certs:/usr/share/logstash/certs - - pong_logstash_data01:/usr/share/logstash/data - - ./config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro - - pong_django_logs:/usr/share/logstash/logs - ports: - - "5044:5044/udp" - command: logstash -f /usr/share/logstash/pipeline/logstash.conf - environment: - - NODE_NAME="logstash" - - ELASTIC_HOSTS=https://es01:9200 - - ELASTIC_USER=${ELASTIC_USERNAME} - - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - - xpack.monitoring.enabled=false - -volumes: - pong: - driver: local - driver_opts: - type: none - device: ${PROJECT_PATH} - o: bind - pong_django_logs: - driver: local - driver_opts: - type: none - device: ${DJANGO_LOGS} - o: bind - pong_pg_data: - driver: local - pong_es_data_01: - driver: local - pong_kibana: - driver: local - pong_logstash_data01: - driver: local - certs: - driver: local - -networks: - app-network: - name: app-network - driver: bridge diff --git a/env_template b/env_template deleted file mode 100644 index b297aeb..0000000 --- a/env_template +++ /dev/null @@ -1,30 +0,0 @@ -# Django settings -SECRET_KEY="FollowTheWhiteRabbit" -DEBUG=True -DJANGO_ALLOWED_HOSTS=['*'] - -# PostgreSQL settings -POSTGRES_DB=players_db -POSTGRES_USER=42student -POSTGRES_PASSWORD= - -# Django settings -DB_HOST=db -DB_PORT=5432 -PWD_PATH=${PWD} -PROJECT_PATH=${PWD_PATH}/pong - -# ElasticSearch settings -STACK_VERSION=8.14.3 -CLUSTER_NAME=docker-cluster -LICENSE=basic - -ELASTIC_USERNAME=elastic -ELASTIC_PASSWORD= - -# Kibana settings -KIBANA_PORT=5601 -KIBANA_USERNAME= -KIBANA_PASSWORD= - -ENCRYPTION_KEY=c34d38b3a14956121ff2170e5030b471551370178f43e5626eec58b04a30fae2 diff --git a/logs/172.31.141.12-1726064615544.log b/logs/172.31.141.12-1726064615544.log deleted file mode 100644 index b185656..0000000 --- a/logs/172.31.141.12-1726064615544.log +++ /dev/null @@ -1,41 +0,0 @@ -:8080/:1 The Cross-Origin-Opener-Policy header has been ignored, because the URL's origin was untrustworthy. It was defined either in the final response or a redirect. Please deliver the response using the HTTPS protocol. You can also use the 'localhost' origin instead. See https://www.w3.org/TR/powerful-features/#potentially-trustworthy-origin and https://html.spec.whatwg.org/#the-cross-origin-opener-policy-header. -game.js:2 DOM fully loaded and parsed -game.js:48 DOM elements initialized -game.js:71 Event listeners added -game.js:186 checkUserExists called with username: dede -game.js:203 User existence check response: {exists: false} -game.js:212 handleRegister called -game.js:225 Attempting to register user: dede -game.js:250 registerUser called with username: dede -game.js:273 Registration response data: {registered: true, token: 'c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793'} -game.js:275 User registered successfully: {registered: true, token: 'c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793'} -game.js:229 Token stored: c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793 -game.js:230 User registered successfully -game.js:922 Joining room: main_room with username: dede and token: c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793 -game.js:929 Joining new room: main_room -game.js:846 createRoomTab: main_room with username: dede and token: c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793 -game.js:856 Tab for room main_room already exists. -game.js:870 Showing tab for room: main_room -game.js:778 Initializing chat WebSocket... -game.js:779 Initializing chat WebSocket for room: main_room with username: dede -game.js:877 switchRoom: main_room with username: dede and token: c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793 -game.js:883 Attempting to switch to room: main_room -game.js:889 Switching from room null to room main_room -game.js:783 startChatWebSocket: main_room with username: dede and token: c4ab5fd7-4b04-4353-8d4e-ae1afb2ba793 -game.js:785 Attempting to connect to WebSocket for room: main_room -game.js:835 WebSocket connection stored for room: main_room -game.js:784 WebSocket connection to 'ws://172.31.141.12:8080/ws/chat/main_room/' failed: -(anonymous) @ game.js:784 -game.js:831 Chat WebSocket error in room main_room: Event {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …} -chatSocket.onerror @ game.js:831 -error -(anonymous) @ game.js:830 -setTimeout -startChatWebSocket @ game.js:781 -joinRoom @ game.js:932 -handleRegister @ game.js:235 -game.js:826 Chat WebSocket closed unexpectedly for room main_room -chatSocket.onclose @ game.js:826 -game.js:754 WebSocket is already in CLOSING or CLOSED state. -sendMessage @ game.js:754 -(anonymous) @ game.js:747 diff --git a/logs/172.31.141.12-1726065549172.log b/logs/172.31.141.12-1726065549172.log deleted file mode 100644 index 7a3b513..0000000 --- a/logs/172.31.141.12-1726065549172.log +++ /dev/null @@ -1,38 +0,0 @@ -:8080/:1 The Cross-Origin-Opener-Policy header has been ignored, because the URL's origin was untrustworthy. It was defined either in the final response or a redirect. Please deliver the response using the HTTPS protocol. You can also use the 'localhost' origin instead. See https://www.w3.org/TR/powerful-features/#potentially-trustworthy-origin and https://html.spec.whatwg.org/#the-cross-origin-opener-policy-header. -game.js:2 DOM fully loaded and parsed -game.js:48 DOM elements initialized -game.js:71 Event listeners added -game.js:186 checkUserExists called with username: ferdy -game.js:203 User existence check response: {exists: false} -game.js:212 handleRegister called -game.js:225 Attempting to register user: ferdy -game.js:250 registerUser called with username: ferdy -game.js:273 Registration response data: {registered: true, token: '4d383e70-92b8-4e04-8efb-d7bdfc0dcfac'} -game.js:275 User registered successfully: {registered: true, token: '4d383e70-92b8-4e04-8efb-d7bdfc0dcfac'} -game.js:229 Token stored: 4d383e70-92b8-4e04-8efb-d7bdfc0dcfac -game.js:230 User registered successfully -game.js:922 Joining room: main_room with username: ferdy and token: 4d383e70-92b8-4e04-8efb-d7bdfc0dcfac -game.js:929 Joining new room: main_room -game.js:846 createRoomTab: main_room with username: ferdy and token: 4d383e70-92b8-4e04-8efb-d7bdfc0dcfac -game.js:856 Tab for room main_room already exists. -game.js:870 Showing tab for room: main_room -game.js:778 Initializing chat WebSocket... -game.js:779 Initializing chat WebSocket for room: main_room with username: ferdy -game.js:877 switchRoom: main_room with username: ferdy and token: 4d383e70-92b8-4e04-8efb-d7bdfc0dcfac -game.js:883 Attempting to switch to room: main_room -game.js:889 Switching from room null to room main_room -game.js:783 startChatWebSocket: main_room with username: ferdy and token: 4d383e70-92b8-4e04-8efb-d7bdfc0dcfac -game.js:785 Attempting to connect to WebSocket for room: main_room -game.js:835 WebSocket connection stored for room: main_room -game.js:784 WebSocket connection to 'ws://172.31.141.12:8080/ws/chat/main_room/' failed: -(anonymous) @ game.js:784 -game.js:831 Chat WebSocket error in room main_room: Event {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}isTrusted: truebubbles: falsecancelBubble: falsecancelable: falsecomposed: falsecurrentTarget: WebSocket {url: 'ws://172.31.141.12:8080/ws/chat/main_room/', readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}defaultPrevented: falseeventPhase: 0returnValue: truesrcElement: WebSocket {url: 'ws://172.31.141.12:8080/ws/chat/main_room/', readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}target: WebSocket {url: 'ws://172.31.141.12:8080/ws/chat/main_room/', readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}timeStamp: 13273.79999999702type: "error"[[Prototype]]: Event -chatSocket.onerror @ game.js:831 -error -(anonymous) @ game.js:830 -setTimeout -startChatWebSocket @ game.js:781 -joinRoom @ game.js:932 -handleRegister @ game.js:235 -game.js:826 Chat WebSocket closed unexpectedly for room main_room -chatSocket.onclose @ game.js:826 diff --git a/logs/172.31.141.12-1726069036744.log b/logs/172.31.141.12-1726069036744.log deleted file mode 100644 index 8c94772..0000000 --- a/logs/172.31.141.12-1726069036744.log +++ /dev/null @@ -1,40 +0,0 @@ -:8080/:1 The Cross-Origin-Opener-Policy header has been ignored, because the URL's origin was untrustworthy. It was defined either in the final response or a redirect. Please deliver the response using the HTTPS protocol. You can also use the 'localhost' origin instead. See https://www.w3.org/TR/powerful-features/#potentially-trustworthy-origin and https://html.spec.whatwg.org/#the-cross-origin-opener-policy-header. -game.js:2 DOM fully loaded and parsed -game.js:48 DOM elements initialized -game.js:71 Event listeners added -game.js:186 checkUserExists called with username: gggg -game.js:203 User existence check response: {exists: false} -game.js:212 handleRegister called -game.js:225 Attempting to register user: gggg -game.js:250 registerUser called with username: gggg -game.js:273 Registration response data: {registered: true, token: 'a6010523-60c5-460b-ac49-39097e66a376'} -game.js:275 User registered successfully: {registered: true, token: 'a6010523-60c5-460b-ac49-39097e66a376'} -game.js:229 Token stored: a6010523-60c5-460b-ac49-39097e66a376 -game.js:230 User registered successfully -game.js:926 Joining room: main_room with username: gggg and token: a6010523-60c5-460b-ac49-39097e66a376 -game.js:933 Joining new room: main_room -game.js:850 createRoomTab: main_room with username: gggg and token: a6010523-60c5-460b-ac49-39097e66a376 -game.js:860 Tab for room main_room already exists. -game.js:874 Showing tab for room: main_room -game.js:780 Initializing chat WebSocket... -game.js:781 Initializing chat WebSocket for room: main_room with username: gggg -game.js:881 switchRoom: main_room with username: gggg and token: a6010523-60c5-460b-ac49-39097e66a376 -game.js:887 Attempting to switch to room: main_room -game.js:893 Switching from room null to room main_room -game.js:785 startChatWebSocket: main_room with username: gggg and token: a6010523-60c5-460b-ac49-39097e66a376 -game.js:787 Attempting to connect to WebSocket for room: main_room -game.js:838 WebSocket connection stored for room: main_room -game.js:839 Authentication username for chat-input: gggg -game.js:790 Chat WebSocket connection established in room: main_room -game.js:798 Authentication message sent with username: gggg -game.js:799 Authentication message sent for room: main_room -game.js:804 Message received from server in room main_room: {type: 'chat_message', message: ': Anonyme Vous avez rejoint le chat main_room', room: 'main_room'}message: ": Anonyme Vous avez rejoint le chat main_room"room: "main_room"type: "chat_message"[[Prototype]]: Object -game.js:814 Message displayed in chat log for room: main_room -game.js:804 Message received from server in room main_room: {type: 'authenticated', username: 'gggg'}type: "authenticated"username: "gggg"[[Prototype]]: Object -game.js:806 User authenticated for chat successfully in room: main_room -game.js:754 Sending message from username: gggg -game.js:804 Message received from server in room main_room: {type: 'chat_message', message: 'gggg: hhfghfh', room: 'main_room'} -game.js:814 Message displayed in chat log for room: main_room -game.js:754 Sending message from username: gggg -game.js:804 Message received from server in room main_room: {type: 'chat_message', message: 'gggg: fhfhfh', room: 'main_room'} -game.js:814 Message displayed in chat log for room: main_room diff --git a/logs/django_errors.log b/logs/django_errors.log deleted file mode 100644 index 08ff9f5..0000000 --- a/logs/django_errors.log +++ /dev/null @@ -1,9 +0,0 @@ -{"asctime": "2024-09-01 18:09:35,223", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 131470748288704, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-01 18:19:53,264", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 131966181574336, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-01 18:34:25,868", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 138740796229312, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-01 18:35:04,063", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 138740796229312, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-01 18:57:12,326", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 125916130838208, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-01 19:05:27,423", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 132460855690944, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-02 09:24:00,957", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 138073176278720, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-02 09:31:57,272", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 129740826478272, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} -{"asctime": "2024-09-02 09:38:30,671", "levelname": "ERROR", "name": "django.request", "module": "log", "process": 25, "thread": 136981996635840, "message": "Internal Server Error: /register_user/", "taskName": null, "status_code": 500, "request": ""} diff --git a/makefile b/makefile deleted file mode 100644 index b6c604c..0000000 --- a/makefile +++ /dev/null @@ -1,49 +0,0 @@ -COMPOSE_FILE=docker-compose.yml -COMPOSE=docker compose -f $(COMPOSE_FILE) -CONTAINER=$(c) - -up: down - $(COMPOSE) build - $(COMPOSE) up $(CONTAINER) || true - -build: - $(COMPOSE) build $(CONTAINER) - -start: - $(COMPOSE) start $(CONTAINER) - -stop: - $(COMPOSE) stop $(CONTAINER) - -down: - $(COMPOSE) down $(CONTAINER) - -destroy: - $(COMPOSE) down -v --rmi all - sudo lsof -i :5432 | awk 'NR>1 {print $$2}' | xargs sudo kill -9 || true - sudo lsof -i :80 | awk 'NR>1 {print $$2}' | xargs sudo kill -9 || true - -logs: - $(COMPOSE) logs -f $(CONTAINER) - -ps: - $(COMPOSE) ps - -db-shell: - $(COMPOSE) exec db psql -U 42student players_db - -re: destroy up - -help: - @echo "Usage:" - @echo " make build [c=service] # Build images" - @echo " make up [c=service] # Start containers in detached mode" - @echo " make start [c=service] # Start existing containers" - @echo " make down [c=service] # Stop and remove containers" - @echo " make destroy # Stop and remove containers and volumes" - @echo " make stop [c=service] # Stop containers" - @echo " make logs [c=service] # Tail logs of containers" - @echo " make ps # List containers" - @echo " make help # Show this help" - -.PHONY: up build start stop down destroy logs ps db-shell help diff --git a/manage.py b/manage.py deleted file mode 100644 index 252b26c..0000000 --- a/manage.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python -import os -import sys - - -def main(): - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pong.settings') - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - -if __name__ == '__main__': - main() diff --git a/pong/__init__.py b/pong/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pong/asgi.py b/pong/asgi.py deleted file mode 100644 index 9c90f25..0000000 --- a/pong/asgi.py +++ /dev/null @@ -1,39 +0,0 @@ -# /pong/asgi.py - -""" -ASGI config for pong project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ -""" - -import os -import django -import logging - -logger = logging.getLogger(__name__) - -logger.debug("Setting default DJANGO_SETTINGS_MODULE to 'pong.settings'") -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pong.settings') - -logger.debug("Initializing Django setup") -django.setup() - -from django.core.asgi import get_asgi_application -from channels.routing import ProtocolTypeRouter, URLRouter -from channels.auth import AuthMiddlewareStack -import pong.game.routing - -logger.debug("Configuring ProtocolTypeRouter") -application = ProtocolTypeRouter({ - "http": get_asgi_application(), - "websocket": AuthMiddlewareStack( - URLRouter( - pong.game.routing.websocket_urlpatterns - ) - ), -}) - -logger.info("ASGI application configurée et prête à accepter les connexions") diff --git a/pong/game/__init__.py b/pong/game/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pong/game/consumers.py b/pong/game/consumers.py deleted file mode 100644 index bf8fb73..0000000 --- a/pong/game/consumers.py +++ /dev/null @@ -1,465 +0,0 @@ -import json -from channels.generic.websocket import AsyncWebsocketConsumer -from asgiref.sync import sync_to_async -from django.contrib.auth.models import User -from channels.db import database_sync_to_async -from .matchmaking import match_maker -from .tournament import tournament_match_maker -import logging - -logger = logging.getLogger(__name__) - -class GameConsumer(AsyncWebsocketConsumer): - async def connect(self): - try: - await self.accept() - self.game = None - logger.info("User connected via WebSocket") - except Exception as e: - logger.error(f"Error during WebSocket connection: {str(e)}") - - async def receive(self, text_data): - try: - logger.debug(f"Received data: {text_data}") - data = json.loads(text_data) - message_type = data.get('type') - - if message_type == 'authenticate': - await self.authenticate(data.get('token')) - elif message_type == 'authenticate2': - await self.authenticate2(data.get('token_1'), data.get('token_2')) - elif message_type == 'authenticate3': - await self.authenticate3(data.get('token')) - elif message_type == 'key_press': - if self.game: - await self.game.handle_key_press(self, data.get('key')) - else: - await match_maker.handle_key_press(self, data.get('key')) - else: - logger.warning(f"Received unknown message type: {message_type}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Unknown message type'})) - except json.JSONDecodeError as e: - logger.error(f"JSON decode error: {str(e)} - Data received: {text_data}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Invalid JSON format'})) - except Exception as e: - logger.error(f"Error in WebSocket receive: {str(e)}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'})) - - async def authenticate(self, token): - if not token: - logger.error("Token is None, authentication cannot proceed") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Token is missing'})) - return - try: - user = await self.get_user_from_token(token) - if user: - self.user = user - await self.send(text_data=json.dumps({'type': 'authenticated'})) - logger.info(f"User {self.user} authenticated") - await self.join_waiting_room() - else: - logger.warning(f"Authentication failed for token: {token}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed'})) - except Exception as e: - logger.error(f"Error during authentication: {str(e)}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'})) - - async def authenticate2(self, token_1, token_2): - try: - user = await self.get_user_from_token(token_1) - if user: - self.user = user - await self.send(text_data=json.dumps({'type': 'authenticated'})) - logger.info(f"User {self.user} authenticated with token_1") - - user2 = await self.get_user_from_token2(token_2) - if user2: - self.user2 = user2 - await self.send(text_data=json.dumps({'type': 'authenticated'})) - logger.info(f"User {self.user2} authenticated with token_2") - await match_maker.create_game(self, None, True) - else: - logger.warning(f"Authentication failed for token_2: {token_2}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed for user 2'})) - else: - logger.warning(f"Authentication failed for token_1: {token_1}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed for user 1'})) - except Exception as e: - logger.error(f"Error during dual authentication: {str(e)}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'})) - - async def authenticate3(self, token): - try: - user = await self.get_user_from_token(token) - if user: - self.user = user - await self.send(text_data=json.dumps({'type': 'authenticated'})) - logger.info(f"User {self.user} authenticated for tournament") - await self.join_tournament_waiting_room() - else: - logger.warning(f"Authentication failed for token: {token}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed'})) - except Exception as e: - logger.error(f"Error during tournament authentication: {str(e)}") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'})) - - @database_sync_to_async - def get_user_from_token(self, token): - try: - user = User.objects.filter(auth_token=token).first() - logger.debug(f"User found: {user} for token: {token}") - return user - except User.DoesNotExist: - logger.warning(f"User not found for token: {token}") - return None - - @database_sync_to_async - def get_user_from_token2(self, token): - try: - user2 = User.objects.filter(auth_token=token).first() - logger.debug(f"User2 found: {user2} for token: {token}") - return user2 - except User.DoesNotExist: - logger.warning(f"User not found for token_2: {token}") - return None - - async def join_waiting_room(self): - logger.info("Joining waiting room") - await self.send(text_data=json.dumps({'type': 'waiting_room'})) - await match_maker.add_player(self) - - async def join_tournament_waiting_room(self): - logger.info("Joining tournament waiting room") - await tournament_match_maker.add_player(self) - - async def disconnect(self, close_code): - try: - if self.game: - await self.game.end_game(disconnected_player=self) - await match_maker.remove_player(self) - await tournament_match_maker.remove_player(self) - logger.info(f"User {self.user.username if hasattr(self, 'user') else 'Unknown'} disconnected") - except Exception as e: - logger.error(f"Error during WebSocket disconnection: {str(e)}") - - async def set_game(self, game): - logger.info(f"Setting game: {game}") - self.game = game - -###################################################################CHAT################################################################### -class ChatConsumer(AsyncWebsocketConsumer): - async def connect(self): - - try: - # Récupérer le nom de la room à partir de l'URL - self.room_group_name = self.scope['url_route']['kwargs']['room_name'] - - # Accepter la connexion WebSocket - await self.accept() - # Ajouter l'utilisateur au groupe (room) - await self.channel_layer.group_add( - self.room_group_name, - self.channel_name - ) - - self.username = self.scope['user'].username # Assurez-vous d'avoir un utilisateur lié à la connexion - logger.info(f"Connexion de l'utilisateur {self.username} à la room {self.room_group_name}") - # Ajouter l'utilisateur à son propre groupe personnel (pour messages directs) - - - except Exception as e: - logger.error(f"Erreur lors de la connexion WebSocket: {str(e)}") - - async def disconnect(self, close_code): - try: - # Retirer l'utilisateur du groupe (room) - await self.channel_layer.group_discard( - self.room_group_name, - self.channel_name - ) - - # Retirer l'utilisateur de son groupe personnel - await self.channel_layer.group_discard( - f"user_{self.username}", - self.channel_name - ) - - # Envoyer un message indiquant que l'utilisateur a quitté la room - await self.chat_message( - 'chat_message', - self.user.username if hasattr(self, "user") else "Unknown", - f'{self.user.username if hasattr(self, "user") else "Unknown"} a quitté le chat', - self.room_group_name - ) - logger.info(f"{self.user.username if hasattr(self, 'user') else 'Unknown'} déconnecté de la room {self.room_group_name}") - - except Exception as e: - logger.error(f"Erreur lors de la déconnexion WebSocket: {str(e)}") - - async def receive(self, text_data): - try: - # Convertir les données JSON reçues en dictionnaire Python - data = json.loads(text_data) - message_type = data.get('type') - username = data.get('username') - message = data.get('message', None) - target_user = data.get('target_user', None) - - logger.info(f"Message reçu: {data}") - - if not username: - logger.error(f"Username manquant dans le message: {data}") - await self.chat_message('error', 'server', 'Username is missing', self.room_group_name) - return - - # Gestion des différents types de messages - if message_type == 'authenticate': - logger.info(f"Authentification demandée pour {username}") - await self.authenticate(data.get('token'), username) - return - - elif message_type == 'chat_message': - logger.info(f"Message de chat envoyé par {username}: {message}") - await self.chat_message('chat_message', username, message, self.room_group_name) - - elif message_type == 'block_user': - logger.info(f"{username} tente de bloquer {target_user}") - await self.handle_block_user(data) - - elif message_type == 'invite': - await self.handle_invite_user(data) - - elif message_type == 'invite_response': - await self.handle_invite_response(data) - - else: - logger.warning(f"Type de message non géré: {message_type}") - await self.chat_message('error', 'server', f"Unhandled message type: {message_type}", self.room_group_name) - - except json.JSONDecodeError as e: - logger.error(f"Erreur de décodage JSON : {str(e)} - Données reçues : {text_data}") - await self.chat_message('error', 'server', 'Invalid JSON format', self.room_group_name) - - except Exception as e: - logger.error(f"Erreur lors de la réception du message: {str(e)}") - await self.chat_message('error', 'server', 'Internal server error', self.room_group_name) - - async def chat_message(self, message_type, username, message, room): - """ - Fonction générale pour envoyer tout type de message via WebSocket à tous les utilisateurs dans la room. - """ - logger.info(f"Envoi d'un message de type {message_type} de {username} dans la room {room}") - - # Utilisation de channel_layer pour envoyer le message à tout le groupe (room) - await self.channel_layer.group_send( - room, - { - 'type': 'send_group_message', # Nom de la méthode qui va gérer ce message - 'username': username, - 'message': message, - 'room': room - } - ) - - async def send_group_message(self, event): - """ - Cette fonction est appelée par channel_layer pour envoyer des messages à tous les utilisateurs dans une room. - """ - message = event['message'] - username = event.get('username', 'Anonyme') - room = event.get('room', 'unknown') - - logger.info(f"Diffusion d'un message de {username} à la room {room}: {message}") - - # Envoi du message à chaque utilisateur dans la room via WebSocket - await self.send(text_data=json.dumps({ - 'type': 'chat_message', # Le type de message qui sera renvoyé au client - 'username': username, - 'message': message, - 'room': room - })) - - async def handle_block_user(self, data): - username = data['username'] - target_user = data['target_user'] - - logger.info(f"handle_block_user appelé avec : {data}") - - if target_user == username: - logger.warning(f"{username} a tenté de se bloquer lui-même.") - await self.send(text_data=json.dumps({'type': 'error', 'message': 'You cannot block yourself'})) - return - - logger.info(f"{username} a bloqué {target_user}") - - # Utilisation correcte de l' f-string pour inclure la valeur de target_user - await self.send(text_data=json.dumps({ - 'type': 'block_user', - 'message': f'Vous avez bloqué les messages de {target_user}' - })) - - async def handle_invite_user(self, data): - # Récupération des informations de l'invitation - inviter = data.get('username') - target_user = data.get('target_user') - room = data.get('room') - - # Validation des paramètres - if not inviter: - logger.error("Invitant manquant dans le message d'invitation") - await self.chat_message('error', 'server', 'Invitant manquant', self.room_group_name) - return - - if not target_user: - logger.error("Utilisateur cible manquant dans le message d'invitation") - await self.chat_message('error', 'server', 'Utilisateur cible manquant', self.room_group_name) - return - - if not room: - logger.error("Room manquante dans le message d'invitation") - await self.chat_message('error', 'server', 'Room manquante', self.room_group_name) - return - - logger.info(f"Invitation envoyée de {inviter} à {target_user} dans la room {room}") - await self.chat_message('chat_message', 'server', f'{inviter} a invité {target_user} à rejoindre une partie {room}', room) - - # Envoi de l'invitation - await self.channel_layer.group_send( - room, - { - 'type': 'invite', - 'inviter': inviter, - 'target_user': target_user, - 'room': room, - 'message': f'{inviter} vous a invité à rejoindre la room {room}.' - } - ) - - async def handle_invite_response(self, data): - inviter = data.get('inviter') - username = data.get('username') # L'utilisateur invité qui répond - response = data.get('response') - room = data.get('room') - - logger.info(f"{username} a répondu '{response}' à l'invitation de {inviter}") - await self.chat_message('chat_message', 'server', f'{username} a répondu {response} à l\'invitation.', room) - - # Si la réponse est 'yes', informer l'invitant que l'invité a accepté - if response.lower() == 'yes': - try: - # Informer l'invitant que l'invitation a été acceptée - await self.channel_layer.group_send( - room, - { - 'type': 'invite_response', - 'inviter': inviter, - 'username': username, - 'response': response, - 'room': room, - 'message': f'{username} a accepté l\'invitation.' - } - ) - # Informer à la fois l'invité et l'invitant que le jeu va commencer - await self.channel_layer.group_send( - room, - { - 'type': 'start_quick_match', - 'inviter': inviter, - 'username': username, - 'message': 'La partie va démarrer pour vous deux.', - } - ) - except Exception as e: - logger.error(f"Error while sending invite response: {str(e)}") - await self.chat_message('error', 'server', f'Internal server error: {str(e)}', room) - - # Méthode appelée pour envoyer l'invitation à l'utilisateur invité (target_user) - async def invite(self, event): - inviter = event['inviter'] - message = event['message'] - room = event['room'] - target_user = event['target_user'] - logger.info(f"invite: Envoi de l'invitation à l'utilisateur via WebSocket. Inviter={inviter}, Room={room}, Message={message}") - - # Envoyer le message d'invitation via WebSocket - await self.send(text_data=json.dumps({ - 'type': 'invite', - 'inviter': inviter, - 'target_user': target_user, - 'message': message, - 'room': room - })) - - async def handle_invite_response(self, data): - inviter = data.get('inviter') - username = data.get('username') # L'utilisateur invité qui répond - response = data.get('response') - room = data.get('room') - - logger.info(f"{username} a répondu '{response}' à l'invitation de {inviter}") - await self.chat_message('chat_message', 'server', f'{username} a répondu {response} à l\'invitation.', room) - - # Envoi de la réponse directement à l'invitant dans la room - await self.channel_layer.group_send( - room, - { - 'type': 'invite_response', # Type de message 'invite_response' - 'inviter': inviter, - 'username': username, - 'room': room, - 'message': f'{username} a répondu {response} à l\'invitation.', - 'response': response # Ajout de la réponse 'yes' ou 'no' - } - ) - - async def invite_response(self, event): - message = event['message'] - response = event.get('response') - inviter = event.get('inviter') # Récupérer l'inviteur - - logger.info(f"invite_response: Envoi de la réponse à l'invitation via WebSocket. Message={message}, Response={response}, Inviter={inviter}") - - # Envoyer la réponse à l'invitation via WebSocket à l'invitant - await self.send(text_data=json.dumps({ - 'type': 'invite_response', - 'message': message, - 'response': response, - 'inviter': inviter - })) - - async def authenticate(self, token, username): - if not token: - logger.error("Token est manquant, l'authentification ne peut pas se poursuivre.") - await self.chat_message('error', 'server', 'Token is missing', self.room_group_name) - return - - logger.info(f"Tentative d'authentification avec le token: {token} pour l'utilisateur: {username}") - - try: - user = await self.get_user_from_token(token) - if user: - self.user = user - logger.info(f"Utilisateur {username} authentifié avec succès") - await self.chat_message('authenticated', username, 'Authentication successful', self.room_group_name) - - await self.channel_layer.group_add( - f"user_{self.username}", # Group name unique pour cet utilisateur - self.channel_name - ) - logger.info(f"Connexion de l'utilisateur {self.username} à son groupe personnel") - else: - logger.warning(f"Échec de l'authentification pour le token: {token}") - await self.chat_message('error', username, 'Authentication failed', self.room_group_name) - except Exception as e: - logger.error(f"Erreur lors de l'authentification : {str(e)}") - await self.chat_message('error', 'server', 'Internal server error', self.room_group_name) - - @sync_to_async - def get_user_from_token(self, token): - try: - user = User.objects.filter(auth_token=token).first() - logger.debug(f"Utilisateur trouvé : {user} pour le token : {token}") - return user - except User.DoesNotExist: - logger.warning(f"Utilisateur non trouvé pour le token : {token}") - return None \ No newline at end of file diff --git a/pong/game/game.py b/pong/game/game.py deleted file mode 100644 index 515dccd..0000000 --- a/pong/game/game.py +++ /dev/null @@ -1,240 +0,0 @@ -# /pong/game/game.py - -import json -import asyncio -import random -from datetime import datetime -from .utils import handle_game_data -from asgiref.sync import sync_to_async - - -class Game: - def __init__(self, game_id, player1, player2, localgame): - self.game_id = game_id - self.player1 = player1 - self.player2 = player2 - self.localgame = localgame - if self.localgame: - self.botgame = False - self.game_state = { - 'player1_name': player1.user.username, - 'player2_name': player1.user2.username, - 'player1_position': 150, - 'player2_position': 150, - 'ball_position': {'x': 390, 'y': 190}, - 'ball_velocity': {'x': random.choice([-5, 5]), 'y': random.choice([-5, 5])}, - 'player1_score': 0, - 'player2_score': 0, - 'game_text': '' - } - else: - self.botgame = player2 is None - self.game_state = { - 'player1_name': player1.user.username, - 'player2_name': player2.user.username if player2 else 'BOT', - 'player1_position': 150, - 'player2_position': 150, - 'ball_position': {'x': 390, 'y': 190}, - 'ball_velocity': {'x': random.choice([-5, 5]), 'y': random.choice([-5, 5])}, - 'player1_score': 0, - 'player2_score': 0, - 'game-text': '' - } - self.speed = 1 - self.game_loop_task = None - self.ended = False - self.p1_mov = 0 - self.p2_mov = 0 - self.bt1 = 0 - self.bt2 = 0 - self.start_time = None - - async def start_game(self): - print(f"- Game #{self.game_id} STARTED") - self.game_loop_task = asyncio.create_task(self.game_loop()) - self.start_time = datetime.now() - print(f" Begin MATCH at: {self.start_time}") - - async def game_loop(self): - print(" In the game loop..") - x = 0 - while not self.ended: - if self.botgame: - x += 1 - if x == 60: - await self.update_bot_position() - x = 0 - await self.handle_pad_movement() - await self.update_game_state() - await self.send_game_state() - await asyncio.sleep(1/60) # Around 60 FPS - - async def update_bot_position(self): - future_ball_position = self.predict_ball_trajectory() - - target_y = future_ball_position['y'] - player2_position = self.game_state['player2_position'] - - # Adjusts bot position based on expected ball position - if player2_position < target_y < player2_position + 80: - pass #bot already placed - elif player2_position < target_y: - self.game_state['player2_position'] = min(player2_position + (50 * self.speed), 300) - elif player2_position + 80 > target_y: - self.game_state['player2_position'] = max(player2_position - (50 * self.speed), 0) - - def predict_ball_trajectory(self, steps=60): - - future_x = self.game_state['ball_position']['x'] - future_y = self.game_state['ball_position']['y'] - velocity_x = self.game_state['ball_velocity']['x'] - velocity_y = self.game_state['ball_velocity']['y'] - - for _ in range(steps): - future_x += velocity_x - future_y += velocity_y - - # Dealing with bounces off walls - if future_y <= 0 or future_y >= 300: - velocity_y = -velocity_y # Reverse the direction of vertical movement - - return {'x': future_x, 'y': future_y} - - async def update_game_state(self): - if self.ended: - return - # Update ball position - self.game_state['ball_position']['x'] += self.game_state['ball_velocity']['x'] - self.game_state['ball_position']['y'] += self.game_state['ball_velocity']['y'] - # Check for collisions with top and bottom walls - if self.game_state['ball_position']['y'] <= 10 or self.game_state['ball_position']['y'] >= 390: - self.game_state['ball_velocity']['y'] *= -1 - # Check for collisions with paddles - if self.game_state['ball_position']['x'] <= 20 and \ - self.game_state['player1_position'] - 10 <= self.game_state['ball_position']['y'] <= self.game_state['player1_position'] + 90: - if self.game_state['ball_velocity']['x'] < 0: - self.game_state['ball_velocity']['x'] *= -1 - self.bt1 += 1 - self.update_ball_velocity() - elif self.game_state['ball_position']['x'] >= 760 and \ - self.game_state['player2_position'] - 10 <= self.game_state['ball_position']['y'] <= self.game_state['player2_position'] + 90: - if self.game_state['ball_velocity']['x'] > 0: - self.game_state['ball_velocity']['x'] *= -1 - self.bt2 += 1 - self.update_ball_velocity() - # Check if some player won the game - if self.game_state['ball_position']['x'] <= 10: - self.game_state['player2_score'] += 1 - if self.game_state['player2_score'] > 2: - self.game_state['game_text'] = f"{self.game_state['player2_name']} WINS!" - await self.send_game_state() - await self.end_game() - self.reset_ball() - elif self.game_state['ball_position']['x'] >= 790: - self.game_state['player1_score'] += 1 - if self.game_state['player1_score'] > 2: - self.game_state['game_text'] = f"{self.game_state['player1_name']} WINS!" - await self.send_game_state() - await self.end_game() - self.reset_ball() - - def reset_ball(self): - self.game_state['ball_position'] = {'x': 390, 'y': 190} - self.game_state['ball_velocity'] = {'x': random.choice([-5, 5]), 'y': random.choice([-5, 5])} - self.speed = 1 - - def update_ball_velocity(self): - self.speed += 0.05 - if self.speed > 2: - self.speed = 2 - self.game_state['ball_velocity']['x'] *= self.speed - if self.game_state['ball_velocity']['x'] < -10: - self.game_state['ball_velocity']['x'] = -10 - elif self.game_state['ball_velocity']['x'] > 10: - self.game_state['ball_velocity']['x'] = 10 - self.game_state['ball_velocity']['y'] *= self.speed - if self.game_state['ball_velocity']['y'] < -10: - self.game_state['ball_velocity']['y'] = -10 - elif self.game_state['ball_velocity']['y'] > 10: - self.game_state['ball_velocity']['y'] = 10 - - async def send_game_state(self): - if self.ended: - return - message = json.dumps({ - 'type': 'game_state_update', - 'game_state': self.game_state - }) - await self.player1.send(message) - if not self.botgame: - if not self.localgame: - await self.player2.send(message) - - async def handle_key_press(self, player, key): - if self.ended: - return - if self.localgame: - if key == 'arrowup': - self.p2_mov = -1 - elif key == 'arrowdown': - self.p2_mov = 1 - elif key == 'w': - self.p1_mov = -1 - elif key == 's': - self.p1_mov = 1 - elif player == self.player1: - if key == 'arrowup': - self.p1_mov = -1 - elif key == 'arrowdown': - self.p1_mov = 1 - elif player == self.player2: - if key == 'arrowup': - self.p2_mov = -1 - elif key == 'arrowdown': - self.p2_mov = 1 - - async def handle_pad_movement(self): - if self.ended: - return - if self.p1_mov == -1: - self.game_state['player1_position'] = max(self.game_state['player1_position'] - (5 * self.speed), 0) - elif self.p1_mov == 1: - self.game_state['player1_position'] = min(self.game_state['player1_position'] + (5 * self.speed), 300) - if self.p2_mov == -1: - self.game_state['player2_position'] = max(self.game_state['player2_position'] - (5 * self.speed), 0) - elif self.p2_mov == 1: - self.game_state['player2_position'] = min(self.game_state['player2_position'] + (5 * self.speed), 300) - - async def end_game(self, disconnected_player=None): - if not self.ended: - self.ended = True - if self.game_loop_task: - self.game_loop_task.cancel() - print(f"- Game #{self.game_id} ENDED") - - end_time = datetime.now() - duration = (end_time - self.start_time).total_seconds() / 60 - - # Notify that one player left the game - if disconnected_player: - remaining_player = self.player2 if disconnected_player == self.player1 else self.player1 - disconnected_name = disconnected_player.user.username - message = json.dumps({ - 'type': 'player_disconnected', - 'player': disconnected_name - }) - if not self.botgame: - if not self.localgame: - await remaining_player.send(message) - # Notify both players that the game has ended - end_message = json.dumps({ - 'type': 'game_ended', - 'game_id': self.game_id - }) - await self.player1.send(end_message) - if not self.botgame: - if not self.localgame: - await self.player2.send(end_message) - await sync_to_async(handle_game_data)(self.game_state['player1_name'], self.game_state['player2_name'], - self.game_state['player1_score'], self.game_state['player2_score'], - self.bt1, self.bt2, duration, False, None) diff --git a/pong/game/matchmaking.py b/pong/game/matchmaking.py deleted file mode 100644 index 989a1dd..0000000 --- a/pong/game/matchmaking.py +++ /dev/null @@ -1,112 +0,0 @@ -# /pong/game/matchmaking.py - -import json -import asyncio -from .game import Game - -class MatchMaker: - def __init__(self): - self.waiting_players = [] - self.active_games = {} - self.matching_task = None - self.timer = 0 - self.botgame = False - - async def add_player(self, player): - if player not in self.waiting_players: - self.waiting_players.append(player) - print(f"User {player.user.username} joins the WAITING ROOM") - if not self.matching_task or self.matching_task.done(): - self.matching_task = asyncio.create_task(self.match_loop()) - - async def remove_player(self, player): - if player in self.waiting_players: - self.waiting_players.remove(player) - - for game in self.active_games.values(): - if player in [game.player1, game.player2]: - await game.end_game(disconnected_player=player) - del self.active_games[game.game_id] - break - - async def match_loop(self): - while True: - if len(self.waiting_players) >= 2: - player1 = self.waiting_players.pop(0) - player2 = self.waiting_players.pop(0) - print(f"*** MATCH FOUND: {player1.user.username} vs {player2.user.username}") - await self.create_game(player1, player2, False) - else: - await asyncio.sleep(1) - self.timer += 1 - # Waiting for more than 30s -> BOT game - if self.timer >= 15 and self.waiting_players: - player1 = self.waiting_players.pop(0) - print(f"*** MATCH FOUND: {player1.user.username} vs BOT") - self.botgame = True - self.timer = 0 - await self.create_bot_game(player1) - if not self.waiting_players: - break - - async def create_game(self, player1, player2, localgame): - game_id = len(self.active_games) + 1 - if localgame: - print(f"- Creating LOCAL game: #{game_id}") - else: - print(f"- Creating MATCH game: #{game_id}") - new_game = Game(game_id, player1, player2, localgame) - self.active_games[game_id] = new_game - await player1.set_game(new_game) - if not localgame: - await player2.set_game(new_game) - await self.notify_players(player1, player2, game_id, localgame) - asyncio.create_task(new_game.start_game()) - - async def create_bot_game(self, player1): - game_id = len(self.active_games) + 1 - print(f"- Creating BOT game: #{game_id}") - new_game = Game(game_id, player1, None, False) - self.active_games[game_id] = new_game - await player1.set_game(new_game) - await self.notify_players(player1, None, game_id, False) - asyncio.create_task(new_game.start_game()) - - async def notify_players(self, player1, player2, game_id, localgame): - if player2: - await player1.send(json.dumps({ - 'type': 'game_start', - 'game_id': game_id, - 'player1': player1.user.username, - 'player2': player2.user.username - })) - await player2.send(json.dumps({ - 'type': 'game_start', - 'game_id': game_id, - 'player1': player1.user.username, - 'player2': player2.user.username - })) - else: - if localgame: - await player1.send(json.dumps({ - 'type': 'game_start', - 'game_id': game_id, - 'player1': player1.user.username, - 'player2': player1.user2.username - })) - else: - await player1.send(json.dumps({ - 'type': 'game_start', - 'game_id': game_id, - 'player1': player1.user.username, - 'player2': 'BOT' - })) - - async def handle_key_press(self, player, key): - for game in self.active_games.values(): - if player in [game.player1, game.player2]: - await game.handle_key_press(player, key) - break - -# Instance of the class -match_maker = MatchMaker() diff --git a/pong/game/migrations/0001_initial.py b/pong/game/migrations/0001_initial.py deleted file mode 100644 index 2f03168..0000000 --- a/pong/game/migrations/0001_initial.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 5.0.7 on 2024-07-31 16:01 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='Player', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=100)), - ('total_match', models.PositiveSmallIntegerField(default=0)), - ('total_win', models.PositiveSmallIntegerField(default=0)), - ('p_win', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), - ('m_score_match', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), - ('m_score_adv_match', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), - ('best_score', models.PositiveSmallIntegerField(default=0)), - ('m_nbr_ball_touch', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), - ('total_duration', models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True)), - ('m_duration', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), - ('num_participated_tournaments', models.PositiveSmallIntegerField(default=0)), - ('num_won_tournaments', models.PositiveSmallIntegerField(default=0)), - ], - ), - migrations.CreateModel( - name='Tournoi', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=200)), - ('nbr_player', models.PositiveSmallIntegerField()), - ('date', models.DateField()), - ('winner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='game.player')), - ], - ), - migrations.CreateModel( - name='Match', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('score_player1', models.PositiveSmallIntegerField()), - ('score_player2', models.PositiveSmallIntegerField()), - ('nbr_ball_touch_p1', models.PositiveIntegerField()), - ('nbr_ball_touch_p2', models.PositiveIntegerField()), - ('duration', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), - ('date', models.DateField(auto_now_add=True)), - ('is_tournoi', models.BooleanField()), - ('player1', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='match_as_player1', to='game.player')), - ('player2', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='match_as_player2', to='game.player')), - ('winner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='won_matches', to='game.player')), - ('tournoi', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='matches', to='game.tournoi')), - ], - ), - ] diff --git a/pong/game/migrations/0002_alter_match_winner.py b/pong/game/migrations/0002_alter_match_winner.py deleted file mode 100644 index c53fc0b..0000000 --- a/pong/game/migrations/0002_alter_match_winner.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.1.1 on 2024-09-15 16:40 - -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'), - ), - ] diff --git a/pong/game/migrations/__init__.py b/pong/game/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pong/game/models.py b/pong/game/models.py deleted file mode 100644 index efdb580..0000000 --- a/pong/game/models.py +++ /dev/null @@ -1,78 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User -from django.core.exceptions import ValidationError -import logging - -logger = logging.getLogger(__name__) - -# Ajout d'un champ auth_token à la classe User -User.add_to_class('auth_token', models.CharField(max_length=100, null=True, blank=True, unique=True)) -logger.debug("Ajout du champ auth_token à la classe User") - -class Player(models.Model): - name = models.CharField(max_length=100) - total_match = models.PositiveSmallIntegerField(default=0) - total_win = models.PositiveSmallIntegerField(default=0) - p_win = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) - m_score_match = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) - m_score_adv_match = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) - best_score = models.PositiveSmallIntegerField(default=0) - m_nbr_ball_touch = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) - total_duration = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True) - m_duration = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) - num_participated_tournaments = models.PositiveSmallIntegerField(default=0) - num_won_tournaments = models.PositiveSmallIntegerField(default=0) - - def __str__(self): - return self.name - - def save(self, *args, **kwargs): - logger.info(f"Saving player: {self.name}") - super().save(*args, **kwargs) - logger.info(f"Player {self.name} saved successfully") - -class Tournoi(models.Model): - name = models.CharField(max_length=200) - nbr_player = models.PositiveSmallIntegerField() - date = models.DateField() - winner = models.ForeignKey('Player', on_delete=models.SET_NULL, null=True) - - def __str__(self): - return self.name - - def save(self, *args, **kwargs): - logger.info(f"Saving tournament: {self.name}") - super().save(*args, **kwargs) - logger.info(f"Tournament {self.name} saved successfully") - -class Match(models.Model): - player1 = models.ForeignKey('Player', related_name='match_as_player1', on_delete=models.CASCADE) - player2 = models.ForeignKey('Player', related_name='match_as_player2', on_delete=models.CASCADE) - score_player1 = models.PositiveSmallIntegerField() - score_player2 = models.PositiveSmallIntegerField() - winner = models.ForeignKey('Player', related_name='won_matches', on_delete=models.CASCADE, null=True) - nbr_ball_touch_p1 = models.PositiveIntegerField() - nbr_ball_touch_p2 = models.PositiveIntegerField() - duration = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) - date = models.DateField(auto_now_add=True) - is_tournoi = models.BooleanField() - tournoi = models.ForeignKey('Tournoi', related_name='matches', on_delete=models.SET_NULL, null=True) - - def clean(self): - logger.debug(f"Cleaning match: {self.player1.name} vs {self.player2.name}") - if self.score_player1 < 0 or self.score_player2 < 0: - raise ValidationError('Les scores doivent être positifs.') - if self.score_player1 > self.score_player2 and self.winner != self.player1: - raise ValidationError('Le gagnant ne correspond pas aux scores.') - if self.score_player2 > self.score_player1 and self.winner != self.player2: - raise ValidationError('Le gagnant ne correspond pas aux scores.') - super().clean() - - def save(self, *args, **kwargs): - logger.info(f"Saving match: {self.player1.name} vs {self.player2.name}") - self.clean() - super().save(*args, **kwargs) - logger.info(f"Match {self.player1.name} vs {self.player2.name} saved successfully") - - def __str__(self): - return f"{self.player1.name} vs {self.player2.name}" diff --git a/pong/game/routing.py b/pong/game/routing.py deleted file mode 100644 index 3c631ff..0000000 --- a/pong/game/routing.py +++ /dev/null @@ -1,15 +0,0 @@ -# /pong/game/routing.py -from django.urls import re_path -from . import consumers -import logging - -logger = logging.getLogger(__name__) - -logger.debug("Configuring WebSocket routing patterns") - -websocket_urlpatterns = [ - re_path(r'ws/game/$', consumers.GameConsumer.as_asgi(), name='game_ws'), - re_path(r'ws/chat/(?P\w+)/$', consumers.ChatConsumer.as_asgi()), -] - -logger.info("WebSocket routing patterns configured successfully") diff --git a/pong/game/templates/pong/tournament_waiting_room.html b/pong/game/templates/pong/tournament_waiting_room.html deleted file mode 100644 index dc09859..0000000 --- a/pong/game/templates/pong/tournament_waiting_room.html +++ /dev/null @@ -1,10 +0,0 @@ - -
-

Tournament Waiting Room

-

Players currently waiting: {{ players|length }}

-
    - {% for player in players %} -
  • {{ player }}
  • - {% endfor %} -
-
\ No newline at end of file diff --git a/pong/game/tournament.py b/pong/game/tournament.py deleted file mode 100644 index 4faeca0..0000000 --- a/pong/game/tournament.py +++ /dev/null @@ -1,49 +0,0 @@ -# /pong/game/tournament.py -import json -from django.template.loader import render_to_string -import logging - -logger = logging.getLogger(__name__) - -class TournamentMatchMaker: - def __init__(self): - self.waiting_players = [] - logger.debug("TournamentMatchMaker initialized with an empty waiting_players list") - - async def add_player(self, player): - if player not in self.waiting_players: - self.waiting_players.append(player) - logger.info(f"User {player.user.username} added to the TOURNAMENT WAITING ROOM") - await self.update_waiting_room() - else: - logger.warning(f"User {player.user.username} is already in the TOURNAMENT WAITING ROOM") - - async def remove_player(self, player): - if player in self.waiting_players: - self.waiting_players.remove(player) - logger.info(f"User {player.user.username} removed from the TOURNAMENT WAITING ROOM") - await self.update_waiting_room() - else: - logger.warning(f"Attempt to remove non-existent user {player.user.username} from the TOURNAMENT WAITING ROOM") - - async def update_waiting_room(self): - logger.debug("Updating TOURNAMENT WAITING ROOM") - html = self.generate_waiting_room_html() - for player in self.waiting_players: - await player.send(json.dumps({ - 'type': 'update_waiting_room', - 'html': html - })) - logger.info("TOURNAMENT WAITING ROOM updated and sent to all players") - - def generate_waiting_room_html(self): - logger.debug("Generating TOURNAMENT WAITING ROOM HTML") - context = { - 'players': [player.user.username for player in self.waiting_players] - } - html = render_to_string('pong/tournament_waiting_room.html', context) - logger.info("TOURNAMENT WAITING ROOM HTML generated successfully") - return html - -# Instance of the class -tournament_match_maker = TournamentMatchMaker() diff --git a/pong/game/urls.py b/pong/game/urls.py deleted file mode 100644 index f4bf6e2..0000000 --- a/pong/game/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -# /pong/game/urls.py - -from django.urls import path, include -from . import views -#from rest_framework.routers import DefaultRouter -from .views import match_list_json, player_list_json, tournoi_list_json - -urlpatterns = [ - path('', views.index, name='index'), - path('check_user_exists/', views.check_user_exists, name='check_user_exists'), - path('register_user/', views.register_user, name='register_user'), - path('authenticate_user/', views.authenticate_user, name='authenticate_user'), - path('web3/', views.read_data, name='read_data'), - path('api/match_list/', match_list_json, name='match_list_json'), - path('api/player_list/', player_list_json, name='player_list_json'), - path('api/tournoi_list/', tournoi_list_json, name='tournoi_list_json') -] diff --git a/pong/game/utils.py b/pong/game/utils.py deleted file mode 100644 index 6b0f565..0000000 --- a/pong/game/utils.py +++ /dev/null @@ -1,192 +0,0 @@ -import logging -from .models import Player, Tournoi, Match -from django.core.exceptions import ValidationError -from django.shortcuts import get_object_or_404 -from django.db.models import Max, Sum, F -from datetime import timedelta -from channels.db import database_sync_to_async - -logger = logging.getLogger(__name__) - -def handle_game_data(p1, p2, s_p1, s_p2, bt_p1, bt_2, dur, is_tournoi, name_tournament): - logger.info(f"Handling game data for players: {p1} vs {p2}") - try: - player_1 = get_or_create_player(p1) - player_2 = get_or_create_player(p2) - logger.debug(f"Players created or retrieved: {player_1}, {player_2}") - - create_match(player_1, player_2, s_p1, s_p2, bt_p1, bt_2, dur, is_tournoi, name_tournament) - logger.info("Match created successfully") - - update_player_statistics(p1) - update_player_statistics(p2) - logger.info("Player statistics updated") - - except Exception as e: - logger.error(f"Error in handle_game_data: {e}") - -def get_player_by_name(name): - logger.debug(f"Checking if player exists with name: {name}") - exists = Player.objects.filter(name=name).exists() - logger.debug(f"Player exists: {exists}") - return exists - -def get_player(name): - logger.debug(f"Retrieving player with name: {name}") - return Player.objects.get(name=name) - -def get_or_create_player(name): - logger.info(f"Getting or creating player with name: {name}") - player_exists = get_player_by_name(name) - if not player_exists: - player = create_player(name) - logger.info(f"Player created: {player}") - return player - else: - player = get_player(name) - logger.info(f"Player retrieved: {player}") - return player - -def create_player( - name, - total_match=0, - total_win=0, - p_win=None, - m_score_match=None, - m_score_adv_match=None, - best_score=0, - m_nbr_ball_touch=None, - total_duration=None, - m_duration=None, - num_participated_tournaments=0, - num_won_tournaments=0 -): - logger.info(f"Creating player: {name}") - player = Player( - name=name, - total_match=total_match, - total_win=total_win, - p_win=p_win, - m_score_match=m_score_match, - m_score_adv_match=m_score_adv_match, - best_score=best_score, - m_nbr_ball_touch=m_nbr_ball_touch, - total_duration=total_duration, - m_duration=m_duration, - num_participated_tournaments=num_participated_tournaments, - num_won_tournaments=num_won_tournaments - ) - player.save() - logger.info(f"Player {name} saved successfully") - return player - -def create_tournoi(name, nbr_player, date, winner): - logger.info(f"Creating tournament: {name}") - tournoi = Tournoi(name=name, nbr_player=nbr_player, date=date, winner=winner) - tournoi.save() - logger.info(f"Tournament {name} saved successfully") - return tournoi - -def create_match(player1, player2, score_player1, score_player2, nbr_ball_touch_p1, nbr_ball_touch_p2, duration, is_tournoi, tournoi): - logger.info(f"Creating match between {player1.name} and {player2.name}") - match = Match( - player1=player1, - player2=player2, - score_player1=score_player1, - score_player2=score_player2, - nbr_ball_touch_p1=nbr_ball_touch_p1, - nbr_ball_touch_p2=nbr_ball_touch_p2, - duration=duration, - is_tournoi=is_tournoi, - tournoi=tournoi - ) - - if score_player1 > score_player2: - match.winner = match.player1 - elif score_player2 > score_player1: - match.winner = match.player2 - else: - match.winner = None - - match.save() - logger.info(f"Match saved successfully with winner: {match.winner.name if match.winner else 'None'}") - return match - -def update_player_statistics(player_name): - logger.info(f"Updating statistics for player: {player_name}") - player = get_object_or_404(Player, name=player_name) - - matches_as_player1 = Match.objects.filter(player1=player) - matches_as_player2 = Match.objects.filter(player2=player) - - total_match = matches_as_player1.count() + matches_as_player2.count() - - if total_match == 0: - logger.warning(f"No matches found for player: {player_name}") - player.total_match = total_match - player.total_win = 0 - player.p_win = 0 - player.m_score_match = 0 - player.m_score_adv_match = 0 - player.best_score = 0 - player.m_nbr_ball_touch = 0 - player.total_duration = 0 - player.m_duration = 0 - player.num_participated_tournaments = 0 - player.num_won_tournaments = 0 - player.save() - logger.info(f"Player statistics reset for {player_name}") - return - - won_matches = Match.objects.filter(winner=player) - #part_tourn_as_p1 = Tournoi.objects.filter(matches__is_tournoi=True, matches__matches_as_player1=player) - #part_tourn_as_p2 = Tournoi.objects.filter(matches__is_tournoi=True, matches__matches_as_player2=player) - #won_tourn = Tournoi.objects.filter(winner=player) - - total_score = matches_as_player1.aggregate(Sum('score_player1'))['score_player1__sum'] or 0 - total_score += matches_as_player2.aggregate(Sum('score_player2'))['score_player2__sum'] or 0 - - total_score_adv = matches_as_player1.aggregate(Sum('score_player2'))['score_player2__sum'] or 0 - total_score_adv += matches_as_player2.aggregate(Sum('score_player1'))['score_player1__sum'] or 0 - - total_win = won_matches.count() - p_win = (total_win / total_match) * 100 - - m_score_match = total_score / total_match - m_score_adv_match = total_score_adv / total_match - - nbr_ball_touch = matches_as_player1.aggregate(Sum('nbr_ball_touch_p1'))['nbr_ball_touch_p1__sum'] or 0 - nbr_ball_touch += matches_as_player2.aggregate(Sum('nbr_ball_touch_p2'))['nbr_ball_touch_p2__sum'] or 0 - m_nbr_ball_touch = nbr_ball_touch / total_match - - total_duration = matches_as_player1.aggregate(Sum('duration'))['duration__sum'] or 0 - total_duration += matches_as_player2.aggregate(Sum('duration'))['duration__sum'] or 0 - m_duration = total_duration / total_match - - #total_tourn_p = part_tourn_as_p1.count() + part_tourn_as_p2.count() - #total_win_tourn = won_tourn.count() - #p_win_tourn = (total_win_tourn / total_tourn_p) * 100 if total_tourn_p else 0 - - best_score_as_player1 = matches_as_player1.aggregate(Max('score_player1'))['score_player1__max'] or 0 - best_score_as_player2 = matches_as_player2.aggregate(Max('score_player2'))['score_player2__max'] or 0 - best_score = max(best_score_as_player1, best_score_as_player2) - - player.total_match = total_match - player.total_win = total_win - player.p_win = p_win - player.m_score_match = m_score_match - player.m_score_adv_match = m_score_adv_match - player.best_score = best_score - player.m_nbr_ball_touch = m_nbr_ball_touch - player.total_duration = total_duration - player.m_duration = m_duration - # player.num_participated_tournaments = total_tourn_p - #player.num_won_tournaments = total_win_tourn - - player.save() - logger.info(f"Statistics updated for player: {player_name}") - -def get_player_p_win(player_name): - logger.debug(f"Getting win percentage for player: {player_name}") - player = get_object_or_404(Player, name=player_name) - return player.p_win diff --git a/pong/game/views.py b/pong/game/views.py deleted file mode 100644 index 22d057a..0000000 --- a/pong/game/views.py +++ /dev/null @@ -1,228 +0,0 @@ -# /pong/game/views.py - -from django.shortcuts import render -from django.core.exceptions import ObjectDoesNotExist -from .models import Player, Tournoi, Match -from .utils import create_player, create_tournoi, create_match -from django.http import JsonResponse -from django.contrib.auth.models import User -from django.contrib.auth import authenticate -from django.views.decorators.csrf import csrf_exempt -from rest_framework import viewsets -from django.db import transaction, IntegrityError - -import json -import uuid -import logging - -logger = logging.getLogger(__name__) - -def index(request): - logger.info("Accessing index view") - return render(request, 'index.html') - -@csrf_exempt -def check_user_exists(request): - if request.method == 'POST': - logger.info("POST request received for checking user existence") - data = json.loads(request.body) - username = data.get('username') - if User.objects.filter(username=username).exists(): - logger.info(f"User {username} exists") - return JsonResponse({'exists': True}) - logger.info(f"User {username} does not exist") - return JsonResponse({'exists': False}) - logger.warning("Invalid request method for check_user_exists") - return JsonResponse({'error': 'Invalid request method'}, status=400) - -@csrf_exempt -def register_user(request): - if request.method == 'POST': - try: - logger.info("Received POST request for user registration") - data = json.loads(request.body) - username = data.get('username') - password = data.get('password') - - logger.info(f"Attempting to register user: {username}") - - if not username or not password: - logger.warning("Username or password not provided") - return JsonResponse({'registered': False, 'error': 'Username and password are required'}, status=400) - - with transaction.atomic(): - user_exists = User.objects.select_for_update().filter(username=username).exists() - - if user_exists: - logger.warning(f"User {username} already exists") - return JsonResponse({'registered': False, 'error': 'User already exists'}, status=409) - - user = User.objects.create_user(username=username, password=password) - token = get_or_create_token(user) - logger.info(f"User {username} registered successfully") - return JsonResponse({'registered': True, 'token': token}) - - except json.JSONDecodeError as e: - logger.error(f"JSON decode error: {str(e)}") - return JsonResponse({'error': 'Invalid JSON data'}, status=400) - - except IntegrityError: - logger.error(f"IntegrityError: User {username} already exists") - return JsonResponse({'registered': False, 'error': 'User already exists'}, status=409) - - except Exception as e: - logger.error(f"Error in register_user: {str(e)}") - return JsonResponse({'error': f'Internal Server Error: {str(e)}'}, status=500) - - logger.warning("Invalid request method for register_user") - return JsonResponse({'error': 'Invalid request method'}, status=405) - -def get_or_create_token(user): - logger.info(f"Generating or retrieving token for user: {user.username}") - if not user.auth_token: - while True: - token = str(uuid.uuid4()) - if not User.objects.filter(auth_token=token).exists(): - user.auth_token = token - user.save() - logger.info(f"Token generated for user {user.username}: {token}") - break - return user.auth_token - -@csrf_exempt -def authenticate_user(request): - if request.method == 'POST': - try: - logger.info("Received POST request for user authentication") - data = json.loads(request.body) - username = data.get('username', '') - password = data.get('password', '') - user = authenticate(username=username, password=password) - if user is not None: - token = get_or_create_token(user) - logger.info(f"User {username} authenticated successfully") - return JsonResponse({'authenticated': True, 'token': token, 'user_id': user.id}) - else: - logger.warning(f"Authentication failed for user {username}") - return JsonResponse({'authenticated': False}, status=401) - except Exception as e: - logger.error(f"Error in authenticate_user: {str(e)}") - return JsonResponse({'error': str(e)}, status=500) - else: - logger.warning("Invalid request method for authenticate_user") - return JsonResponse({'error': 'Method not allowed'}, status=405) - -def match_list_json(request): - logger.info("Fetching match list") - matches = Match.objects.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' - )) - } - logger.info(f"Match list fetched successfully: {len(data['matches'])} matches found") - return JsonResponse(data) - -def player_list_json(request): - logger.info("Fetching player list") - players = Player.objects.all() - - 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' - )) - } - logger.info(f"Player list fetched successfully: {len(data['players'])} players found") - return JsonResponse(data) - -def tournoi_list_json(request): - logger.info("Fetching tournoi list") - tournois = Tournoi.objects.all() - - data = { - 'tournois': list(tournois.values( - 'id', 'name', 'nbr_player', 'date', 'winner' - )) - } - logger.info(f"Tournoi list fetched successfully: {len(data['tournois'])} tournois found") - return JsonResponse(data) - -def tournoi_list_json(request): - tournois = Tournoi.objects.all() - - data = { - 'tournois': list(tournois.values( - 'id', 'name', 'nbr_player', 'date', 'winner' - )) - } - return JsonResponse(data) - -from web3 import Web3 - -provider = Web3.HTTPProvider("https://sepolia.infura.io/v3/60e51df7c97c4f4c8ab41605a4eb9907") -web3 = Web3(provider) -eth_gas_price = web3.eth.gas_price/1000000000 -print(eth_gas_price) - -contract_address = "0x078D04Eb6fb97Cd863361FC86000647DC876441B" -contract_abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"uint256","name":"_timecode","type":"uint256"},{"internalType":"uint256","name":"_participantCount","type":"uint256"},{"internalType":"string[]","name":"_playerPseudonyms","type":"string[]"},{"internalType":"string[]","name":"_finalOrder","type":"string[]"}],"name":"addTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllTournaments","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"timecode","type":"uint256"},{"internalType":"uint256","name":"participantCount","type":"uint256"},{"internalType":"string[]","name":"playerPseudonyms","type":"string[]"},{"internalType":"string[]","name":"finalOrder","type":"string[]"}],"internalType":"struct PongTournament.Tournament[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getTournament","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"timecode","type":"uint256"},{"internalType":"uint256","name":"participantCount","type":"uint256"},{"internalType":"string[]","name":"playerPseudonyms","type":"string[]"},{"internalType":"string[]","name":"finalOrder","type":"string[]"}],"internalType":"struct PongTournament.Tournament","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tournamentCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tournaments","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"timecode","type":"uint256"},{"internalType":"uint256","name":"participantCount","type":"uint256"}],"stateMutability":"view","type":"function"}] - -contract = web3.eth.contract(address=contract_address, abi=contract_abi) - -def read_data(request): - # Créer une instance du contrat - - # Appeler une fonction du contrat pour obtenir tous les tournois - tournaments = contract.functions.getAllTournaments().call() - - # Afficher les résultats - json_data = [] - for tournament in tournaments: - tournament_data = [] - for item in tournament: - print(f"{item}") - tournament_data.append(item) - json_data.append(tournament_data) - - # Retourner le JSON comme réponse HTTP - # print(f"Tournament ID: {tournament[0]}") - # print(f"Name: {tournament[1]}") - # print(f"Timecode: {tournament[2]}") - # print(f"Participant Count: {tournament[3]}") - # print(f"Player Pseudonyms: {', '.join(tournament[4])}") - # print(f"Final Order: {', '.join(tournament[5])}") - print("-----------------------------") - return JsonResponse(json_data, safe=False) - - -def write_data(request): - # addTournament(string,uint256,uint256,string[],string[]) - - # # Configuration de la transaction pour la fonction store - # account = "0x66CeBE2A1F7dae0F6AdBAad2c15A56A9121abfEf" - # private_key = "beb16ee3434ec5abec8b799549846cc04443c967b8d3643b943e2e969e7d25be" - - # nonce = web3.eth.get_transaction_count(account) - # transaction = contract.functions.addTournament("test",1721830559,6,["aaudeber", "tlorne", "ocassany", "yestello", "jcheca", "toto"],["toto", "jcheca", "yestello", "tlorne", "ocassany", "aaudeber"]).build_transaction({ - # 'chainId': 11155111, # ID de la chaîne Sepolia - # 'gas': 2000000, - # 'gasPrice': web3.to_wei(eth_gas_price, 'gwei'), - # 'nonce': nonce - # }) - - # # Signature de la transaction - # signed_txn = web3.eth.account.sign_transaction(transaction, private_key) - - # # Envoi de la transaction - # tx_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction) - # print("Transaction hash:", web3.to_hex(tx_hash)) - - # # Attente de la confirmation de la transaction - # tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) - # print("Transaction receipt:", tx_receipt) - print("-----------------------------") diff --git a/pong/settings.py b/pong/settings.py deleted file mode 100644 index af52863..0000000 --- a/pong/settings.py +++ /dev/null @@ -1,212 +0,0 @@ -# /pong/settings.py - -""" -Django settings for pong project. - -Generated by 'django-admin startproject' using Django 3.2. -""" - -import os -import logging.config -from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '12345678' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = ['*'] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'channels', - 'pong.game', - 'rest_framework' -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'pong.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'pong', 'static')], # Ensure templates are found - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -ASGI_APPLICATION = 'pong.asgi.application' - -# Database -# https://docs.djangoproject.com/en/3.2/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.getenv('DB_NAME'), - 'USER': os.getenv('DB_USER'), - 'PASSWORD': os.getenv('DB_PASSWORD'), - 'HOST': os.getenv('DB_HOST'), - 'PORT': '5432', - } -} - -# Password validation -# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -# Internationalization -# https://docs.djangoproject.com/en/3.2/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - -STATIC_URL = '/static/' -STATICFILES_DIRS = [os.path.join(BASE_DIR, 'pong/static')] -STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') - -# Default primary key field type -# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - -# Channels -# Define the channel layers for WebSockets -# Define the channel layers for WebSockets -CHANNEL_LAYERS = { - 'default': { - 'BACKEND': 'channels.layers.InMemoryChannelLayer', - }, -} - -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'json': { - '()': 'pythonjsonlogger.jsonlogger.JsonFormatter', - 'format': '%(asctime)s %(levelname)s %(name)s %(module)s %(process)d %(thread)d %(message)s', - }, - 'default': { - 'format': '[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s', - }, - 'verbose': { - 'format': '[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s [%(process)d:%(thread)d]', - }, - 'simple': { - 'format': '%(levelname)s %(message)s', - }, - }, - 'filters': { - 'require_debug_true': { - '()': 'django.utils.log.RequireDebugTrue', - }, - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse', - }, - }, - 'handlers': { - 'file': { - 'level': 'INFO', - 'class': 'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(BASE_DIR, 'logs/django.log'), - 'formatter': 'json', - 'maxBytes': 1024 * 1024 * 5, # 5 MB - 'backupCount': 5, - }, - 'error_file': { - 'level': 'ERROR', - 'class': 'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(BASE_DIR, 'logs/django_errors.log'), - 'formatter': 'json', - 'maxBytes': 1024 * 1024 * 5, # 5 MB - 'backupCount': 5, - }, - 'console': { - 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'verbose', - 'filters': ['require_debug_true'], - }, - 'mail_admins': { - 'level': 'ERROR', - 'class': 'django.utils.log.AdminEmailHandler', - 'filters': ['require_debug_false'], - }, - }, - 'loggers': { - 'django': { - 'handlers': ['file', 'console', 'mail_admins'], - 'level': 'DEBUG', - 'propagate': True, - }, - 'django.request': { - 'handlers': ['error_file', 'mail_admins'], - 'level': 'ERROR', - 'propagate': False, - }, - 'django.security': { - 'handlers': ['error_file', 'mail_admins'], - 'level': 'ERROR', - 'propagate': False, - }, - }, - 'root': { - 'handlers': ['console', 'file'], - 'level': 'INFO', - }, -} diff --git a/pong/static/burger.js b/pong/static/burger.js deleted file mode 100644 index a98343c..0000000 --- a/pong/static/burger.js +++ /dev/null @@ -1,397 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - - const menuButton = document.querySelector('.burger-menu'); - const dropdownMenu = document.getElementById('dropdown-menu'); - - const playerList = document.getElementById('player-list'); - const matchList = document.getElementById('match-list'); - const tournoiList = document.getElementById('tournoi-list'); - const blockchainList = document.getElementById('blockchain-list'); - - const logo = document.querySelector('.logo'); - - menuButton.addEventListener('click', toggleMenu); - - function toggleMenu() { - console.log('Menu toggled'); - if (dropdownMenu.style.display === "block") { - dropdownMenu.style.display = "none"; - hideAllTables(); - } else { - dropdownMenu.style.display = "block"; - } - } - - function hideAllTables(){ - if (playerList) playerList.style.display = 'none'; - if (matchList) matchList.style.display = 'none'; - if (tournoiList) tournoiList.style.display = 'none'; - if (blockchainList) blockchainList.style.display = 'none'; - logo.style.display = 'block'; - } - - const links = document.querySelectorAll('#dropdown-menu a'); - - links.forEach(link => { - link.addEventListener('click', (event) => { - event.preventDefault(); - const tableId = link.getAttribute('data-table'); - showTable(tableId); - }); - }); - - function showTable(tableId) { - hideAllTables(); - logo.style.display = 'none'; - - if (tableId === 'player-list') { - playerList.style.display = 'block'; - fetchPlayers(); - } else if (tableId === 'match-list') { - matchList.style.display = 'block'; - fetchMatches(); - } else if (tableId === 'tournoi-list') { - tournoiList.style.display = 'block'; - fetchTournois(); - } else if (tableId === 'blockchain-list') { - console.log('Opening external page in a new tab'); - window.open('https://sepolia.etherscan.io/address/0x078d04eb6fb97cd863361fc86000647dc876441b', '_blank'); - } - - if (dropdownMenu) { - dropdownMenu.style.display = 'none'; - } - } - - function fetchMatches() { - console.log('Fetching matches...'); - 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(){ - console.log('Fetching players...'); - 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 fetchTournois(){ - console.log('Fetching tournois...'); - fetch('/api/tournoi_list/') - .then(response => response.json()) - .then(data => { - if (data.tournois) { - displayTournois(data.tournois); - } - }) - .catch(error => console.error('Error fetching match data:', error)); - } - - function displayMatches(matches) { - console.log('Displaying matches:'); - const matchListBody = document.querySelector('#match-list tbody'); - matchListBody.innerHTML = ''; - - if (matches.length != 0) { - matches.forEach(match => { - const row = document.createElement('tr'); - row.innerHTML = ` - ${match.id} - ${match.player1__name} - ${match.player2__name} - ${match.score_player1} - ${match.score_player2} - ${match.winner__name} - ${match.nbr_ball_touch_p1} - ${match.nbr_ball_touch_p2} - ${match.duration} - ${match.date} - ${match.is_tournoi} - ${match.tournoi__name} - `; - matchListBody.appendChild(row); - }); - } else { - row.innerHTML = ` - No matches found. - `; - matchListBody.appendChild(row); - } - } - - function displayPlayers(players) { - console.log('Displaying players:'); - const playersListBody = document.querySelector('#player-list tbody'); - playersListBody.innerHTML = ''; - - if (players.length != 0) { - players.forEach(player => { - const row = document.createElement('tr'); - row.innerHTML = ` - ${player.id} - ${player.name} - ${player.total_match} - ${player.total_win} - ${player.p_win} - ${player.m_score_match} - ${player.m_score_adv_match} - ${player.best_score} - ${player.m_nbr_ball_touch} - ${player.total_duration} - ${player.m_duration} - ${player.num_participated_tournaments} - ${player.num_won_tournaments} - `; - playersListBody.appendChild(row); - }); - } else { - row.innerHTML = ` - No matches found. - ` - playersListBody.appendChild(row); - } - } - - function displayTournois(tournois) { - console.log('Displaying tournois:'); - const tournoisListBody = document.querySelector('#tournoi-list tbody'); - tournoisListBody.innerHTML = ''; - - if (tournois.length != 0) { - tournois.forEach(tournoi => { - const row = document.createElement('tr'); - row.innerHTML = ` - ${tournoi.id} - ${tournoi.name} - ${tournoi.nbr_player} - ${tournoi.date} - ${tournoi.winner.name} - `; - tournoisListBody.appendChild(row); - }); - } else { - row.innerHTML = ` - No matches found. - ` - tournoisListBody.appendChild(row); - } - - } - - document.getElementById('search-player').addEventListener('input', filterPlayers); - document.getElementById('search-match-player').addEventListener('input', filterMatches); - document.getElementById('search-match-date').addEventListener('input', filterMatches); - - function filterPlayers() { - const searchValue = document.getElementById('search-player').value.toLowerCase(); - const playersListBody = document.querySelector('#player-list tbody'); - const rows = playersListBody.getElementsByTagName('tr'); - - for (let i = 0; i < rows.length; i++) { - const nameCell = rows[i].getElementsByTagName('td')[1]; - if (nameCell) { - const nameValue = nameCell.textContent || nameCell.innerText; - if (nameValue.toLowerCase().indexOf(searchValue) > -1 ) { - rows[i].style.display = ''; - } else { - rows[i].style.display = 'none'; - } - } - } - } - - function filterMatches() { - const playerSearchValue = document.getElementById('search-match-player').value.toLowerCase(); - const dateSearchValue = document.getElementById('search-match-date').value; - const matchListBody = document.querySelector('#match-list tbody'); - const rows = matchListBody.getElementsByTagName('tr'); - - for (let i = 0; i < rows.length; i++) { - const player1Cell = rows[i].getElementsByTagName('td')[1]; - const player2Cell = rows[i].getElementsByTagName('td')[2]; - const dateCell = rows[i].getElementsByTagName('td')[9]; - - let playerMatch = true; - if (playerSearchValue) { - const player1Value = player1Cell.textContent || player1Cell.innerText; - const player2Value = player2Cell.textContent || player2Cell.innerText; - playerMatch = player1Value.toLowerCase().indexOf(playerSearchValue) > -1 || - player2Value.toLowerCase().indexOf(playerSearchValue) > -1; - } - - let dateMatch = true; - if (dateSearchValue) { - const dateValue = dateCell.textContent || dateCell.innerText; - dateMatch = dateValue.startsWith(dateSearchValue); - } - - if (playerMatch && dateMatch) { - rows[i].style.display = ''; - } else { - rows[i].style.display = 'none'; - } - } - } - - document.getElementById('generate-player-chart').addEventListener('click', generatePlayerChart); - document.getElementById('generate-match-chart').addEventListener('click', generateMatchLinePlot); - - function generatePlayerChart() { - - if (document.getElementById('player-chart').style.display === 'block'){ - document.getElementById('player-chart').style.display = 'none'; - return ; - } - - if (logo.style.display === 'block'){ - logo.style.display = 'none'; - } - const rows = document.querySelectorAll('#player-list tbody tr'); - const playerNames = []; - const totalMatches = []; - const totalWins = []; - - rows.forEach(row => { - const cells = row.getElementsByTagName('td'); - playerNames.push(cells[1].innerText); - totalMatches.push(parseInt(cells[2].innerText)); - totalWins.push(parseInt(cells[3].innerText)); - }); - - const ctx = document.getElementById('player-chart').getContext('2d'); - document.getElementById('player-chart').style.display = 'block'; - new Chart(ctx, { - type: 'bar', - data: { - labels: playerNames, - datasets: [ - { label: 'Total Matches', data: totalMatches, backgroundColor: 'rgba(75, 192, 192, 0.6)' }, - { label: 'Total Wins', data: totalWins, backgroundColor: 'rgba(54, 162, 235, 0.6)' }, - ] - }, - options: { - scales: { - x: { - ticks: { - color: '#00ffff' - } - }, - y: { - beginAtZero: true, - ticks: { - color: '#00ffff' - } - } - } - } - }); - } - - function generateMatchLinePlot() { - - if (document.getElementById('match-chart').style.display === 'block'){ - document.getElementById('match-chart').style.display = 'none'; - return ; - } - - const rows = document.querySelectorAll('#match-list tbody tr'); - const playerWins = {}; - const dates = []; - - rows.forEach(row => { - const cells = row.getElementsByTagName('td'); - const winner = cells[5].innerText; - const date = cells[9].innerText; - - if (!dates.includes(date)) { - dates.push(date); - } - - if (!playerWins[winner]) { - playerWins[winner] = []; - } - - let existingEntry = playerWins[winner].find(entry => entry.date === date); - - if (existingEntry) { - existingEntry.wins += 1; - } - - else { - let lastWinCount = playerWins[winner].length > 0 ? playerWins[winner][playerWins[winner].length - 1].wins : 0; - playerWins[winner].push({ date: date, wins: lastWinCount + 1 }); - } - }); - - const datasets = Object.keys(playerWins).map(player => { - return { - label: player, - data: playerWins[player].map(entry => ({ x: entry.date, y: entry.wins })), - fill: false, - borderColor: getRandomColor(), - tension: 0.1 - }; - }); - - const ctx = document.getElementById('match-chart').getContext('2d'); - document.getElementById('match-chart').style.display = 'block'; - new Chart(ctx, { - type: 'line', - data: { - labels: dates.sort(), - datasets: datasets - }, - options: { - scales: { - x: { - type: 'time', - time: { - parser: 'YYYY-MM-DD', - unit: 'day', - tooltipFormat: 'll' - }, - title: { - display: true, - text: 'Date' - }, - ticks: { - color: '#00ffff' - } - }, - y: { - beginAtZero: true, - title: { - display: true, - text: 'Nombre de Victoires Cumulées' - }, - ticks: { - color: '#00ffff' - } - } - } - } - }); - } - - function getRandomColor() { - const letters = '0123456789ABCDEF'; - let color = '#'; - for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; - } - return color; - } - -}); \ No newline at end of file diff --git a/pong/static/flags/de.svg b/pong/static/flags/de.svg deleted file mode 100644 index 61e64d0..0000000 --- a/pong/static/flags/de.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/pong/static/flags/es.svg b/pong/static/flags/es.svg deleted file mode 100644 index ce2e1a8..0000000 --- a/pong/static/flags/es.svg +++ /dev/null @@ -1,712 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pong/static/flags/fr.svg b/pong/static/flags/fr.svg deleted file mode 100644 index 240e789..0000000 --- a/pong/static/flags/fr.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/pong/static/flags/it.svg b/pong/static/flags/it.svg deleted file mode 100644 index 038afd9..0000000 --- a/pong/static/flags/it.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/pong/static/flags/us.svg b/pong/static/flags/us.svg deleted file mode 100644 index 8a8fb5c..0000000 --- a/pong/static/flags/us.svg +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pong/static/game.js b/pong/static/game.js deleted file mode 100644 index 8efd2f6..0000000 --- a/pong/static/game.js +++ /dev/null @@ -1,1048 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - console.log("DOM fully loaded and parsed"); - const formBlock = document.getElementById('block-form'); - - const authForm = document.getElementById('auth-form'); - const nicknameInput = document.getElementById('nickname'); - const checkNicknameButton = document.getElementById('check-nickname'); - - const registerForm = document.getElementById('register-form'); - const passwordInput = document.getElementById('password'); - const confirmPasswordInput = document.getElementById('confirm-password'); - const registerButton = document.getElementById('register'); - - const loginForm = document.getElementById('login-form'); - const loginPasswordInput = document.getElementById('login-password'); - const loginButton = document.getElementById('login'); - - const authForm2 = document.getElementById('auth-form2'); - const nicknameInput2 = document.getElementById('nickname2'); - const checkNicknameButton2 = document.getElementById('check-nickname2'); - - const registerForm2 = document.getElementById('register-form2'); - const passwordInput2 = document.getElementById('password2'); - const confirmPasswordInput2 = document.getElementById('confirm-password2'); - const registerButton2 = document.getElementById('register2'); - - const loginForm2 = document.getElementById('login-form2'); - const loginPasswordInput2 = document.getElementById('login-password2'); - const loginButton2 = document.getElementById('login2'); - - const gameContainer = document.getElementById('game1'); - const tournamentContainer = document.getElementById('tournament-bracket'); - - const pongElements = document.getElementById('pong-elements'); - const logo = document.querySelector('.logo'); - - const localGameButton = document.getElementById('local-game'); - const quickMatchButton = document.getElementById('quick-match'); - const tournamentButton = document.getElementById('tournament'); - - let socket; - let gameState; - let activeRoom = null; // Stocker la room active - let roomSockets = {}; // Stocker les connexions WebSocket par room - let chatManager = null; - let username = null; - let token = null; - - console.log("DOM elements initialized"); - - // Auto-focus and key handling for AUTH-FORM - nicknameInput.focus(); - nicknameInput.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - handleCheckNickname(); // Appeler directement la fonction au lieu de simuler un clic - } - }); - - checkNicknameButton.addEventListener('click', handleCheckNickname); - registerButton.addEventListener('click', handleRegister); - loginButton.addEventListener('click', handleLogin); - - checkNicknameButton2.addEventListener('click', handleCheckNickname2); - registerButton2.addEventListener('click', handleRegister2); - loginButton2.addEventListener('click', handleLogin2); - - localGameButton.addEventListener('click', startLocalGame); - quickMatchButton.addEventListener('click', startQuickMatch); - tournamentButton.addEventListener('click', startTournament); - - console.log("Event listeners added"); - - // Function to get the CSRF token from cookies - function getCSRFToken() { - let csrfToken = null; - const cookies = document.cookie.split(';'); - cookies.forEach(cookie => { - const [name, value] = cookie.trim().split('='); - if (name === 'csrftoken') { - csrfToken = value; - } - }); - return csrfToken; - } - - async function handleCheckNickname() { - const nickname = nicknameInput.value.trim(); - if (nickname) { - try { - const exists = await checkUserExists(nickname); - if (exists) { - authForm.style.display = 'none'; - loginForm.style.display = 'block'; - loginPasswordInput.focus(); - loginPasswordInput.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - loginButton.click(); - } - }); - } else { - authForm.style.display = 'none'; - registerForm.style.display = 'block'; - passwordInput.focus(); - passwordInput.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - confirmPasswordInput.focus(); - confirmPasswordInput.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - registerButton.click(); - } - }); - } - }); - } - } catch (error) { - console.error('Error checking user existence:', error); - } - } else { - alert('Please enter a nickname.'); - } - } - - async function checkUserExists(username) { - console.log("checkUserExists called with username:", username); - try { - const response = await fetch('/check_user_exists/', { - method: 'POST', - headers: { - 'X-CSRFToken': getCSRFToken(), - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ username }) - }); - - if (!response.ok) { - console.error(`HTTP error! Status: ${response.status}`); - return false; - } - - const data = await response.json(); - console.log("User existence check response:", data); - return data.exists; - } catch (error) { - console.error('Error during user existence check:', error); - return false; - } - } - - async function handleRegister() { - console.log("handleRegister called"); - const nickname = nicknameInput.value.trim(); - const password = passwordInput.value.trim(); - const confirmPassword = confirmPasswordInput.value.trim(); - - if (!nickname || nickname.length < 3) { - console.error("Invalid username. It must be at least 3 characters long."); - alert("Invalid username. It must be at least 3 characters long."); - return; - } - - if (password === confirmPassword) { - try { - console.log("Attempting to register user:", nickname); - const result = await registerUser(nickname, password); - if (result) { - token = result; // Assurez-vous que le token est bien stocké ici - console.log("Token stored:", token); - console.log("User registered successfully"); - registerForm.style.display = 'none'; - document.getElementById("post-form-buttons").style.display = 'block'; - username = nickname; - roomName = 'main_room'; // Nom de la room principale - chatManager = new ChatManager(username, token); // Initialiser ChatManager - chatManager.joinRoom(roomName); // Utilisez ChatManager pour rejoindre la room - } else { - console.error('Registration failed.'); - alert('Registration failed. Please try again.'); - } - } catch (error) { - console.error('Error registering user:', error); - } - } else { - alert('Passwords do not match.'); - console.error('Passwords do not match.'); - } - } - - async function registerUser(username, password) { - console.log("registerUser called with username:", username); - try { - const response = await fetch('/register_user/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ username, password }) - }); - - if (!response.ok) { - console.error(`HTTP error! Status: ${response.status}`); - return null; // Retournez null en cas d'erreur HTTP - } - - let data; - try { - data = await response.json(); - } catch (error) { - console.error('Invalid JSON response:', error); - return null; - } - - console.log("Registration response data:", data); - if (data.registered) { - console.log('User registered successfully:', data); - return data.token; - } else { - console.error('Registration failed:', data.error); - return null; // Retournez null si l'enregistrement échoue - } - } catch (error) { - console.error('Error during registration request:', error); - return null; - } - } - - async function handleLogin() { - console.log("handleLogin called"); - const nickname = nicknameInput.value.trim(); - const password = loginPasswordInput.value.trim(); - try { - console.log("Attempting to authenticate user:", nickname); - const result = await authenticateUser(nickname, password); - if (result) { - console.log("User authenticated successfully"); - loginForm.style.display = 'none'; - document.getElementById("post-form-buttons").style.display = 'block'; - } else { - console.error('Authentication failed.'); - alert('Authentication failed. Please try again.'); - } - } catch (error) { - console.error('Error authenticating user:', error); - } - } - - async function authenticateUser(username, password) { - console.log("authenticateUser called with username:", username); - try { - const response = await fetch('/authenticate_user/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ username, password }) - }); - - if (!response.ok) { - console.error(`HTTP error! Status: ${response.status}`); - return false; - } - - const data = await response.json(); - console.log("Authentication response data:", data); - if (data.authenticated) { - token = data.token; - } - return data.authenticated; - } catch (error) { - console.error('Error during authentication request:', error); - return false; - } - } - - - async function handleCheckNickname2() { - const nickname2 = nicknameInput2.value.trim(); - if (nickname2) { - try { - const exists = await checkUserExists2(nickname2); - if (exists) { - authForm2.style.display = 'none'; - loginForm2.style.display = 'block'; - loginPasswordInput2.focus(); - loginPasswordInput2.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - loginButton2.click(); - } - }); - } else { - authForm2.style.display = 'none'; - registerForm2.style.display = 'block'; - passwordInput2.focus(); - passwordInput2.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - confirmPasswordInput2.focus(); - confirmPasswordInput2.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - registerButton2.click(); - } - }); - } - }); - } - } catch (error) { - console.error('Error checking user existence:', error); - } - } else { - alert('Please enter a nickname.'); - } - } - - async function checkUserExists2(username) { - console.log("checkUserExists2 called with username:", username); - try { - const response = await fetch('/check_user_exists/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ username }) - }); - - if (!response.ok) { - console.error(`HTTP error! Status: ${response.status}`); - return false; - } - - const data = await response.json(); - console.log("User existence check response (checkUserExists2):", data); - return data.exists; - } catch (error) { - console.error('Error during user existence check (checkUserExists2):', error); - return false; - } - } - - async function handleRegister2() { - console.log("handleRegister2 called"); - const nickname2 = nicknameInput2.value.trim(); - const password2 = passwordInput2.value.trim(); - const confirmPassword2 = confirmPasswordInput2.value.trim(); - - if (!nickname2 || nickname2.length < 3) { - console.error("Invalid username (handleRegister2). It must be at least 3 characters long."); - alert("Invalid username. It must be at least 3 characters long."); - return; - } - - if (password2 === confirmPassword2) { - try { - console.log("Attempting to register user (handleRegister2):", nickname2); - const result = await registerUser2(nickname2, password2); - if (result) { - console.log("User registered successfully (handleRegister2)"); - registerForm2.style.display = 'none'; - startLocalGame2(); - } else { - console.error('Registration failed (handleRegister2).'); - alert('Registration failed. Please try again.'); - } - } catch (error) { - console.error('Error registering user (handleRegister2):', error); - } - } else { - alert('Passwords do not match.'); - console.error('Passwords do not match (handleRegister2).'); - } - } - - async function registerUser2(username, password) { - console.log("registerUser2 called with username:", username); - try { - const response = await fetch('/register_user/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ username, password }) - }); - - if (!response.ok) { - console.error(`HTTP error (registerUser2)! Status: ${response.status}`); - return null; - } - - let data; - try { - data = await response.json(); - } catch (error) { - console.error('Invalid JSON response (registerUser2):', error); - return null; - } - - console.log("Registration response data (registerUser2):", data); - if (data.registered) { - console.log('User registered successfully (registerUser2):', data); - return data.token; - } else { - console.error('Registration failed (registerUser2):', data.error); - return null; - } - } catch (error) { - console.error('Error during registration request (registerUser2):', error); - return null; - } - } - - async function handleLogin2() { - console.log("handleLogin2 called"); - const nickname2 = nicknameInput2.value.trim(); - const password2 = loginPasswordInput2.value.trim(); - try { - console.log("Attempting to authenticate user (handleLogin2):", nickname2); - const result = await authenticateUser2(nickname2, password2); - if (result) { - console.log("User authenticated successfully (handleLogin2)"); - loginForm2.style.display = 'none'; - startLocalGame2(); - } else { - console.error('Authentication failed (handleLogin2).'); - alert('Authentication failed. Please try again.'); - } - } catch (error) { - console.error('Error authenticating user (handleLogin2):', error); - } - } - - async function authenticateUser2(username, password) { - console.log("authenticateUser2 called with username:", username); - try { - const response = await fetch('/authenticate_user/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ username, password }) - }); - - if (!response.ok) { - console.error(`HTTP error (authenticateUser2)! Status: ${response.status}`); - return false; - } - - const data = await response.json(); - console.log("Authentication response data (authenticateUser2):", data); - if (data.authenticated) { - token2 = data.token; - } - return data.authenticated; - } catch (error) { - console.error('Error during authentication request (authenticateUser2):', error); - return false; - } - } - - function startLocalGame() { - console.log("Starting a Local Game..."); - - document.getElementById("post-form-buttons").style.display = 'none'; - console.log("Hid post-form-buttons."); - - authForm2.style.display = 'block'; - console.log("Displayed authForm2."); - - nicknameInput2.focus(); - console.log("Focused on nicknameInput2."); - - nicknameInput2.addEventListener('keypress', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - console.log("Enter key pressed on nicknameInput2."); - checkNicknameButton2.click(); - } - }); - } - - function startLocalGame2() { - console.log("Starting the local game (2 players)..."); - - // Display the game container - gameContainer.style.display = 'flex'; - console.log("Game container set to 'flex'"); - - // Hide the logo, pong elements, and form block - logo.style.display = 'none'; - console.log("Logo hidden"); - - pongElements.style.display = 'none'; - console.log("Pong elements hidden"); - - formBlock.style.display = 'none'; - console.log("Form block hidden"); - - // Log the token before starting the WebSocket connection - console.log("Token before WebSocket authentication:", token); - - // Check if token is defined - if (!token) { - console.error("Token is not defined or is null."); - return; - } - - // Start the WebSocket connection - startWebSocketConnection(token, 2); - console.log("WebSocket connection initiated for a local game."); - } - - function startQuickMatch() { - // Masquer les éléments inutiles et afficher le conteneur de jeu - gameContainer.style.display = 'flex'; - logo.style.display = 'none'; - pongElements.style.display = 'none'; - formBlock.style.display = 'none'; - - // Log pour vérifier le token avant l'authentification WebSocket - console.log("Token before WebSocket authentication:", token); - - if (!token) { - console.error("Token is not defined or is null. WebSocket connection aborted."); - return; - } - - // Vérification si une connexion WebSocket est déjà active avant d'initialiser - if (roomSockets["quick_match"] && roomSockets["quick_match"].readyState === WebSocket.OPEN) { - console.warn("WebSocket for quick_match already open."); - return; - } - roomName = "quick_match"; // Nom de la room principale - chatManager = new ChatManager(username, token); // Initialiser ChatManager - chatManager.joinRoom(roomName); // Utilisez ChatManager pour rejoindre la room - console.log("Starting WebSocket connection for quick match..."); - startWebSocketConnection(token, 1); // Le "1" pourrait être un identifiant pour le mode Quick Match - } - - - function startTournament() { - // Masquer les éléments inutiles et afficher le conteneur du tournoi - tournamentContainer.style.display = 'flex'; - logo.style.display = 'none'; - pongElements.style.display = 'none'; - formBlock.style.display = 'none'; - - // Log pour vérifier le token avant l'authentification WebSocket - console.log("Token before WebSocket authentication:", token); - - if (!token) { - console.error("Token is not defined or is null. WebSocket connection aborted."); - return; - } - - // Vérification si une connexion WebSocket est déjà active avant d'initialiser - if (roomSockets["tournament"] && roomSockets["tournament"].readyState === WebSocket.OPEN) { - console.warn("WebSocket for tournament already open."); - return; - } - chatManager = new ChatManager(username, token); // Initialiser ChatManager - chatManager.joinRoom('tournament'); // Utilisez ChatManager pour rejoindre la room - console.log("Starting WebSocket connection for tournament..."); - startWebSocketConnection(token, 42); // Le "42" pourrait être un identifiant pour le mode tournoi - } - - - function startWebSocketConnection(token, players) { - if (socket && socket.readyState === WebSocket.OPEN) { - console.warn('WebSocket connection already open.'); - return; - } - socket = new WebSocket(`ws://${window.location.host}/ws/game/`); - - socket.onopen = function (event) { - console.log('WebSocket connection established'); - if (players === 1) { - console.log("Sending token for a quick match game"); - socket.send(JSON.stringify({ type: 'authenticate', token: token })); - } else if (players === 2) { - console.log("Sending tokens for a local game"); - socket.send(JSON.stringify({ type: 'authenticate2', token_1: token, token_2: token2 })); - } else { - console.log("Sending token for a tournament game"); - socket.send(JSON.stringify({ type: 'authenticate3', token: token })); - } - }; - - // Gestion des messages reçus - socket.onmessage = function (event) { - const data = JSON.parse(event.data); - if (data.type === 'authenticated') { - console.log('Authentication successful'); - } else if (data.type === 'waiting_room') { - console.log('Entered the WAITING ROOM'); - } else if (data.type === 'game_start') { - console.log('Game started:', data.game_id, '(', data.player1, 'vs', data.player2, ')'); - document.addEventListener('keydown', handleKeyDown); - } else if (data.type === 'game_state_update') { - updateGameState(data.game_state); - } else if (data.type === 'player_disconnected') { - console.log("Player disconnected:", data.player); - } else if (data.type === 'game_ended') { - console.log("Game ended:", data.game_id); - } else if (data.type === 'error') { - console.error(data.message); - } else if (data.type === 'update_waiting_room') { - document.getElementById('tournament-bracket').innerHTML = data.html; - } else { - console.log('Message from server:', data.type, data.message); - } - }; - - // Gestion des fermetures de connexion - socket.onclose = function (event) { - console.log('WebSocket connection closed'); - }; - - socket.onerror = function (error) { - console.error('WebSocket error:', error); - }; - } - - // Gestion des événements de touche - function handleKeyDown(event) { - console.log("Key pressed:", event.key); - if (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'w' || event.key === 's') { - sendKeyPress(event.key.toLowerCase()); - } - } - - function sendKeyPress(key) { - console.log("Sending key press:", key); - if (socket.readyState === WebSocket.OPEN) { - socket.send(JSON.stringify({ type: 'key_press', key })); - } else { - console.warn("WebSocket is not open. Key press not sent."); - } - } - - // Fonction pour mettre à jour l'état du jeu - function updateGameState(newState) { - console.log("Updating game state..."); - gameState = newState; - renderGame(); - } - - // Fonction pour rendre l'état du jeu à l'écran - function renderGame() { - console.log("Rendering game state..."); - document.getElementById('player1-name').textContent = `${gameState.player1_name}`; - document.getElementById('player2-name').textContent = `${gameState.player2_name}`; - - document.getElementById('player1-pad').style.top = `${gameState.player1_position}px`; - document.getElementById('player2-pad').style.top = `${gameState.player2_position}px`; - - document.getElementById('ball').style.left = `${gameState.ball_position.x}px`; - document.getElementById('ball').style.top = `${gameState.ball_position.y}px`; - - document.getElementById('player1-score').textContent = gameState.player1_score; - document.getElementById('player2-score').textContent = gameState.player2_score; - - document.getElementById('game-text').textContent = gameState.game_text; - } - - ////////////////////////////CHAT//////////////////////////////////// - class ChatManager { - constructor(username, token) { - this.username = username; - this.token = token; - this.roomSockets = {}; // Stockage des WebSockets par room - this.blockedUsers = []; // Liste des utilisateurs bloqués - this.activeRoom = null; // La room actuellement active - - console.log(`ChatManager initialized for user: ${username}`); - } - - startChatWebSocket(roomName) { - if (!this.username || this.username.trim() === '') { - console.error("Username is not defined or empty. WebSocket connection aborted."); - alert("Username is required to join the chat. Please log in."); - return; - } - - if (this.roomSockets[roomName] && this.roomSockets[roomName].readyState === WebSocket.OPEN) { - console.warn(`WebSocket for room ${roomName} already open.`); - return; - } - - console.log("Initializing chat WebSocket..."); - console.log(`Initializing chat WebSocket for room: ${roomName} with username: ${this.username}`); - - try { - const chatSocket = new WebSocket(`ws://${window.location.host}/ws/chat/${roomName}/`); - this.roomSockets[roomName] = chatSocket; // Stockage du WebSocket - console.log(`startChatWebSocket: ${roomName} with username: ${this.username} and token: ${this.token}`); - - const chatInputInstance = new ChatInput(roomName, this.username, chatSocket, this); // On passe l'instance du manager - - // Gestion de l'ouverture du WebSocket - chatSocket.onopen = () => { - console.log(`WebSocket ouvert pour l'utilisateur ${this.username} dans la room ${roomName}`); - - chatSocket.send(JSON.stringify({ - 'type': 'authenticate', - 'username': this.username, - 'token': this.token, - 'room': roomName, - })); - console.log(`Authentication message sent for room: ${roomName} with username: ${this.username}`); - }; - - // Gestion des messages WebSocket - chatSocket.onmessage = (event) => { - const data = JSON.parse(event.data); - console.log(`Message received from server in room ${roomName}:`, data); - const receivedUsername = data.username || this.username; - - // Assurez-vous que le chat log est bien trouvé pour la room active - let chatLog = document.getElementById(`chat-log-${roomName}`); - if (!chatLog) { - console.error(`Chat log element for room ${roomName} not found.`); - return; - } - - switch (data.type) { - case 'authenticated': - console.log(`User authenticated successfully in room: ${roomName}`); - break; - - case 'chat_message': - const message = data.message; - const receivedUsername = data.username; - const roomName = data.room; - - // Si l'utilisateur n'est pas bloqué, afficher le message - if (!this.blockedUsers.includes(receivedUsername)) { - const messageElement = document.createElement('div'); - messageElement.textContent = `${receivedUsername}: ${message}`; - chatLog.appendChild(messageElement); - console.log(`Message displayed in chat log for room: ${roomName}`); - } else { - console.log(`Message from blocked user ${receivedUsername} was filtered out.`); - } - break; - - case 'block_user': - if (data.message) { - const messageElement = document.createElement('div'); - messageElement.textContent = data.message; - chatLog.appendChild(messageElement); // Ajoute le message au chat-log - } else { - console.error(`Failed to block user: ${data.message}`); - alert(`Error: Failed to block user. ${data.message}`); - } - break; - - case 'invite_confirmation': - console.log(`Confirmation de l'invitation reçue: ${data.message}`); - if (data.message) { - const messageElement = document.createElement('div'); - messageElement.textContent = data.message; - chatLog.appendChild(messageElement); - console.log(`Invitation confirmation message displayed in chat log: ${data.message}`); - } else { - console.error(`Échec de l'envoi de l'invitation: ${data.message}`); - alert(`Error: Failed to invite user. ${data.message}`); - } - break; - - case 'invite': - // Vérifie si l'invitation est destinée à cet utilisateur (invité) - if (data.target_user === this.username) { - console.log(`Invitation reçue de ${data.inviter}`); - - const messageElement = document.createElement('div'); - messageElement.textContent = data.message; - chatLog.appendChild(messageElement); // Affiche le message dans le chat-log - - // Demande à l'utilisateur s'il accepte ou refuse l'invitation - const inviteResponse = confirm(`${data.inviter} vous a invité dans la room ${data.room}. Accepter? yes/no.`); - const response = inviteResponse ? 'yes' : 'no'; - - console.log(`Réponse à l'invitation: ${response}`); - - // Envoie la réponse (oui ou non) au serveur - chatSocket.send(JSON.stringify({ - 'type': 'invite_response', - 'username': this.username, // Utilisateur invité - 'response': response, - 'inviter': data.inviter, // Le nom de l'invitant - 'room': data.room - })); - - if (response === 'yes') { - // Si l'invitation est acceptée, lancer QuickMatch pour l'invité - console.log(`L'invité ${this.username} va démarrer le QuickMatch...`); - // Si l'invitation est acceptée, lancer QuickMatch pour l'invité après un délai - console.log("Invitation acceptée, démarrage du QuickMatch pour l'invité après un délai..."); - setTimeout(() => { - startQuickMatch(); // Lancer le jeu après 2 secondes - }, 2000); // 2000 millisecondes = 2 secondes - } - } - break; - - case 'invite_response': - // Vérifie si l'invitation concerne cet utilisateur (l'invitant) - if (data.inviter === this.username) { - const messageElement = document.createElement('div'); - messageElement.textContent = data.message; - chatLog.appendChild(messageElement); // Affiche la réponse dans le chat-log - console.log(`Réponse à l'invitation: ${data.message}`); - - if (data.response && data.response.toLowerCase() === 'yes') { - console.log("Invitation acceptée, démarrage du QuickMatch pour l'invitant..."); - startQuickMatch(); - } - } - break; - - - case 'success': - console.log(`Success message received: ${data.message}`); - alert('Success: ' + data.message); - break; - - case 'error': - console.error('Error message received:', data.message); - alert('Error: ' + data.message); - break; - - default: - console.warn('Unhandled message type:', data); - } - }; - - // Gestion de la fermeture du WebSocket - chatSocket.onclose = (event) => { - if (event.wasClean) { - console.log(`Chat WebSocket closed cleanly for room ${roomName}, code=${event.code}, reason=${event.reason}`); - } else { - console.error(`Chat WebSocket closed unexpectedly for room ${roomName}`); - } - }; - - // Gestion des erreurs WebSocket - chatSocket.onerror = (error) => { - console.error(`Chat WebSocket error in room ${roomName}:`, error); - }; - - } catch (error) { - console.error(`Error initializing chat WebSocket for room ${roomName}:`, error); - } - } - - blockUser(targetUser) { - this.blockedUsers.push(targetUser); - console.log(`User ${targetUser} added to blocked list.`); - } - - createRoomTab(roomName) { - console.log(`createRoomTab: ${roomName} with username: ${username} and token: ${token}`); - - const tabContainer = document.getElementById('room-tabs-container'); - if (!tabContainer) { - console.error('Room tabs container not found.'); - return; - } - - const existingTab = Array.from(tabContainer.children).find(tab => tab.dataset.room === roomName); - if (existingTab) { - console.log(`Tab for room ${roomName} already exists.`); - // Vous pouvez ajouter une classe pour indiquer que l'onglet est inactif - existingTab.classList.remove('active'); - } else { - console.warn(`Tab for room ${roomName} not found in the HTML.`); - } - } - - showRoomTab(roomName) { - const tabContainer = document.getElementById('room-tabs-container'); - const tab = Array.from(tabContainer.children).find(tab => tab.dataset.room === roomName); - if (tab) { - tab.classList.add('active'); - console.log(`Showing tab for room: ${roomName}`); - } else { - console.warn(`Tab for room ${roomName} not found.`); - } - } - - switchRoom(roomName) { - - if (!roomName) { - console.error('Room name is undefined.'); - return; - } - console.log(`Attempting to switch to room: ${roomName}`); - if (activeRoom === roomName) { - console.log(`Already in room: ${roomName}`); - return; - } - - console.log(`Switching from room ${activeRoom} to room ${roomName}`); - const previousRoom = activeRoom; - activeRoom = roomName; - - if (previousRoom && document.getElementById(`chat-log-${previousRoom}`)) { - console.log(`Hiding chat log for previous room: ${previousRoom}`); - document.getElementById(`chat-log-${previousRoom}`).style.display = 'none'; - } - - const chatLog = document.getElementById(`chat-log-${roomName}`); - if (chatLog) { - chatLog.style.display = 'block'; - } else { - console.warn(`No chat log found for room: ${roomName}`); - } - - // Mettre à jour l'affichage des inputs - document.querySelectorAll('.chat-input').forEach(input => { - input.style.display = 'none'; - }); - document.getElementById(`chat-input-${roomName}`).style.display = 'block'; - - // Mettre à jour l'onglet actif - const tabs = document.querySelectorAll('.room-tab'); - tabs.forEach(t => t.classList.remove('active')); - const activeTab = Array.from(tabs).find(tab => tab.dataset.room === roomName); - if (activeTab) { - activeTab.classList.add('active'); - } - } - - joinRoom(roomName) { - console.log(`Joining room: ${roomName} with username: ${chatManager.username} and token: ${chatManager.token}`); - if (activeRoom === roomName) { - console.log(`Already in room: ${roomName}`); - return; - } - - // Si la room n'a pas de WebSocket actif, on le crée - if (!chatManager.roomSockets[roomName]) { - console.log(`Joining new room: ${roomName}`); - this.createRoomTab(roomName); - this.showRoomTab(roomName); - this.startChatWebSocket(roomName); // Utilisation du ChatManager pour démarrer le WebSocket - } - - this.switchRoom(roomName); - // Activer l'affichage du conteneur de chat - document.getElementById('chat-container').style.display = 'flex'; - } -} - - class ChatInput { - constructor(roomName, username, chatSocket, chatManager) { - this.roomName = roomName; - this.username = username; - this.chatSocket = chatSocket; - this.chatManager = chatManager; - this.messageInput = document.querySelector(`#chat-input-${roomName} input`); - this.chatButton = document.querySelector(`#chat-input-${roomName} button`); - - console.log(`ChatInput initialized for room: ${roomName}, username: ${username}`); - this.initEventListeners(); - } - - initEventListeners() { - this.messageInput.addEventListener('keypress', (event) => { - if (event.key === 'Enter') { - console.log("Enter key pressed, attempting to send message..."); - this.sendMessage(); - } - }); - - this.chatButton.addEventListener('click', () => { - console.log("Send button clicked, attempting to send message..."); - this.sendMessage(); - }); - } - - sendMessage() { - const message = this.messageInput.value.trim(); - console.log(`Attempting to send message: ${message}`); - - if (message) { - if (message.startsWith('/b ')) { - const targetUser = message.slice(3).trim(); - console.log(`Detected block command for user: ${targetUser}`); - this.sendBlockCommand(targetUser); - } else if (message.startsWith('/i ')) { - const targetUser = message.slice(3).trim(); - console.log(`Detected invite command for user: ${targetUser}`); - this.sendInviteCommand(targetUser); - } else { - console.log(`Sending chat message to WebSocket...`); - this.chatSocket.send(JSON.stringify({ - 'type': 'chat_message', - 'username': this.username, - 'message': message, - 'room': this.roomName - })); - } - this.messageInput.value = ''; - console.log("Message input cleared."); - } else { - console.warn('Cannot send an empty message.'); - } - } - - sendBlockCommand(targetUser) { - this.chatManager.blockUser(targetUser); // Met à jour la liste des utilisateurs bloqués via ChatManager - console.log(`Sending block command to WebSocket for user: ${targetUser}`); - this.chatSocket.send(JSON.stringify({ - 'type': 'block_user', - 'username': this.username, - 'target_user': targetUser, - 'room': this.roomName - })); - } - - sendInviteCommand(targetUser) { - if (!targetUser) { - console.error("Target user is not defined. Cannot send invite."); - return; - } - if (!this.username) { - console.error("Username is not defined. Cannot send invite."); - return; - } - if (!this.roomName) { - console.error("Room name is not defined. Cannot send invite."); - return; - } - - console.log(`Sending invite command to WebSocket for user: ${targetUser}`); - - this.chatSocket.send(JSON.stringify({ - 'type': 'invite', - 'username': this.username, // Utilisateur qui envoie l'invitation - 'target_user': targetUser, // Utilisateur qui reçoit l'invitation - 'room': this.roomName // Room où l'invitation est faite - })); - } - } - -}); diff --git a/pong/static/index.html b/pong/static/index.html deleted file mode 100644 index ed7361d..0000000 --- a/pong/static/index.html +++ /dev/null @@ -1,319 +0,0 @@ -{% load static %} - - - - - - - Pong Game - - - - -
- Français - English - Italiano - Español - Deutsch -
-
-
-
-
-
-
-
-
- - - - -
-

BIENVENUE DANS LE PONG 42

-
-
- - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - -
- - -
- -
- -
-
- - -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
Main Room
-
Tournament
-
Quick Match
-
-
- - - - - - - \ No newline at end of file diff --git a/pong/static/language.js b/pong/static/language.js deleted file mode 100644 index dd5b518..0000000 --- a/pong/static/language.js +++ /dev/null @@ -1,113 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - const translations = { - fr: { - welcome: "BIENVENUE DANS LE PONG 42", - labelNickname: "Entrez votre surnom:", - labelPassword: "Entrez votre mot de passe:", - labelConfirmPassword: "Confirmez votre mot de passe:", - labelLoginPassword: "Entrez votre mot de passe:" - }, - en: { - welcome: "WELCOME TO PONG 42", - labelNickname: "Enter your nickname:", - labelPassword: "Enter your password:", - labelConfirmPassword: "Confirm your password:", - labelLoginPassword: "Enter your password:" - }, - it: { - welcome: "BENVENUTO A PONG 42", - labelNickname: "Inserisci il tuo soprannome:", - labelPassword: "Inserisci la tua password:", - labelConfirmPassword: "Conferma la tua password:", - labelLoginPassword: "Inserisci la tua password:" - }, - es: { - welcome: "BIENVENIDO A PONG 42", - labelNickname: "Introduce tu apodo:", - labelPassword: "Introduce tu contraseña:", - labelConfirmPassword: "Confirma tu contraseña:", - labelLoginPassword: "Introduce tu contraseña:" - }, - de: { - welcome: "WILLKOMMEN BEI PONG 42", - labelNickname: "Geben Sie Ihren Spitznamen ein:", - labelPassword: "Geben Sie Ihr Passwort ein:", - labelConfirmPassword: "Bestätigen Sie Ihr Passwort:", - labelLoginPassword: "Geben Sie Ihr Passwort ein:" - } - }; - - function setCookie(name, value, days) { - const d = new Date(); - d.setTime(d.getTime() + (days*24*60*60*1000)); - const expires = "expires=" + d.toUTCString(); - document.cookie = name + "=" + value + ";" + expires + ";path=/"; - } - - function getCookie(name) { - const cname = name + "="; - const decodedCookie = decodeURIComponent(document.cookie); - const ca = decodedCookie.split(';'); - for(let i = 0; i < ca.length; i++) { - let c = ca[i]; - while (c.charAt(0) === ' ') { - c = c.substring(1); - } - if (c.indexOf(cname) === 0) { - return c.substring(cname.length, c.length); - } - } - return ""; - } - - function changeLanguage(lang) { - setCookie('preferredLanguage', lang, 365); - document.getElementById('welcome').innerText = translations[lang].welcome; - document.getElementById('label-nickname').innerText = translations[lang].labelNickname; - document.getElementById('label-password').innerText = translations[lang].labelPassword; - document.getElementById('label-confirm-password').innerText = translations[lang].labelConfirmPassword; - document.getElementById('label-login-password').innerText = translations[lang].labelLoginPassword; - } - - function setLanguageFromCookie() { - const preferredLanguage = getCookie('preferredLanguage'); - if (preferredLanguage && translations[preferredLanguage]) { - changeLanguage(preferredLanguage); - } else { - changeLanguage('fr'); // Default to French if no cookie is found - } - } - - document.getElementById('lang-fr').addEventListener('click', () => changeLanguage('fr')); - document.getElementById('lang-en').addEventListener('click', () => changeLanguage('en')); - document.getElementById('lang-it').addEventListener('click', () => changeLanguage('it')); - document.getElementById('lang-es').addEventListener('click', () => changeLanguage('es')); - document.getElementById('lang-de').addEventListener('click', () => changeLanguage('de')); - - window.onload = setLanguageFromCookie; - - document.getElementById('settings-btn').addEventListener('click', function() { - document.getElementById('settings-menu').style.display = 'block'; - }); - - document.getElementById('close-settings').addEventListener('click', function() { - document.getElementById('settings-menu').style.display = 'none'; - }); - - - document.getElementById('color-picker').addEventListener('input', function() { - document.body.style.color = this.value; - document.querySelectorAll('button').forEach(function(button) { - button.style.backgroundColor = this.value; - }, this); - }); - - document.getElementById('font-selector').addEventListener('change', function() { - document.body.style.fontFamily = this.value; - }); - - document.getElementById('font-size-slider').addEventListener('input', function() { - document.body.style.fontSize = this.value + 'px'; - }); - -}); \ No newline at end of file diff --git a/pong/static/logo-42-perpignan.png b/pong/static/logo-42-perpignan.png deleted file mode 100644 index d91cd1f..0000000 Binary files a/pong/static/logo-42-perpignan.png and /dev/null differ diff --git a/pong/static/styles.css b/pong/static/styles.css deleted file mode 100644 index 332f746..0000000 --- a/pong/static/styles.css +++ /dev/null @@ -1,681 +0,0 @@ -/* General styles */ - -html { - font-family: Arial, sans-serif; - color: #00ffff; - background-color: #0a0a2a; - margin: 0; - padding: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - overflow: auto; -} - - -label { - margin: 10px 0 5px; -} - -input { - padding: 10px; - margin: 5px 0 20px; - width: 200px; -} - -button { - background-color: #00ffff; - color: #000033; - border: none; - padding: 1rem 2rem; - font-size: 1.5rem; - cursor: pointer; - transition: all 0.3s ease; - border-radius: 10px; - margin-top: 1rem; - text-transform: uppercase; - letter-spacing: 2px; -} - -button:hover { - background-color: #000033; - color: #00ffff; - box-shadow: 0 0 20px #00ffff; -} - -#game1 { - width: 810px; - height: 500px; - position: relative; - background-color: #000; - border: 3px solid #00ffff; - box-shadow: 0 0 30px #00ffff, inset 0 0 20px #00ffff; - overflow: hidden; - display: flex; - justify-content: center; - align-items: center; -} - -.name { - font-size: 24px; - position: absolute; - top: 20px; -} - -#player1-name { - left: 10px; - /* Adjust player score position */ -} - -#player2-name { - right: 10px; - /* Adjust bot score position */ -} - -#game2 { - top: 60px; - width: 800px; - height: 400px; - position: absolute; - background-color: #000; - overflow: hidden; - border: 2px solid white; - /* Add red border */ - display: flex; - justify-content: center; - align-items: center; -} - -.score { - font-size: 24px; - position: absolute; - top: 10px; -} - -#player1-score { - left: 50px; - /* Adjust player score position */ -} - -#player2-score { - right: 50px; - /* Adjust bot score position */ -} - -.pad { - width: 10px; - height: 100px; - background-color: #ffffff; - position: absolute; -} - -#player1-pad { - left: 10px; - background-color: #00ffff; - border-radius: 10px; - box-shadow: 0 0 15px #00ffff; -} - -#player2-pad { - right: 10px; - background-color: #00ffff; - border-radius: 10px; - box-shadow: 0 0 15px #00ffff; -} - -#ball { - width: 20px; - height: 20px; - background-color: #00ffff; - border-radius: 50%; - position: absolute; -} - -#game-text { - font-size: 64px; - color: #00ffff; - position: absolute; - top: 150px; -} - -.logo { - position: absolute; - top: 20px; - left: 20px; - z-index: 20; -} - -.logo img { - max-width: 100%; - height: auto; -} - -.stars { - position: absolute; - width: 100%; - height: 100%; -} - -.star { - position: absolute; - background-color: #ffffff; - border-radius: 50%; - animation: twinkle 2s infinite alternate; -} - -.background { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 0; - pointer-events: none; -} - -.pong-elements { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 5; - pointer-events: none; -} - -.paddle { - position: absolute; - width: 20px; - height: 100px; - background-color: #00ffff; - border-radius: 10px; - box-shadow: 0 0 15px #00ffff; -} - -.paddle-left { - left: 50px; - animation: paddleMove 5s infinite alternate ease-in-out; -} - -.paddle-right { - right: 50px; - animation: paddleMove 4s infinite alternate-reverse ease-in-out; -} - -.ball_anim { - position: absolute; - width: 30px; - height: 30px; - background-color: #00ffff; - border-radius: 50%; - box-shadow: 0 0 20px #00ffff; - left: 80px; - top: 50%; - transform-style: preserve-3d; - animation: ballMove 3s linear infinite; -} - -@keyframes paddleMove { - 0% { - transform: translateY(10vh); - } - - 100% { - transform: translateY(70vh); - } -} - -@keyframes ballMove { - 0% { - transform: translateZ(0) scale(1); - } - - 50% { - transform: translateZ(-500px) scale(0.5); - } - - 100% { - transform: translateZ(0) scale(1); - } -} - -.input-container { - margin-bottom: 2rem; -} - -.container { - text-align: center; - background-color: rgba(0, 0, 40, 0.8); - padding: 3rem; - border-radius: 15px; - border: 3px solid #00ffff; - box-shadow: 0 0 30px #00ffff, inset 0 0 20px #00ffff; - position: relative; - z-index: 10; - max-width: 80%; - overflow: auto; -} - - -.navbar { - position: absolute; - top: 30px; - right: 10px; - padding: 10px; -} - -.burger-menu { - font-size: 24px; - background: none; - border: none; - color: #00ffff; - cursor: pointer; - transition: color 0.3s ease; -} - -.burger-menu:hover { - color: #ffffff; -} - - -.dropdown-content { - display: none; - position: absolute; - top: 100%; - right: 0; - margin-top: 10px; - background-color: #1a1a2e; - color: #ffffff; - box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.3); - border-radius: 5px; - z-index: 1; - width: max-content; -} - -.dropdown-content.show { - display: block; -} - - -.dropdown-content a { - color: #ffffff; - padding: 12px 16px; - text-decoration: none; - display: block; - border-bottom: 1px solid rgba(255, 255, 255, 0.2); - transition: background-color 0.3s ease; -} - - -.dropdown-content a:hover { - background-color: #333; - color: #00ffff; -} - -.language-switcher { - position: absolute; - top: 10px; - right: 10px; - display: flex; - gap: 10px; -} - -.language-switcher img { - width: 30px; - height: 20px; - cursor: pointer; -} - -#settings-btn { - position: fixed; - bottom: 10px; - right: 10px; - cursor: pointer; - z-index: 1000; - border: none; - border-radius: 50%; - padding: 10px; - font-size: 18px; -} - -#settings-menu { - position: fixed; - bottom: 50px; - right: 10px; - padding: 20px; - background-color: rgb(66, 63, 63); - border: 1px solid #ccc; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - width: 250px; - z-index: 1000; -} - -#close-settings { - position: absolute; - top: 10px; - right: 10px; - background: none; - border: none; - cursor: pointer; - font-size: 16px; -} - -.modal { - display: none; - position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgb(0, 0, 0); - background-color: rgba(0, 0, 0, 0.4); - padding-top: 60px; -} - -.modal-content { - background-color: #fefefe; - margin: 5% auto; - padding: 20px; - border: 5px solid #888; - width: 80%; - max-height: 70vh; - overflow-y: auto; -} - -.close { - color: #aaa; - float: right; - font-size: 28px; - font-weight: bold; -} - -.close:hover, -.close:focus { - color: black; - text-decoration: none; - cursor: pointer; -} - -pre { - white-space: pre-wrap; - word-wrap: break-word; -} - -.tournament-waiting-room { - background-color: rgba(0, 0, 0, 0.6); - padding: 20px; - border-radius: 15px; - color: #00ffff; - width: 50%; - margin: auto; - text-align: center; - box-shadow: 0 0 30px #00ffff, inset 0 0 20px #00ffff; - -} - -.tournament-waiting-room h2 { - font-family: 'Arial', sans-serif; - font-size: 2em; - margin-bottom: 15px; - text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7); -} - -.tournament-waiting-room p { - font-family: 'Verdana', sans-serif; - font-size: 1.2em; - margin-bottom: 20px; - text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6); -} - -.tournament-waiting-room ul { - list-style-type: none; - padding: 0; -} - -body { - color: rgb(0, 255, 255); /* Valeur par défaut */ - font-family: Arial, sans-serif; - font-size: 16px; -} - -canvas { - max-width: 100%; - height: auto; - margin-top: 20px; -} - -#game-controls { - display: flex; - justify-content: center; - gap: 20px; - margin-bottom: 10px; -} - -#game-controls button { - background-color: #00ffff; - color: #000033; - border: none; - padding: 1rem 2rem; - font-size: 1rem; - cursor: pointer; - transition: all 0.3s ease; - border-radius: 10px; - text-transform: uppercase; - letter-spacing: 2px; -} - -#game-controls button:hover { - background-color: #000033; - color: #00ffff; - box-shadow: 0 0 20px #00ffff; -} - -/**************************CHAT*************************************/ -@keyframes borderGlow { - 0% { - box-shadow: 0 0 30px #00ffff, inset 0 0 20px #00ffff; - } - 50% { - box-shadow: 0 0 60px #0099ff, inset 0 0 40px #0099ff; - } - 100% { - box-shadow: 0 0 30px #00ffff, inset 0 0 20px #00ffff; - } -} - -#chat-container { - display: none; /* Masquer par défaut */ - position: fixed; - bottom: 10px; - left: 10px; - width: 300px; - background-color: rgba(0, 0, 0, 0.7); /* Couleur de fond semi-transparente par défaut */ - border-radius: 10px; - padding: 10px; - box-shadow: 0 0 30px #00ffff, inset 0 0 20px #00ffff; - z-index: 1000; - box-sizing: border-box; - flex-direction: column; - animation: borderGlow 3s infinite; /* Ajouter l'animation */ - transition: background-color 0.3s, transform 0.3s; /* Ajouter des transitions */ -} - -#chat-container:hover { - background-color: rgba(0, 0, 0, 1); /* Couleur de fond opaque au survol */ - transform: scale(1.05); /* Agrandir légèrement au survol */ -} - -.chat-log { - max-height: 150px; - overflow-y: auto; - margin-bottom: 10px; - box-sizing: border-box; - background-color: transparent; - display: none; -} - -.chat-input { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - margin-bottom: 5px; - position: relative; /* Assurez-vous que le conteneur parent est positionné */ -} - -.chat-input.active { - display: flex; /* Afficher uniquement l'élément actif */ -} - -.chat-input input[type="text"] { - flex: 1; - padding: 5px; - font-size: 13px; - border: none; - border-radius: 5px; - box-sizing: border-box; - height: 28px; - align-items: center; - justify-content: center; -} - -.chat-button { - height: 50px; - width: 50px; /* Réduire la taille du bouton */ - border: none; - border-radius: 50%; - background: linear-gradient(45deg, #00ffff, #0099ff); - color: #000033; - cursor: pointer; - position: absolute; /* Positionner le bouton de manière absolue */ - right: 10px; /* Ajuster la position à droite */ - top: 10%; /* Centrer verticalement */ - transform: translateY(-50%); /* Centrer verticalement */ - display: flex; - align-items: center; - justify-content: center; - text-align: center; - font-size: 20px; - padding: 0; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - transition: background 0.3s, transform 0.3s; - animation: buttonGlow 3s infinite; /* Ajouter l'animation */ -} - -.chat-button:hover { - background: linear-gradient(45deg, #0099ff, #00ffff); - transform: translateY(-50%) scale(1.1); /* Agrandir légèrement au survol */ -} - -.chat-button:active { - transform: translateY(-50%) scale(0.95); /* Réduire légèrement à l'activation */ -} - -@keyframes buttonGlow { - 0% { - box-shadow: 0 0 10px #00ffff, inset 0 0 5px #00ffff; - } - 50% { - box-shadow: 0 0 20px #0099ff, inset 0 0 10px #0099ff; - } - 100% { - box-shadow: 0 0 10px #00ffff, inset 0 0 5px #00ffff; - } -} - -#room-tabs-container { - display: flex; - justify-content: space-between; - margin-top: 5px; -} - -.room-tab { - font-size: 14px; - padding: 5px 10px; - margin-right: 5px; - cursor: pointer; - border: 1px solid #00ffff; - background-color: #000033; - color: #00ffff; - border-radius: 5px; - box-sizing: border-box; - opacity: 0.1; - transition: background 0.3s, transform 0.3s; /* Ajouter des transitions */ - animation: tabGlow 3s infinite; /* Ajouter l'animation */ -} - -.room-tab:hover { - background-color: #00ffff; - color: #000033; - transform: scale(1.1); /* Agrandir légèrement au survol */ -} - -.room-tab:active { - transform: scale(0.95); /* Réduire légèrement à l'activation */ -} - -.room-tab.active { - background-color: #00ffff; - color: #000033; - opacity: 1; -} - -@keyframes tabGlow { - 0% { - box-shadow: 0 0 10px #00ffff, inset 0 0 5px #00ffff; - } - 50% { - box-shadow: 0 0 20px #0099ff, inset 0 0 10px #0099ff; - } - 100% { - box-shadow: 0 0 10px #00ffff, inset 0 0 5px #00ffff; - } -} - -#chat-controls { - position: fixed; - bottom: 10px; - left: 320px; /* Ajuster la position à côté du conteneur de chat */ - display: flex; - flex-direction: column; - gap: 5px; /* Espacement entre les boutons */ -} - -#chat-controls button { - width: 100px; /* Réduire la taille des boutons */ - height: 30px; /* Réduire la taille des boutons */ - font-size: 12px; /* Ajuster la taille de la police */ - padding: 5px; - border-radius: 5px; - cursor: pointer; - background-color: #00ffff; - color: #000033; - border: none; - transition: background-color 0.3s, transform 0.3s; - animation: buttonGlow 3s infinite; /* Ajouter l'animation */ -} - -#chat-controls button:hover { - background-color: #0099ff; - transform: scale(1.05); -} - -#chat-controls button:active { - transform: scale(0.95); -} - -@keyframes buttonGlow { - 0% { - box-shadow: 0 0 10px #00ffff, inset 0 0 5px #00ffff; - } - 50% { - box-shadow: 0 0 20px #0099ff, inset 0 0 10px #0099ff; - } - 100% { - box-shadow: 0 0 10px #00ffff, inset 0 0 5px #00ffff; - } -} \ No newline at end of file diff --git a/pong/urls.py b/pong/urls.py deleted file mode 100644 index dae9bf6..0000000 --- a/pong/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -# /pong/urls.py - -from django.contrib import admin -from django.urls import path, include -from django.conf import settings -from django.conf.urls.static import static - -urlpatterns = [ - # Disable the admin page - # path('admin/', admin.site.urls), - # path('api/', include('pong.game.urls')), - path('', include('pong.game.urls')), -] - -if settings.DEBUG: - urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 15069d9..0000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -django -psycopg2 -python-dotenv -channels -daphne -djangorestframework -web3 -python-json-logger==2.0.7