├── .dockerignore ├── .envtemplate ├── .github └── workflows │ └── docker-image.yml ├── .gitignore ├── Dockerfile ├── Dockerfile.nginx ├── Makefile ├── README.MD ├── docker-compose.yml ├── indianpong ├── indianpong │ ├── __init__.py │ ├── asgi.py │ ├── routing.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py ├── pong │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── consumer_chat.py │ ├── consumer_pong.py │ ├── consumer_rps.py │ ├── consumer_status.py │ ├── forms.py │ ├── game.py │ ├── langs.py │ ├── management │ │ └── commands │ │ │ ├── initdata.py │ │ │ └── populate.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── rps.py │ ├── templates │ │ ├── 404.html │ │ ├── _nav.html │ │ ├── aboutus.html │ │ ├── activate_account_email.html │ │ ├── activation_fail.html │ │ ├── base.html │ │ ├── chat.html │ │ ├── dashboard.html │ │ ├── friends.html │ │ ├── inventory.html │ │ ├── local-game.html │ │ ├── local-tournament.html │ │ ├── login.html │ │ ├── password_change.html │ │ ├── password_reset.html │ │ ├── password_reset_done.html │ │ ├── password_reset_email.html │ │ ├── play-ai.html │ │ ├── play-rps-ai.html │ │ ├── play-rps.html │ │ ├── pong-game-find.html │ │ ├── profile-settings.html │ │ ├── profile.html │ │ ├── rankings.html │ │ ├── remote-game.html │ │ ├── room.html │ │ ├── rps-game-find.html │ │ ├── search.html │ │ ├── set_password.html │ │ ├── signup.html │ │ ├── store.html │ │ ├── tournament-create.html │ │ ├── tournament-room-list.html │ │ ├── tournament-room.html │ │ └── tournament.html │ ├── templatetags │ │ ├── custom_filters.py │ │ ├── status.py │ │ ├── transnav.py │ │ └── user_info.py │ ├── tests.py │ ├── update.py │ ├── utils.py │ └── views.py ├── start.sh └── static │ ├── assets │ ├── 42.svg │ ├── backgrounds │ │ ├── bg-pingpong.png │ │ ├── bg-rps.png │ │ ├── confetti.webp │ │ ├── home-bg.jpg │ │ ├── leader-bg.avif │ │ ├── leader-bg.png │ │ ├── lose.png │ │ ├── pong-room-bg.jpeg │ │ ├── pong-room-bg.png │ │ ├── rankings-bg.jpeg │ │ └── rps-room-bg.jpeg │ ├── email │ │ ├── 268a.jpg │ │ ├── Beefree-logo.png │ │ ├── back.png │ │ ├── github.png │ │ └── head.png │ ├── favicon.ico │ ├── flags │ │ ├── english.png │ │ ├── hindi.png │ │ ├── portugal.png │ │ └── turkey.png │ ├── intra-42-white.svg │ ├── intra42-logo.svg │ ├── logo-dark.png │ ├── logo.png │ ├── profile │ │ ├── ataskin.jpeg │ │ ├── c1.jpg │ │ ├── c2.jpg │ │ ├── c3.jpg │ │ ├── c4.jpg │ │ ├── default_avatar.jpeg │ │ ├── eyagiz.jpeg │ │ ├── fyurtsev.jpeg │ │ ├── indianai.jpg │ │ ├── profilephoto.jpeg │ │ ├── sciftci.jpeg │ │ └── yeaktas.jpeg │ ├── rankings │ │ └── crown.svg │ ├── ranks │ │ ├── bronze.webp │ │ ├── challenger.webp │ │ ├── diamond.webp │ │ ├── emerald.webp │ │ ├── gold.webp │ │ ├── grandmaster.webp │ │ ├── iron.webp │ │ ├── master.webp │ │ ├── platinum.webp │ │ ├── silver.webp │ │ └── unranked.webp │ ├── rps │ │ ├── .DS_Store │ │ ├── bg-pentagon.svg │ │ ├── bg-triangle.svg │ │ ├── favicon-32x32.png │ │ ├── icon-cheater.svg │ │ ├── icon-close.svg │ │ ├── icon-godofthings.svg │ │ ├── icon-godthings.svg │ │ ├── icon-likeacheater.svg │ │ ├── icon-lizard.svg │ │ ├── icon-paper.svg │ │ ├── icon-rock.svg │ │ ├── icon-scissors.svg │ │ ├── icon-spock.svg │ │ ├── image-rules-bonus.svg │ │ ├── image-rules.svg │ │ ├── logo-bonus.svg │ │ └── logo.svg │ ├── scrool │ │ ├── crossedsword.png │ │ └── pixelsword.png │ └── stores │ │ ├── ai-nametag.webp │ │ ├── cheater-rps.webp │ │ ├── cheater.webp │ │ ├── colorpick.webp │ │ ├── djplaythemusic.webp │ │ ├── fast-and-furious.webp │ │ ├── fireball.webp │ │ ├── giantman.webp │ │ ├── godofthings-rps.webp │ │ ├── mybeatifulpaddle.webp │ │ ├── store_data.json │ │ └── versus-time.webp │ ├── css │ ├── aboutus.css │ ├── card.css │ ├── changepassword.css │ ├── chat.css │ ├── color.css │ ├── fonts │ │ ├── CommonPixel.ttf │ │ ├── Lobster-Regular.ttf │ │ ├── Minecraftia-Regular.ttf │ │ ├── Pixeboy-z8XGD.ttf │ │ ├── PixelifySans-VariableFont_wght.ttf │ │ ├── alagard.ttf │ │ └── rainyhearts.ttf │ ├── friends-list.css │ ├── game-find.css │ ├── game.css │ ├── in-game.chat.css │ ├── in-game.css │ ├── inventory.css │ ├── leader-bg.png │ ├── local-tournament.css │ ├── loginregister.css │ ├── match-history.css │ ├── mediaquery.css │ ├── modal.css │ ├── navbar.css │ ├── profile.css │ ├── profilesettings.css │ ├── ranking.css │ ├── register.css │ ├── remote-player.css │ ├── room-list.css │ ├── rps.css │ ├── scrollbar.css │ ├── search.css │ ├── store.css │ ├── style.css │ └── tournament-room.css │ ├── fonts │ ├── CommonPixel.ttf │ ├── Lobster-Regular.ttf │ ├── Minecraftia-Regular.ttf │ ├── Pixeboy-z8XGD.ttf │ ├── alagard.ttf │ └── rainyhearts.ttf │ ├── js │ ├── base-chat.js │ ├── burger.js │ ├── chat.js │ ├── create-tournament.js │ ├── game │ │ ├── local-game.js │ │ ├── localTournament.js │ │ ├── play-ai.js │ │ └── sockPong.js │ ├── inventory.js │ ├── login.js │ ├── navigation.js │ ├── profile-settings.js │ ├── profile.js │ ├── rps.js │ ├── search.js │ ├── signup.js │ ├── sockRps.js │ ├── store.js │ └── tournament-room.js │ └── music │ ├── defeat-sound.mp3 │ ├── fast-and-furious.mp3 │ ├── frozen-ball.mp3 │ ├── one_beep.mp3 │ ├── one_beep_2.mp3 │ ├── one_beep_2_left.mp3 │ ├── one_beep_2_right.mp3 │ ├── pong-defeat-sound.mp3 │ ├── pong-music.mp3 │ ├── pong-victory-sound.mp3 │ ├── rps-cheater.mp3 │ ├── rps-defeat.mp3 │ ├── rps-drawonce.mp3 │ ├── rps-godthings.mp3 │ ├── rps-loseonce.mp3 │ ├── rps-paper.mp3 │ ├── rps-rock.mp3 │ ├── rps-scissors.mp3 │ ├── rps-win.mp3 │ ├── rps-winonce.mp3 │ └── victory-sound.mp3 ├── nginx.conf └── requirements.txt /.dockerignore: -------------------------------------------------------------------------------- 1 | zort -------------------------------------------------------------------------------- /.envtemplate: -------------------------------------------------------------------------------- 1 | SECRET_KEY= 2 | DEBUG=False 3 | BASE_URL=https://localhost:8443 4 | 5 | SUPER_USER= 6 | SUPER_MAIL= 7 | SUPER_PASS= 8 | 9 | FT_CLIENT_ID= 10 | FT_CLIENT_SECRET= 11 | 12 | EMAIL_HOST_USER=indianpong@gmail.com 13 | EMAIL_HOST_PASSWORD= 14 | 15 | POSTGRES_DB= 16 | POSTGRES_USER= 17 | POSTGRES_PASSWORD= 18 | #POSTGRES_HOST_AUTH_METHOD=trust -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Build and Push 2 | 3 | on: 4 | push: 5 | branches: [ "onrender" ] 6 | 7 | jobs: 8 | 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Build and push Docker images 16 | run: | 17 | docker-compose -f docker-compose.yml build 18 | echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin 19 | docker-compose -f docker-compose.yml push -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/django 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=django 3 | 4 | ### Django ### 5 | *.log 6 | *.pot 7 | *.pyc 8 | __pycache__/ 9 | local_settings.py 10 | db.sqlite3 11 | db.sqlite3-journal 12 | media 13 | staticfiles 14 | migrations/ 15 | 0001_initial.py 16 | 17 | # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ 18 | # in your Git repository. Update and uncomment the following line accordingly. 19 | # /staticfiles/ 20 | 21 | ### Django.Python Stack ### 22 | # Byte-compiled / optimized / DLL files 23 | *.py[cod] 24 | *$py.class 25 | 26 | # Node modules 27 | node_modules/ 28 | 29 | .vscode/ 30 | 31 | # C extensions 32 | *.so 33 | 34 | # Distribution / packaging 35 | .Python 36 | build/ 37 | develop-eggs/ 38 | dist/ 39 | downloads/ 40 | eggs/ 41 | .eggs/ 42 | lib/ 43 | lib64/ 44 | parts/ 45 | sdist/ 46 | var/ 47 | wheels/ 48 | share/python-wheels/ 49 | *.egg-info/ 50 | .installed.cfg 51 | *.egg 52 | MANIFEST 53 | 54 | # PyInstaller 55 | # Usually these files are written by a python script from a template 56 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 57 | *.manifest 58 | *.spec 59 | 60 | # Installer logs 61 | pip-log.txt 62 | pip-delete-this-directory.txt 63 | 64 | # Unit test / coverage reports 65 | htmlcov/ 66 | .tox/ 67 | .nox/ 68 | .coverage 69 | .coverage.* 70 | .cache 71 | nosetests.xml 72 | coverage.xml 73 | *.cover 74 | *.py,cover 75 | .hypothesis/ 76 | .pytest_cache/ 77 | cover/ 78 | 79 | # Translations 80 | *.mo 81 | 82 | # Django stuff: 83 | 84 | # Flask stuff: 85 | instance/ 86 | .webassets-cache 87 | 88 | # Scrapy stuff: 89 | .scrapy 90 | 91 | # Sphinx documentation 92 | docs/_build/ 93 | 94 | # PyBuilder 95 | .pybuilder/ 96 | target/ 97 | 98 | # Jupyter Notebook 99 | .ipynb_checkpoints 100 | 101 | # IPython 102 | profile_default/ 103 | ipython_config.py 104 | 105 | # pyenv 106 | # For a library or package, you might want to ignore these files since the code is 107 | # intended to run in multiple environments; otherwise, check them in: 108 | # .python-version 109 | 110 | # pipenv 111 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 112 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 113 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 114 | # install all needed dependencies. 115 | #Pipfile.lock 116 | 117 | # poetry 118 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 119 | # This is especially recommended for binary packages to ensure reproducibility, and is more 120 | # commonly ignored for libraries. 121 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 122 | #poetry.lock 123 | 124 | # pdm 125 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 126 | #pdm.lock 127 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 128 | # in version control. 129 | # https://pdm.fming.dev/#use-with-ide 130 | .pdm.toml 131 | 132 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 133 | __pypackages__/ 134 | 135 | # Celery stuff 136 | celerybeat-schedule 137 | celerybeat.pid 138 | 139 | # SageMath parsed files 140 | *.sage.py 141 | 142 | # Environments 143 | .env 144 | .venv 145 | env/ 146 | venv/ 147 | ENV/ 148 | env.bak/ 149 | venv.bak/ 150 | 151 | # Spyder project settings 152 | .spyderproject 153 | .spyproject 154 | 155 | # Rope project settings 156 | .ropeproject 157 | 158 | # mkdocs documentation 159 | /site 160 | 161 | # mypy 162 | .mypy_cache/ 163 | .dmypy.json 164 | dmypy.json 165 | 166 | # Pyre type checker 167 | .pyre/ 168 | 169 | # pytype static type analyzer 170 | .pytype/ 171 | 172 | # Cython debug symbols 173 | cython_debug/ 174 | 175 | # PyCharm 176 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 177 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 178 | # and can be added to the global gitignore or merged into this file. For a more nuclear 179 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 180 | #.idea/ 181 | 182 | # End of https://www.toptal.com/developers/gitignore/api/django 183 | 184 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | FROM python:alpine 3 | 4 | ENV PIP_ROOT_USER_ACTION=ignore \ 5 | PYTHONUNBUFFERED=1 \ 6 | PYTHONDONTWRITEBYTECODE=1 7 | #PIP_NO_CACHE_DIR=off 8 | 9 | # Copy only requirements.txt first to leverage Docker cache 10 | COPY requirements.txt /indianpong/requirements.txt 11 | 12 | RUN pip install --upgrade pip && pip install -r /indianpong/requirements.txt 13 | 14 | # After the packages are installed, copy the rest of your application 15 | COPY indianpong /indianpong 16 | 17 | RUN chmod +x /indianpong/start.sh 18 | 19 | EXPOSE 8001 20 | 21 | CMD [ "sh", "/indianpong/start.sh" ] 22 | 23 | 24 | -------------------------------------------------------------------------------- /Dockerfile.nginx: -------------------------------------------------------------------------------- 1 | FROM nginx:alpine 2 | 3 | # Update package list and install openssl 4 | RUN apk update && apk add openssl 5 | 6 | # Create a directory for the certificates 7 | # Generate a self-signed certificate 8 | RUN mkdir -p /etc/nginx/ssl && \ 9 | openssl req -x509 -newkey rsa:4096 -keyout /etc/nginx/ssl/key.pem -out /etc/nginx/ssl/cert.pem -days 365 -nodes -subj '/CN=localhost' 10 | 11 | # Copy the Nginx configuration file 12 | COPY nginx.conf /etc/nginx/nginx.conf 13 | 14 | # Expose the Nginx port 15 | EXPOSE 8000 16 | EXPOSE 8443 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DOCKER = docker 2 | DOCKER_COMPOSE = docker-compose 3 | SUDO_DOCKER_COMPOSE = sudo docker-compose 4 | 5 | all: up 6 | 7 | sudo_up: 8 | $(SUDO_DOCKER_COMPOSE) up -d --build 9 | 10 | up: 11 | $(DOCKER_COMPOSE) up -d --build 12 | 13 | down: 14 | $(DOCKER_COMPOSE) down 15 | 16 | image: 17 | $(DOCKER_COMPOSE) images 18 | 19 | stop: 20 | $(DOCKER_COMPOSE) stop 21 | 22 | fclean: 23 | $(DOCKER_COMPOSE) down --rmi all 24 | 25 | prune: down fclean 26 | $(DOCKER) system prune -a -f 27 | 28 | re: fclean all 29 | 30 | .PHONY: all up down image stop fclean re sudo_up -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker-compose.yaml 2 | version: '3.9' 3 | 4 | services: 5 | db: 6 | image: postgres:13-alpine 7 | restart: always 8 | volumes: 9 | - db_data:/var/lib/postgresql/data 10 | ports: 11 | - "5432:5432" 12 | env_file: 13 | - .env 14 | 15 | web: 16 | build: 17 | context: . 18 | dockerfile: Dockerfile 19 | volumes: 20 | - staticfiles:/indianpong/staticfiles 21 | - media:/indianpong/media 22 | - ssl_data:/etc/nginx/ssl 23 | env_file: 24 | - .env 25 | ports: 26 | - 8001:8001 27 | depends_on: 28 | - db 29 | 30 | nginx: 31 | build: 32 | context: . 33 | dockerfile: Dockerfile.nginx 34 | volumes: 35 | - staticfiles:/indianpong/staticfiles 36 | - media:/indianpong/media 37 | - ssl_data:/etc/nginx/ssl 38 | ports: 39 | - 8000:8000 40 | - 8443:8443 41 | depends_on: 42 | - web 43 | 44 | volumes: 45 | db_data: 46 | staticfiles: 47 | media: 48 | ssl_data: -------------------------------------------------------------------------------- /indianpong/indianpong/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/indianpong/__init__.py -------------------------------------------------------------------------------- /indianpong/indianpong/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for indianpong project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | from channels.routing import ProtocolTypeRouter, URLRouter 14 | from channels.auth import AuthMiddlewareStack 15 | from . import routing 16 | 17 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'indianpong.settings') 18 | 19 | #application = get_asgi_application() 20 | 21 | application = ProtocolTypeRouter({ 22 | 'http': get_asgi_application(), 23 | 'websocket': AuthMiddlewareStack( 24 | URLRouter( 25 | routing.websocket_urlpatterns 26 | ) 27 | ), 28 | }) -------------------------------------------------------------------------------- /indianpong/indianpong/routing.py: -------------------------------------------------------------------------------- 1 | 2 | from django.urls import re_path 3 | from django.urls import path 4 | 5 | from pong import consumer_pong, consumer_rps, consumer_status, consumer_chat 6 | 7 | websocket_urlpatterns = [ 8 | path('ws/online_status/', consumer_status.OnlineStatusConsumer.as_asgi()), 9 | 10 | re_path(r'^ws/chat/(?P[\w-]+)/$', consumer_chat.ChatConsumer.as_asgi()), 11 | re_path(r'^ws/remote-game/(?P[-\w]+)/(?P[\w-]+)/$', consumer_pong.PongConsumer.as_asgi()), 12 | re_path(r'^ws/rps/$', consumer_rps.RPSConsumer.as_asgi()), 13 | ] 14 | -------------------------------------------------------------------------------- /indianpong/indianpong/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URL configuration for indianpong project. 3 | 4 | The `urlpatterns` list routes URLs to views. For more information please see: 5 | https://docs.djangoproject.com/en/5.0/topics/http/urls/ 6 | Examples: 7 | Function views 8 | 1. Add an import: from my_app import views 9 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 10 | Class-based views 11 | 1. Add an import: from other_app.views import Home 12 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 13 | Including another URLconf 14 | 1. Import the include() function: from django.urls import include, path 15 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 16 | """ 17 | from django.conf import settings 18 | from django.conf.urls.static import static 19 | from django.contrib import admin 20 | from django.urls import path 21 | from pong.views import get_useritems, play_rps, local_tournament, play_rps_ai, aboutus, follow_unfollow, remote_game, tournament_room, tournament_create, local_game, tournament, tournament_room_list, update_winner, inventory, store, activate_account, play_ai, pong_game_find, rps_game_find, auth_callback, chat, friends, password_change, password_reset, password_reset_done, rankings, dashboard, index, auth, profile_view, search, set_password, signup, login_view, logout_view, profile_settings, start_chat, room 22 | 23 | urlpatterns = [ 24 | path('admin/', admin.site.urls), 25 | path('', index, name='index'), 26 | path('signup', signup, name='signup'), 27 | path('activate//', activate_account, name='activate'), 28 | path('login', login_view, name='login'), 29 | path('auth', auth, name='auth'), 30 | path('auth_callback', auth_callback, name='auth_callback'), 31 | path('logout', logout_view, name='logout'), 32 | path('rps-game-find', rps_game_find, name='rps_game_find'), 33 | path('pong-game-find', pong_game_find, name='pong_game_find'), 34 | path('play-ai//', play_ai, name='play_ai'), 35 | path('remote-game//', remote_game, name='remote_game'), 36 | path('local-game', local_game, name='local_game'), 37 | path('local-tournament', local_tournament, name='local_tournament'), 38 | path('chat/', chat, name='chat'), 39 | path("start_chat/", start_chat, name="start_chat"), 40 | path("chat//", room, name="room"), 41 | path("tournament", tournament, name="tournament"), 42 | path('tournament-room/', tournament_room, name="tournament-room"), 43 | path("tournament-create", tournament_create, name="tournament_create"), 44 | path("tournament-room-list", tournament_room_list, name="tournament_room_list"), 45 | path('dashboard', dashboard, name='dashboard'), 46 | path('friends/', friends, name='friends'), 47 | path('about-us', aboutus, name='aboutus'), 48 | path('rankings', rankings, name='rankings'), 49 | path('inventory//', inventory, name='inventory'), 50 | path('store//', store, name='store'), 51 | path('search', search, name='search'), 52 | path('follow_unfollow/', follow_unfollow, name='follow_unfollow'), 53 | path('get_useritems', get_useritems, name='get_useritems'), 54 | path('update_winner/', update_winner, name='update_winner'), 55 | path('profile/', profile_view, name='profile'), 56 | path('profile//settings', profile_settings, name='profile_settings'), 57 | path('password_change', password_change, name='password_change'), 58 | path('password_reset', password_reset, name='password_reset'), 59 | path('password_reset_confirm///', password_reset, name='password_reset_confirm'), 60 | path('password_reset_done', password_reset_done, name='password_reset_done'), 61 | path('set_password///', set_password, name='set_password'), 62 | path('play-rps-ai', play_rps_ai, name='play_rps_ai'), 63 | path('play-rps', play_rps, name='play-rps'), 64 | 65 | ] 66 | 67 | handler404 = 'pong.views.handler404' 68 | 69 | if settings.DEBUG: 70 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -------------------------------------------------------------------------------- /indianpong/indianpong/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for indianpong project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'indianpong.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /indianpong/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'indianpong.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /indianpong/pong/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/pong/__init__.py -------------------------------------------------------------------------------- /indianpong/pong/admin.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib import admin 3 | from .models import OAuthToken, Social, UserGameStatRPS, UserItem, StoreItem, UserProfile, Tournament, Room, Message, Game, UserGameStat 4 | from django.utils.html import format_html 5 | 6 | 7 | @admin.register(UserProfile) 8 | class UserProfileAdmin(admin.ModelAdmin): 9 | """ 10 | Admin class for managing user profiles. 11 | 12 | Attributes: 13 | list_display (tuple): A tuple of fields to be displayed in the admin list view. 14 | search_fields (tuple): A tuple of fields to be used for searching in the admin list view. 15 | fieldsets (tuple): A tuple of fieldsets to be displayed in the admin edit view. 16 | """ 17 | 18 | list_display = ('username', 'email', 'displayname', 'avatar_thumbnail') 19 | search_fields = ('username', 'email', 'displayname') 20 | fieldsets = ( 21 | ('User Information', {'fields': ('username', 'password', 'displayname', 'email', 'avatar', 'friends', 'elo_point', 'indian_wallet', 'blocked_users')}), 22 | ('Dates', {'fields': ('date_joined', 'last_login')}), 23 | ('Roles', {'fields': ('is_staff', 'is_active', 'is_superuser', 'is_verified', 'is_42student', 'is_indianai')}), 24 | ('Permissions', {'fields': ('groups', 'user_permissions')}), 25 | ) 26 | 27 | def avatar_thumbnail(self, obj): 28 | return format_html(obj.thumbnail) 29 | avatar_thumbnail.short_description = 'Avatar' 30 | 31 | @admin.register(StoreItem) 32 | class StoreAdmin(admin.ModelAdmin): 33 | list_display = ('category_name', 'name', 'name_hi', 'name_pt', 'name_tr', 'image_url', 'description', 'description_hi', 'description_pt', 'description_tr', 'price', 'keypress', 'show_status') 34 | search_fields = ('name', 'description') 35 | 36 | def __str__(self): 37 | return self.name 38 | 39 | class UserItemForm(forms.ModelForm): 40 | class Meta: 41 | model = UserItem 42 | fields = ('user', 'item', 'whatis', 'is_bought', 'is_equipped') 43 | 44 | def __init__(self, *args, **kwargs): 45 | super().__init__(*args, **kwargs) 46 | self.fields['item'].label_from_instance = lambda obj: obj.name 47 | 48 | @admin.register(UserItem) 49 | class UserItemAdmin(admin.ModelAdmin): 50 | form = UserItemForm 51 | list_display = ('user', 'get_item_name', 'whatis', 'is_bought', 'is_equipped') 52 | list_filter = ('is_equipped',) 53 | search_fields = ('user__username', 'item__name') 54 | 55 | def get_item_name(self, obj): 56 | return obj.item.name 57 | 58 | get_item_name.short_description = 'Item Name' 59 | 60 | @admin.register(UserGameStat) 61 | class UserGameStatAdmin(admin.ModelAdmin): 62 | list_display = ('get_user', 'total_games_pong', 'total_win_pong', 'total_lose_pong', 'total_win_streak_pong', 'total_win_rate_pong', 'total_lose_streak_pong', 'total_avg_game_duration_pong', 'total_avg_points_won_pong', 'total_avg_points_lost_pong') 63 | search_fields = ('userprofile__username', 'total_win_pong',) 64 | 65 | def get_user(self, obj): 66 | return obj.userprofile 67 | get_user.short_description = 'User' 68 | 69 | @admin.register(UserGameStatRPS) 70 | class UserGameStatRPSAdmin(admin.ModelAdmin): 71 | list_display = ('get_user', 'total_games_rps', 'total_win_rps', 'total_lose_rps', 'total_win_streak_rps', 'total_win_rate_rps', 'total_lose_streak_rps', 'total_avg_game_duration_rps', 'total_avg_points_won_rps', 'total_avg_points_lost_rps') 72 | search_fields = ('userprofile__username', 'total_win_rps',) 73 | 74 | def get_user(self, obj): 75 | return obj.userprofile 76 | get_user.short_description = 'User' 77 | 78 | @admin.register(Social) 79 | class SocialAdmin(admin.ModelAdmin): 80 | list_display = ('get_user', 'intra42', 'linkedin', 'github', 'twitter') 81 | 82 | def get_user(self, obj): 83 | return obj.userprofile 84 | get_user.short_description = 'User' 85 | 86 | search_fields = ('userprofile__username', 'intra42', 'linkedin', 'github', 'twitter') 87 | 88 | 89 | @admin.register(Game) 90 | class GameAdmin(admin.ModelAdmin): 91 | list_display = ('game_kind' ,'tournament_id', 'group_name', 'player1', 'player2', 'winner_score', 'loser_score', 'created_at', 'game_duration', 'winner', 'loser') 92 | list_filter = ('player1', 'player2', 'winner', 'loser') 93 | search_fields = ('player1__username', 'player2__username', 'group_name') 94 | 95 | @admin.register(Tournament) 96 | class TournamentAdmin(admin.ModelAdmin): 97 | list_display = ('name', 'creator', 'winner', 'start_date', 'status') 98 | search_fields = ('name', 'status') 99 | 100 | @admin.register(Room) 101 | class RoomAdmin(admin.ModelAdmin): 102 | list_display = ["first_user", "second_user"] 103 | 104 | @admin.register(Message) 105 | class MessageAdmin(admin.ModelAdmin): 106 | list_display = ["user", "room", "created_date"] 107 | 108 | 109 | @admin.register(OAuthToken) 110 | class OAuthTokenAdmin(admin.ModelAdmin): 111 | list_display = ('user', 'access_token', 'refresh_token', 'expires_in', 'created_at', 'secret_valid_until') 112 | search_fields = ('user__username',) 113 | 114 | 115 | -------------------------------------------------------------------------------- /indianpong/pong/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | #from django.contrib.auth.signals import user_logged_in, user_logged_out 3 | #from django.dispatch import receiver 4 | 5 | 6 | class PongConfig(AppConfig): 7 | default_auto_field = 'django.db.models.BigAutoField' 8 | name = 'pong' 9 | 10 | """ def ready(self): 11 | 12 | @receiver(user_logged_in) 13 | def user_logged_in_handler(sender, request, **kwargs): 14 | request.user.is_online = True 15 | request.user.save() 16 | 17 | @receiver(user_logged_out) 18 | def user_logged_out_handler(sender, request, **kwargs): 19 | request.user.is_online = False 20 | request.user.save() """ 21 | 22 | -------------------------------------------------------------------------------- /indianpong/pong/consumer_status.py: -------------------------------------------------------------------------------- 1 | from channels.generic.websocket import AsyncWebsocketConsumer 2 | from django.core.cache import cache 3 | #from .models import UserProfile 4 | import json 5 | 6 | class OnlineStatusConsumer(AsyncWebsocketConsumer): 7 | async def connect(self): 8 | self.user = self.scope['user'] 9 | if self.user.is_anonymous: 10 | return 11 | 12 | """ # get UserProfile object 13 | user_profile = await UserProfile.objects.aget(id=self.user.id) 14 | user_profile.is_online = True 15 | await user_profile.asave() 16 | # Add user ID to online_users list 17 | add_to_cache('online_users', set(), self.user.id) """ 18 | cache.set(f'online_{self.user.username}', True) 19 | cache.set(f'playing_{self.user.username}', False) #TODO spada çalışmıyabilir 20 | # Maybe add playing to the cache 21 | await self.accept() 22 | 23 | await self.send(text_data=json.dumps({ 24 | 'status': 'online', 25 | })) 26 | 27 | 28 | async def disconnect(self, close_code): 29 | if self.user.is_anonymous: 30 | return 31 | 32 | cache.set(f'online_{self.user.username}', False) 33 | # Maybe add playing to the cache 34 | """ user_profile = await UserProfile.objects.aget(id=self.user.id) 35 | user_profile.is_online = False 36 | await user_profile.asave() 37 | # Remove user ID from online_users list 38 | remove_from_cache('online_users', set(), self.user.id) """ 39 | await self.close() 40 | -------------------------------------------------------------------------------- /indianpong/pong/management/commands/initdata.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from pong.models import UserProfile, StoreItem 3 | from django.core.files import File 4 | from os import environ 5 | import json 6 | 7 | class Command(BaseCommand): 8 | def handle(self, *args, **options): 9 | # Create superuser if not exists 10 | superuser = environ.get("SUPER_USER") 11 | supermail = environ.get("SUPER_MAIL") 12 | superpass = environ.get("SUPER_PASS") 13 | if not UserProfile.objects.filter(username=superuser).exists(): 14 | super_user = UserProfile.objects.create_superuser(superuser, supermail, superpass) 15 | file = File(open('static/assets/profile/default_avatar.jpeg', "rb")) 16 | super_user.avatar.save(f"{file.name}.jpg", file, save=False) 17 | file.close() 18 | super_user.indian_wallet = 1000 19 | super_user.is_verified = True 20 | super_user.save() 21 | self.stdout.write(self.style.SUCCESS('Superuser created successfully.')) 22 | # Create IndianAI if not exists 23 | if not UserProfile.objects.filter(username="IndianAI").exists(): 24 | user = UserProfile.objects.create_user(username="IndianAI", email="indianpong@gmail.com") 25 | user.set_unusable_password() 26 | user.displayname = "Sitting AI" 27 | file = File(open('static/assets/profile/indianai.jpg', "rb")) 28 | user.avatar.save(f"{file.name}.jpg", file, save=False) 29 | file.close() 30 | user.is_verified = True 31 | user.is_online = True 32 | user.indian_wallet = 1000 33 | user.is_indianai = True 34 | user.elo_point = 1000 35 | user.save() 36 | self.stdout.write(self.style.SUCCESS('IndianAI created successfully.')) 37 | 38 | # Load store data 39 | if not StoreItem.objects.filter(name="My Beautiful AI").exists(): 40 | with open('static/assets/stores/store_data.json') as f: 41 | data = json.load(f) 42 | 43 | for item_data in data: 44 | StoreItem.objects.create(**item_data) 45 | 46 | self.stdout.write(self.style.SUCCESS('Store data loaded successfully.')) 47 | 48 | self.stdout.write(self.style.SUCCESS('Data initialization completed successfully.')) 49 | 50 | 51 | -------------------------------------------------------------------------------- /indianpong/pong/management/commands/populate.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.hashers import make_password 2 | from pong.models import UserProfile, UserGameStat, Social 3 | from random import randint 4 | from django.core.management.base import BaseCommand 5 | from datetime import timedelta 6 | 7 | class Command(BaseCommand): 8 | help = 'Populates the database with users' 9 | 10 | def add_arguments(self, parser): 11 | parser.add_argument('num_users', type=int, help='Number of users to create') 12 | 13 | def handle(self, *args, **options): 14 | if not UserProfile.objects.filter(username="Indian0").exists(): 15 | num_users = options['num_users'] 16 | user_game_stats_pong = [] 17 | socials = [] 18 | user_profiles = [] 19 | password = make_password('123456a.') 20 | 21 | for i in range(num_users): 22 | username = "Indian" + str(i) 23 | displayname = "Original Indian" + str(i) 24 | email = username + '@indian.com' 25 | 26 | # Prepare UserGameStat instance 27 | game_stat = UserGameStat( 28 | total_games_pong=randint(0, 100), 29 | total_win_pong=randint(0, 100), 30 | total_lose_pong=randint(0, 100), 31 | total_win_streak_pong=randint(0, 100), 32 | total_lose_streak_pong=randint(0, 100), 33 | total_win_rate_pong=randint(0, 100) / 100.0, 34 | total_avg_game_duration_pong=timedelta(seconds=randint(0, 3600)), 35 | total_avg_points_won_pong=randint(0, 100), 36 | total_avg_points_lost_pong=randint(0, 100) 37 | ) 38 | user_game_stats_pong.append(game_stat) 39 | 40 | # Prepare Social instance 41 | social = Social( 42 | intra42 = username, 43 | linkedin = username, 44 | github = username, 45 | twitter= username, 46 | ) 47 | socials.append(social) 48 | 49 | # Prepare UserProfile instance 50 | user_profile = UserProfile( 51 | username=username, 52 | email=email, 53 | displayname=displayname, 54 | password=password, 55 | game_stats_pong=game_stat, 56 | social=social, 57 | is_verified=True 58 | ) 59 | user_profiles.append(user_profile) 60 | 61 | # Create instances in database 62 | UserGameStat.objects.bulk_create(user_game_stats_pong) 63 | Social.objects.bulk_create(socials) 64 | #UserProfile.objects.bulk_create(user_profiles) 65 | # Create UserProfile instances individually to trigger save method 66 | for user_profile in user_profiles: 67 | user_profile.save() 68 | 69 | self.stdout.write(self.style.SUCCESS(f'Successfully populated the database with {num_users} users.')) 70 | else: 71 | self.stdout.write(self.style.SUCCESS('Database already populated.')) -------------------------------------------------------------------------------- /indianpong/pong/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/pong/migrations/__init__.py -------------------------------------------------------------------------------- /indianpong/pong/rps.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | import time 3 | 4 | class Choices(Enum): 5 | ROCK = 0 6 | PAPER = 1 7 | SCISSORS = 2 8 | 9 | class Abilities(Enum): 10 | LIKEACHEATER = 3, 11 | GODOFTHINGS = 4 12 | 13 | class RoundResult(Enum): 14 | DRAW = 0 15 | PLAYER1_WIN = 1 16 | PLAYER2_WIN = 2 17 | 18 | KV_CHOICES = {'rock': Choices.ROCK, 'paper': Choices.PAPER, 'scissors': Choices.SCISSORS, 'godthings': Abilities.GODOFTHINGS, 'cheater': Abilities.LIKEACHEATER} 19 | 20 | class Shaker: 21 | def __init__(self, username): 22 | self.username = username 23 | self.score = 0 24 | self.choices = [] 25 | 26 | class RPS: 27 | def __init__(self, player1, player2): 28 | self.shaker1 = Shaker(player1) 29 | self.shaker2 = Shaker(player2) 30 | self.max_score = 3 31 | self.group_name = f'rps_{player1}_{player2}' 32 | self.start_time = 0 33 | self.end_time = 0 34 | 35 | def play(self, username, choice): 36 | if (self.start_time == 0): 37 | self.start_time = time.time() 38 | if username == self.shaker1.username: 39 | self.shaker1.choices.append(KV_CHOICES[choice]) 40 | elif username == self.shaker2.username: 41 | self.shaker2.choices.append(KV_CHOICES[choice]) 42 | 43 | def ability_result(self, choice1, choice2): 44 | ab1 = choice1 == Abilities.LIKEACHEATER or choice1 == Abilities.GODOFTHINGS 45 | ab2 = choice2 == Abilities.LIKEACHEATER or choice2 == Abilities.GODOFTHINGS 46 | if ab1 and ab2: #both played this it's draw 47 | return 0 48 | elif ab1 and choice1 == Abilities.LIKEACHEATER: #stole opponent score if greater than 0 49 | if self.shaker2.score > 0: 50 | self.shaker2.score -= 1 51 | self.shaker1.score += 1 52 | return 1 53 | elif ab2 and choice2 == Abilities.LIKEACHEATER: #won round instantly 54 | if self.shaker1.score > 0: 55 | self.shaker1.score -= 1 56 | self.shaker2.score += 1 57 | return 2 58 | elif ab1 and choice1 == Abilities.GODOFTHINGS: 59 | self.shaker1.score += 1 60 | return 1 61 | elif ab2 and choice2 == Abilities.GODOFTHINGS: 62 | self.shaker2.score += 1 63 | return 2 64 | else: 65 | return 3 66 | 67 | 68 | def round_result(self): 69 | shaker1_choice = self.shaker1.choices.pop() 70 | shaker2_choice = self.shaker2.choices.pop() 71 | result = self.ability_result(shaker1_choice, shaker2_choice) 72 | if result == 0: 73 | return RoundResult.DRAW.name 74 | elif result == 1: 75 | return RoundResult.PLAYER1_WIN.name 76 | elif result == 2: 77 | return RoundResult.PLAYER2_WIN.name 78 | result = (shaker1_choice.value - shaker2_choice.value) % 3 79 | if result == 0: 80 | return RoundResult.DRAW.name 81 | elif result == 1: 82 | self.shaker1.score += 1 83 | return RoundResult.PLAYER1_WIN.name 84 | else: 85 | self.shaker2.score += 1 86 | return RoundResult.PLAYER2_WIN.name 87 | 88 | def check_is_over(self): 89 | if self.shaker1.score == self.max_score or self.shaker2.score == self.max_score: 90 | self.end_time = time.time() 91 | return True 92 | return False 93 | 94 | def get_winner_loser(self): 95 | if self.shaker1.score > self.shaker2.score: 96 | return self.shaker1.username, self.shaker2.username 97 | else: 98 | return self.shaker2.username, self.shaker1.username 99 | 100 | def otherPlayer(self, username): 101 | if username == self.shaker1.username: 102 | return self.shaker2.username 103 | else: 104 | return self.shaker1.username 105 | 106 | def get_scores(self): 107 | return self.shaker1.score, self.shaker2.score 108 | 109 | def getDuration(self): 110 | if self.start_time == 0: 111 | return 0 112 | if self.end_time == 0: 113 | self.end_time = time.time() 114 | return self.end_time - self.start_time 115 | 116 | def getWinnerLoserandScores(self): 117 | if self.shaker1.score > self.shaker2.score: 118 | return self.shaker1.username, self.shaker2.username, self.shaker1.score, self.shaker2.score 119 | else: 120 | return self.shaker2.username, self.shaker1.username, self.shaker2.score, self.shaker1.score 121 | 122 | def both_played(self): 123 | return len(self.shaker1.choices) == len(self.shaker2.choices) == 1 124 | 125 | def getChoices(self): 126 | return self.shaker1.choices[0].name, self.shaker2.choices[0].name 127 | -------------------------------------------------------------------------------- /indianpong/pong/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "base.html" %} 3 | 4 | {% block title %}{{context.notFoundPageTittle}}{% endblock %} 5 | 6 | {% block app %} 7 |
8 |
404 ERROR
9 |
{{context.notFoundSubHeaderText}}
10 | 23 |
24 | {% endblock app %} -------------------------------------------------------------------------------- /indianpong/pong/templates/_nav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% load static %} 4 | {% load transnav %} 5 | {% load user_info %} 6 | 7 | 65 | {% if not request.user.is_anonymous %} 66 | 67 | 93 | {% endif %} 94 | -------------------------------------------------------------------------------- /indianpong/pong/templates/activation_fail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{context.activationFailedPageTittle}}{% endblock %} 4 | 5 | {% block app %} 6 |
7 |
{{context.activationFailedHeaderText}}
8 |
{{context.activationFailedSubHeaderText}}
9 | 22 |
23 | {% endblock app %} -------------------------------------------------------------------------------- /indianpong/pong/templates/chat.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | {% load status %} 4 | 5 | {% block title %} 6 | {{context.chatPageTittle}} 7 | {% endblock %} 8 | 9 | {% block stylesheet %} 10 | 11 | {% endblock stylesheet %} 12 | 13 | 14 | {% block app %} 15 |
16 |
17 |
18 |
19 | 20 | 27 | 28 | 29 |
30 | 31 | 52 | {% block diff %} 53 | 54 | 55 |
56 | 57 |

{{context.chatContainerSelectText}}

58 |
59 |
60 | 61 |
62 | 63 | {% endblock diff %} 64 |
65 |
66 |
67 | {% csrf_token %} 68 | 69 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{context.dashboardPageTittle}}{% endblock title %} 4 | 5 | {% block app %} 6 | 7 |
8 |
9 |
10 |

{{context.dashboardText1}}{{ profile.username }}!

11 |

12 | {{context.dashboardText2}} 13 |

14 |
15 |
16 |
17 |
18 |
{{context.dashboardGamesPlayed}}
19 |

20 | {% if profile.game_stats_pong.total_games_pong %} {{ profile.game_stats_pong.total_games_pong }} {% else %} 0 {% endif %} 21 |

22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 |
{{context.dashboardWinCount}}
30 |

31 | {% if profile.game_stats_pong.total_win_pong %} {{ profile.game_stats_pong.total_win_pong }} {% else %} 0 {% endif %} 32 |

33 |
34 |
35 |
36 | 37 |
38 |
39 |
40 |
{{context.dashboardWinStreak}}
41 |

42 | {% if profile.game_stats_pong.total_win_streak_pong %} {{ profile.game_stats_pong.total_win_streak_pong }} {% else %} 0 {% endif %} 43 |

44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 |
{{context.dashboardLoseStreak}}
52 |

53 | {% if profile.game_stats_pong.total_lose_streak_pong %} {{ profile.game_stats_pong.total_lose_streak_pong }} {% else %} 0 {% endif %} 54 |

55 |
56 |
57 |
58 | 59 |
60 |
61 |
62 |
{{context.dashboardWinRate}} %
63 |

64 | {% if profile.game_stats_pong.formatted_win_rate %} {{ profile.game_stats_pong.formatted_win_rate }} {% else %} 0 {% endif %} 65 |

66 |
67 |
68 |
69 | 70 |
71 |
72 |
73 |
{{context.dashboardAverageGameDuration}}
74 |

75 | 76 | {% if profile.game_stats_pong.formatted_game_duration %} {{ profile.game_stats_pong.formatted_game_duration }} {% else %} 0 {% endif %} 77 |

78 |
79 |
80 |
81 | 82 |
83 |
84 |
85 |
{{context.dashboardAveragePointsWon}}
86 |

87 | {% if profile.game_stats_pong.formatted_avg_points_won %} {{ profile.game_stats_pong.formatted_avg_points_won }} {% else %} 0 {% endif %} 88 |

89 |
90 |
91 |
92 | 93 |
94 |
95 |
96 |
{{context.dashboardAveragePointsLost}}
97 |

98 | {% if profile.game_stats_pong.formatted_avg_points_lost %} {{ profile.game_stats_pong.formatted_avg_points_lost }} {% else %} 0 {% endif %} 99 |

100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/local-game.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load static %} 4 | 5 | {% block title %}{{context.localGamePageTittle}}{% endblock title %} 6 | 7 | {% block stylesheet %}{% endblock %} 8 | 9 | {% block app %} 10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 |

{{context.localGameHeaderText}}

21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 36 |
37 | 38 |
39 | 40 | 44 |
45 |
46 | 47 | 48 | 49 |
50 | 51 |
52 |

53 |

{{context.aiGameGameOverText}}

54 | 55 | 56 |
57 |
58 |
59 | 115 | 116 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% load static %} 5 | 6 | {% block title %}{{context.loginPageTittle}}{% endblock title %} 7 | 8 | 9 | {% block app %} 10 | 11 |
12 |
13 |
14 |
15 | 29 |
30 | {{context.loginHeaderText1}} 31 | {{context.loginHeaderText2}} 32 |
33 | 36 | {% csrf_token %} 37 |

38 | 39 |

40 |

41 | 42 | 43 |

44 | 47 | 48 | 49 |
50 |
51 |
52 |
53 | 64 |
65 |
66 | 69 | 70 | {% endblock %} 71 | 72 | 73 | {% comment %} {% if messages %} 74 |
    75 | {% for message in messages %} 76 | {{ message }} 77 | {% endfor %} 78 |
79 | {% endif %} {% endcomment %} -------------------------------------------------------------------------------- /indianpong/pong/templates/password_change.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends 'base.html' %} 4 | 5 | {% block title %}Password Change{% endblock %} 6 | 7 | {% block app %} 8 | 9 |
10 |
11 |
12 |
13 |
14 | Change Password 15 | change your password 16 |
17 | {% csrf_token %} 18 | {{ form.as_p }} 19 | 20 |
21 |
22 |
23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /indianpong/pong/templates/password_reset.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %}{{context.forgotPasswordPageTittle}}{% endblock %} 6 | 7 | {% block stylesheet %}{% endblock %} 8 | 9 | {% block app %} 10 | 11 | 12 |
13 |
14 |
15 |
16 | 24 |
25 | {{context.forgotPasswordHeaderText}} 26 |
27 | {% csrf_token %} 28 | 29 | {% comment %} {% endcomment %} 30 | 31 | 35 |
36 |
37 |
38 |
39 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{context.passwordResetDonePageTittle}}{% endblock %} 4 | 5 | {% block app %} 6 |
7 |
{{context.passwordResetDoneHeaderText}}
8 |
{{context.passwordResetDoneSubHeaderText}}
9 | 22 | 23 |
24 | {% endblock app %} -------------------------------------------------------------------------------- /indianpong/pong/templates/play-ai.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load static %} 4 | 5 | {% block title %}{{context.aiGamePageTittle}}{% endblock title %} 6 | 7 | {% block stylesheet %} 8 | 9 | 10 | {% endblock %} 11 | 12 | {% block app %} 13 | 14 |
15 |
16 |
17 |
18 | 19 | 20 |
21 | 22 |
23 |
24 |
25 |
26 | 27 | 28 |
29 |

{{context.aiGameGetReadyText}}!

30 | 31 |
32 |
33 |
34 |

35 |

36 |

{{context.aiGameGameOverText}}

37 | 38 | 39 |
40 |
41 |
42 | 98 | 99 | 100 | {% csrf_token %} 101 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/play-rps-ai.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} 6 | {{context.rpsGamePageTittle}} 7 | {% endblock %} 8 | 9 | {% block stylesheet %}{% endblock %} 10 | 11 | {% block app %} 12 |
13 |
14 |
15 |
16 |
{{request.user.username}}
17 |
{{context.rpsGameScoreText}}
18 |
0
19 |
20 |

{{context.rpsGameRockText}}
{{context.rpsGamePaperText}}
{{context.rpsGameScissorsText}}

21 |
22 |
{% if not ainametag %} IndianAI {% else %} {{ainametag}} {% endif %}
23 |
{{context.rpsGameScoreText}}
24 |
0
25 |
26 |
27 |
28 |
29 | {% if cheater_rps == "true" %} 30 | 35 | {% endif %} 36 | {% if godthings_rps == "true" %} 37 | 42 | {% endif %} 43 | 48 | 53 | 58 |
59 |
60 | 61 | 71 | 72 |
73 |

74 |

{{context.rpsGameGameOverText}}

75 | 76 | 77 |
78 | 79 | 80 | {% csrf_token %} 81 | {% endblock %} 82 | -------------------------------------------------------------------------------- /indianpong/pong/templates/play-rps.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} 6 | Remote RPS 7 | {% endblock %} 8 | 9 | {% block stylesheet %} 10 | 11 | {% endblock %} 12 | 13 | {% block app %} 14 | 15 |
16 |

{{context.rpsUserCountText}}:

17 |
0
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | {{context.rpsGameSearchOpponentButtonText}} 29 |
30 |
31 | 79 | 80 | 83 | 89 | 90 |
91 |

92 |

{{context.rpsGameGameOverText}}

93 | 94 |
95 | 96 |
97 | 108 |
109 | 110 | 111 | {% endblock %} 112 | -------------------------------------------------------------------------------- /indianpong/pong/templates/pong-game-find.html: -------------------------------------------------------------------------------- 1 | ç{% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block title %}{{context.pongGamePageTittle}}{% endblock title %} 5 | 6 | {% block stylesheet %}{% endblock stylesheet %} 7 | 8 | {% block app %} 9 | 10 |
11 |
12 |

{{context.pongGameHeaderText}}

13 |
14 | {{context.pongGameSubHeaderText}} 15 |
16 | 33 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /indianpong/pong/templates/remote-game.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block title %} 5 | {{context.remotePongGamePageTittle}} 6 | {% endblock %} 7 | 8 | {% block stylesheet %} 9 | 10 | 11 | {% endblock %} 12 | 13 | {% block app %} 14 | 15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
{{context.remotePongGameTableName}}{{context.remotePongGameTableActions}}
29 | 30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 | 40 |
41 | 42 | 43 | {% comment %} 44 | 45 | {% endcomment %} 46 |
47 |
48 |
49 | 50 | 51 |
52 |

53 |

54 |

{{context.aiGameGameOverText}}

55 | 56 |
57 |
58 | 69 |
70 | 75 | 76 | {% csrf_token %} 77 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/rps-game-find.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block title %} 5 | {{context.rpsGamePageTittle}} 6 | {% endblock %} 7 | 8 | {% block stylesheet %}{% endblock stylesheet %} 9 | 10 | {% block app %} 11 |
12 |
13 |

{{context.rpsGameText1}}

14 |
{{context.rpsGameText2}}
15 | 31 |
32 |
33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /indianpong/pong/templates/set_password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends 'base.html' %} 4 | {% load static %} 5 | {% block title %}{{context.setPasswordPageTittle}}{% endblock %} 6 | 7 | {% block stylesheet %} 8 | 9 | {% endblock %} 10 | 11 | {% block app %} 12 |
13 |
14 |
15 |
16 | 17 | 30 | 31 |
32 | {{context.setPasswordHeaderText}}, 33 | {{context.setPassswordSubHeaderText}} 34 |
35 | {% csrf_token %} 36 |

37 | 38 |

39 |

40 | 41 |

42 | 43 |
44 |
45 |
46 |
47 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/tournament-create.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block title %}{{context.tournamentCreatePageTittle}}{% endblock title %} 5 | {% block stylesheet %}{% endblock stylesheet %} 6 | 7 | {% block app %} 8 |
9 |
10 |
11 |

{{context.tournamentCreateHeaderText}}

12 |
13 | {{context.tournamentCreateSubHeaderText}} 14 |
15 |
16 |
17 | {% csrf_token %} 18 |
19 |
20 | 21 | 22 | 23 | {% if form.name.errors %} 24 |
{{ form.name.errors }}
25 | {% endif %} 26 |
27 |
28 | 29 | 33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 44 | 47 | {% endblock %} -------------------------------------------------------------------------------- /indianpong/pong/templates/tournament-room-list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block stylesheet %} 5 | 6 | {% endblock stylesheet %} 7 | 8 | {% block title %} {{context.tournamentRoomListPageTittle}} {% endblock title %} 9 | 10 | {% block app %} 11 | 12 |
13 |
14 |

{{context.tournamentRoomListHeaderText}}

15 | 52 |
53 | 72 |
73 | 74 |
75 |
76 | 87 |
88 |
89 | {% endblock %} 90 | 91 | -------------------------------------------------------------------------------- /indianpong/pong/templates/tournament.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block title %}{{context.tournamentPageTittle}}{% endblock title %} 5 | {% block stylesheet %}{% endblock stylesheet %} 6 | 7 | {% block app %} 8 |
9 |
10 |

{{context.tournamentHeaderText}}

11 |
12 | {{context.tournamentSubHeaderText}} 13 |
14 | 15 | 23 |
24 |
25 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /indianpong/pong/templatetags/custom_filters.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | @register.filter 6 | def get_item(dictionary, key): 7 | return dictionary.get(key, False) 8 | -------------------------------------------------------------------------------- /indianpong/pong/templatetags/status.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.core.cache import cache 3 | 4 | register = template.Library() 5 | 6 | @register.simple_tag 7 | def is_user_online(user_username): 8 | return cache.get(f'online_{user_username}', default=False) 9 | 10 | @register.simple_tag 11 | def is_user_playing(user_username): 12 | return cache.get(f'playing_{user_username}', default=False) -------------------------------------------------------------------------------- /indianpong/pong/templatetags/transnav.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | 4 | register = template.Library() 5 | 6 | @register.simple_tag(takes_context=True) 7 | def transnav(context): 8 | request = context['request'] 9 | lang = request.COOKIES.get('selectedLanguage', 'en') 10 | d = {'tr': "Ana Sayfa", 'en': "Dashboard", 'hi': "डैशबोर्ड", 'pt': "Página Inicial"} 11 | c = {'tr': "Sohbet", 'en': "Chat", 'hi': "चैट", 'pt': "Bate-papo"} 12 | p = {'tr': "Pong Oyunu", 'en': "Pong Game", 'hi': "पोंग खेल", 'pt': "Jogo de Pong"} 13 | t = {'tr': "TKM Oyunu", 'en': "RPS Game", 'hi': "पत्थर-कागज-कैंची", 'pt': "PPT Jogo"} 14 | r = {'tr': "Sıralama", 'en': "Ranking", 'hi': "रैंकिंग", 'pt': "Classificação"} 15 | s = {'tr': "Mağaza", 'en': "Store", 'hi': "स्टोर", 'pt': "Loja"} 16 | a = {'tr': "Arama", 'en': "Search", 'hi': "खोज", 'pt': "Pesquisa"} 17 | h = {'tr': "Hakkımızda", 'en': "About Us", 'hi': "हमारे बारे में", 'pt': "Sobre nós"} 18 | f = {'tr': "Profil", 'en': "Profile", 'hi': "प्रोफाइल", 'pt': "Perfil"} 19 | k = {'tr': "Arkadaşlar", 'en': "Friends", 'hi': "मित्र", 'pt': "Amigos"} 20 | g = {'tr': "Profil Ayarları", 'en': "Profile Settings", 'hi': "प्रोफाइल सेटिंग्स", 'pt': "Configurações do Perfil"} 21 | o = {'tr': "Çıkış", 'en': "Logout", 'hi': "लॉग आउट", 'pt': "Sair"} 22 | return d[lang], c[lang], p[lang], t[lang], r[lang], s[lang], a[lang], h[lang], f[lang], k[lang], g[lang], o[lang] 23 | -------------------------------------------------------------------------------- /indianpong/pong/templatetags/user_info.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.shortcuts import get_object_or_404 3 | from django.core.cache import cache 4 | from pong.models import UserProfile 5 | 6 | register = template.Library() 7 | 8 | @register.simple_tag(takes_context=True) 9 | def user_info(context): 10 | request = context['request'] 11 | 12 | profile = get_object_or_404(UserProfile, username=request.user.username) 13 | is_online = cache.get(f'online_{profile.username}', default=False) 14 | is_playing = cache.get(f'playing_{profile.username}', default=False) 15 | return {'username': profile.username, 'avatar': profile.avatar.url, 'is_online': is_online, 'is_playing': is_playing} -------------------------------------------------------------------------------- /indianpong/pong/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | # FILEPATH: /home/gusto/ft_transcendence/indianpong/indianpong/tests.py 5 | import pytest 6 | from channels.testing import WebsocketCommunicator 7 | from django.test import TestCase 8 | from django.urls import reverse 9 | from channels.routing import URLRouter 10 | from channels.auth import AuthMiddlewareStack 11 | from pong.consumers import PongConsumer 12 | from indianpong.asgi import application 13 | 14 | # Define the application for testing 15 | 16 | class TestPongConsumer(TestCase): 17 | @pytest.mark.asyncio 18 | async def test_pong_consumer(self): 19 | # Initialize the WebsocketCommunicator with the testing application and the path 20 | communicator = WebsocketCommunicator(application, '/ws/pong/') 21 | 22 | # Connect to the websocket 23 | connected, _ = await communicator.connect() 24 | assert connected 25 | 26 | # Test sending data 27 | await communicator.send_json_to({"type": "ping"}) 28 | response = await communicator.receive_json_from() 29 | assert response['type'] == 'pong' 30 | 31 | # Disconnect 32 | await communicator.disconnect() -------------------------------------------------------------------------------- /indianpong/pong/utils.py: -------------------------------------------------------------------------------- 1 | import asyncio, os, hashlib 2 | from django.utils.crypto import get_random_string 3 | from django.core.files.base import ContentFile 4 | from django.core.cache import cache 5 | 6 | def delete_from_media(path): 7 | if os.path.isfile(path): 8 | os.remove(path) 9 | 10 | def get_upload_to(instance, filename): 11 | ext = filename.split('.')[-1] 12 | filename = "%s_%s.%s" % (instance.username, get_random_string(length=7), ext) 13 | return filename 14 | 15 | 16 | def create_random_svg(username): 17 | hash = hashlib.md5(username.encode()).hexdigest() 18 | hue = int(hash, 16) % 360 19 | svg_parts = [] 20 | for i in range(25 if username else 0): 21 | if int(hash, 16) & (1 << (i % 15)): 22 | x = 7 - i // 5 if i > 14 else i // 5 23 | svg_parts.append(f'') 24 | svg_content = f''' 25 | 26 | {''.join(svg_parts)} 27 | 28 | ''' 29 | return ContentFile(svg_content.encode('utf-8')) 30 | 31 | def get_equipped_item_value(user_items, item_name, default_item): 32 | if (item_name == "My Playground" or item_name == "My Beautiful Paddle" or item_name == "My Beautiful AI"): 33 | item = user_items.filter(item__name=item_name, is_equipped=True).first() 34 | return item.whatis if item else default_item 35 | else: 36 | item = user_items.filter(item__name=item_name, is_equipped=True).first() 37 | return "true" if item else "false" 38 | 39 | 40 | # This is a race-safe dictionary that can be used to store online status of users 41 | # It is used to check if a user is online before inviting them to a game 42 | # It is also used to get a list of online users to send to the client 43 | # if you use redis-cache you can use it instead of this, redis already recommended for channels 44 | # from django.core.cache import cache 45 | # user_status = cache.get('user_status', {}) 46 | # user_status['username'] = 'online' 47 | # cache.set('user_status', user_status) 48 | # online_users = [k for k, v in user_status.items() if v == 'online'] 49 | 50 | class AsyncLockedDict: 51 | def __init__(self): 52 | self.dict = {} 53 | self.lock = asyncio.Lock() 54 | 55 | async def get(self, key, default=None): 56 | async with self.lock: 57 | return self.dict.get(key, default) 58 | 59 | async def set(self, key, value): 60 | async with self.lock: 61 | self.dict[key] = value 62 | 63 | async def delete(self, key): 64 | async with self.lock: 65 | if key in self.dict: 66 | del self.dict[key] 67 | 68 | async def get_keys_with_value(self, value): 69 | async with self.lock: 70 | return [k for k, v in self.dict.items() if v == value] 71 | 72 | async def set_field_value(self, key, value, field_name): 73 | async with self.lock: 74 | setattr(self.dict[key], field_name, value) 75 | 76 | 77 | """ def add_to_cache(key, container, value): 78 | container_ = cache.get(key, container) 79 | container_.add(value) 80 | cache.set(key, container_) 81 | 82 | def remove_from_cache(key, container, value): 83 | container_ = cache.get(key, container) 84 | if container_: 85 | container_.remove(value) 86 | cache.set(key, container_) 87 | 88 | def pass2fa(request, user_obj): 89 | if user_obj.has_2fa: 90 | hashed_secret = hashlib.sha512((user_obj.username + os.environ.get("OTP_SECRET")).encode("utf-8")).digest() 91 | encoded_secret = base64.b32encode(hashed_secret) 92 | return render(request, "pass2fa.html", {"user": user_obj.username,"key": encoded_secret}) 93 | else: 94 | login(request, user_obj) 95 | return redirect("index") """ -------------------------------------------------------------------------------- /indianpong/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd indianpong 4 | python3 manage.py makemigrations pong 5 | python3 manage.py migrate 6 | python3 manage.py initdata 7 | python3 manage.py populate 10 8 | python3 manage.py collectstatic --no-input 9 | echo "Starting Daphne server..." 10 | daphne -b 0.0.0.0 -p 8001 -e ssl:8443:privateKey=/etc/nginx/ssl/key.pem:certKey=/etc/nginx/ssl/cert.pem indianpong.asgi:application 11 | echo "Daphne server started" -------------------------------------------------------------------------------- /indianpong/static/assets/42.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 50 | 53 | 57 | 61 | 65 | 69 | 70 | -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/bg-pingpong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/bg-pingpong.png -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/bg-rps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/bg-rps.png -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/confetti.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/confetti.webp -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/home-bg.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/leader-bg.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/leader-bg.avif -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/leader-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/leader-bg.png -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/lose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/lose.png -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/pong-room-bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/pong-room-bg.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/pong-room-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/pong-room-bg.png -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/rankings-bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/rankings-bg.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/backgrounds/rps-room-bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/backgrounds/rps-room-bg.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/email/268a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/email/268a.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/email/Beefree-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/email/Beefree-logo.png -------------------------------------------------------------------------------- /indianpong/static/assets/email/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/email/back.png -------------------------------------------------------------------------------- /indianpong/static/assets/email/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/email/github.png -------------------------------------------------------------------------------- /indianpong/static/assets/email/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/email/head.png -------------------------------------------------------------------------------- /indianpong/static/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/favicon.ico -------------------------------------------------------------------------------- /indianpong/static/assets/flags/english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/flags/english.png -------------------------------------------------------------------------------- /indianpong/static/assets/flags/hindi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/flags/hindi.png -------------------------------------------------------------------------------- /indianpong/static/assets/flags/portugal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/flags/portugal.png -------------------------------------------------------------------------------- /indianpong/static/assets/flags/turkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/flags/turkey.png -------------------------------------------------------------------------------- /indianpong/static/assets/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/logo-dark.png -------------------------------------------------------------------------------- /indianpong/static/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/logo.png -------------------------------------------------------------------------------- /indianpong/static/assets/profile/ataskin.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/ataskin.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/c1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/c1.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/c2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/c2.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/c3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/c3.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/c4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/c4.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/default_avatar.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/default_avatar.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/eyagiz.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/eyagiz.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/fyurtsev.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/fyurtsev.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/indianai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/indianai.jpg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/profilephoto.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/profilephoto.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/sciftci.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/sciftci.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/profile/yeaktas.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/profile/yeaktas.jpeg -------------------------------------------------------------------------------- /indianpong/static/assets/rankings/crown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/bronze.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/bronze.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/challenger.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/challenger.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/diamond.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/diamond.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/emerald.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/emerald.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/gold.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/gold.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/grandmaster.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/grandmaster.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/iron.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/iron.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/master.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/master.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/platinum.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/platinum.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/silver.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/silver.webp -------------------------------------------------------------------------------- /indianpong/static/assets/ranks/unranked.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/ranks/unranked.webp -------------------------------------------------------------------------------- /indianpong/static/assets/rps/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/rps/.DS_Store -------------------------------------------------------------------------------- /indianpong/static/assets/rps/bg-pentagon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/bg-triangle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/rps/favicon-32x32.png -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-cheater.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-godofthings.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 26 | 30 | 32 | 34 | 36 | 37 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-godthings.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 26 | 30 | 32 | 34 | 36 | 37 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-likeacheater.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-lizard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-paper.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-rock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-scissors.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/icon-spock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /indianpong/static/assets/rps/image-rules.svg: -------------------------------------------------------------------------------- 1 | BEATSBEATSBEATS -------------------------------------------------------------------------------- /indianpong/static/assets/scrool/crossedsword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/scrool/crossedsword.png -------------------------------------------------------------------------------- /indianpong/static/assets/scrool/pixelsword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/scrool/pixelsword.png -------------------------------------------------------------------------------- /indianpong/static/assets/stores/ai-nametag.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/ai-nametag.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/cheater-rps.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/cheater-rps.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/cheater.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/cheater.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/colorpick.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/colorpick.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/djplaythemusic.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/djplaythemusic.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/fast-and-furious.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/fast-and-furious.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/fireball.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/fireball.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/giantman.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/giantman.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/godofthings-rps.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/godofthings-rps.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/mybeatifulpaddle.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/mybeatifulpaddle.webp -------------------------------------------------------------------------------- /indianpong/static/assets/stores/versus-time.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/assets/stores/versus-time.webp -------------------------------------------------------------------------------- /indianpong/static/css/aboutus.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --pbr: 5; 3 | --grc: 1; 4 | 5 | --card-color: white; 6 | --pp-max-height: 100%; 7 | } 8 | 9 | @media (min-width: 200px) { 10 | :root { 11 | --pbr: 1; 12 | --grc: 5; 13 | --pp-max-height: 50%; 14 | } 15 | } 16 | @media (min-width: 550px) { 17 | :root { 18 | --pbr: 2; 19 | --grc: 3; 20 | --pp-max-height: 60%; 21 | } 22 | } 23 | @media (min-width: 750px) { 24 | :root { 25 | --pbr: 3; 26 | --grc: 2; 27 | --pp-max-height: 60%; 28 | } 29 | } 30 | @media (min-width: 950px) { 31 | :root { 32 | --pbr: 5; 33 | --grc: 1; 34 | --pp-max-height: 100%; 35 | } 36 | } 37 | 38 | body { 39 | font-family: Arial, Helvetica, sans-serif; 40 | } 41 | 42 | 43 | .profiles { 44 | display: grid; 45 | grid-template-columns: repeat(var(--pbr), 1fr); 46 | grid-template-rows: repeat(var(--grc), 1fr); 47 | gap: 10px 48 | } 49 | 50 | 51 | .profile_card { 52 | background-color: transparent; 53 | perspective: 1000px; 54 | height: 370px; 55 | 56 | &.c1 { --card-color: rgb(189, 127, 35);} 57 | &.c2 { --card-color: rgb(55, 204, 50);} 58 | &.c3 { --card-color: rgb(78, 198, 228);} 59 | &.c4 { --card-color: rgb(110, 57, 131);} 60 | &.c5 { --card-color: rgb(235, 235, 34);} 61 | 62 | 63 | .profile_card__inner { 64 | 65 | position: relative; 66 | width: 100%; 67 | height: 100%; 68 | text-align: center; 69 | transition: 0.3s all ease-in-out; 70 | transform-style: preserve-3d; 71 | box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); 72 | 73 | .profile_card__front { 74 | border-radius: 10px; 75 | background-color: rgba(255, 255, 255,0.5); 76 | position: absolute; 77 | width: 100%; 78 | height: 100%; 79 | -webkit-backface-visibility: hidden; 80 | backface-visibility: hidden; 81 | 82 | img { 83 | max-width: 100%; 84 | max-height: var(--pp-max-height); 85 | border-radius: 5px 5px 0 0; 86 | } 87 | 88 | .profile_card__detail { 89 | padding: 1rem; 90 | 91 | .profile__title { 92 | font-weight: 500; 93 | line-height: 1.2; 94 | padding: 0.2rem; 95 | background-color: rgba(255, 255, 255,0.2); 96 | color: rgb(41, 41, 41); 97 | border-radius: 5px; 98 | font-size: 2em; 99 | text-align: center; 100 | border-bottom: 3px solid var(--card-color); 101 | 102 | } 103 | ul { 104 | list-style-type: square; 105 | } 106 | } 107 | } 108 | 109 | } 110 | 111 | .profile_links { 112 | backface-visibility: hidden; 113 | transform: rotateY(180deg); 114 | position: absolute; 115 | width: 100%; 116 | height: 100%; 117 | top:0; 118 | border-radius: 10px; 119 | background-color: rgba(255, 255, 255,0.5); 120 | display: flex; 121 | gap: 2rem; 122 | flex-direction: column; 123 | align-items: center; 124 | justify-content: center; 125 | 126 | 127 | div { 128 | filter: brightness(0); 129 | font-size: 70px; 130 | width: 70px; 131 | transition: all 0.2s ease-in-out; 132 | cursor: pointer; 133 | 134 | &:hover { 135 | transform: scale(1.3); 136 | filter: brightness(0) drop-shadow(0px 0px 10px var(--card-color)); 137 | } 138 | } 139 | } 140 | 141 | &:hover { 142 | .profile_card__inner { 143 | transform: rotateY(180deg); 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /indianpong/static/css/card.css: -------------------------------------------------------------------------------- 1 | card-body { 2 | max-height: 320px; 3 | } 4 | 5 | .rank-img { 6 | text-align: center; 7 | } 8 | 9 | .rank-h4 { 10 | font-family: 'Spiegel', sans-serif; 11 | color: transparent; /* Metin rengini şeffaf hale getirin */ 12 | background: url('../assets/backgrounds/leader-bg.png'); 13 | background-size: cover; /* Resmi kaplama özelliği */ 14 | -webkit-background-clip: text; /* Metni arka plana kırpma, webkit tarayıcıları için */ 15 | background-clip: text; /* Metni arka plana kırpma, diğer tarayıcılar için */ 16 | display: inline-block; /* Metni blok içinde gösterme */ 17 | text-transform: uppercase; 18 | } 19 | 20 | .rank-img img { 21 | height: 224px; /* ya da istediğiniz başka bir değer */ 22 | /* İsteğe bağlı olarak width özelliğini de kullanabilirsiniz. */ 23 | /* width: auto; */ 24 | } 25 | 26 | 27 | .follower { 28 | margin-bottom: 5px; 29 | } 30 | 31 | .follower img { 32 | text-align: left; 33 | width: 48px; 34 | height: 48px; 35 | object-fit: cover; /* Fotoğrafın boyutunu koruyarak kırpmayı sağlar */ 36 | border-radius: 50%; 37 | margin-right: 10px; 38 | } 39 | 40 | .follower a:hover img { 41 | opacity: 0.8; 42 | } 43 | 44 | .displayname { 45 | font-family: 'Roboto', sans-serif; 46 | font-size: 18px; 47 | } 48 | 49 | .card-stat { 50 | border-radius: 5px; 51 | -webkit-box-shadow: 0 1px 2.94px 0.06px rgba(4,26,55,0.16); 52 | box-shadow: 0 1px 2.94px 0.06px rgba(4,26,55,0.16); 53 | border: none; 54 | margin-bottom: 30px; 55 | -webkit-transition: all 0.3s ease-in-out; 56 | transition: all 0.3s ease-in-out; 57 | } 58 | 59 | .card-stat .card-block { 60 | padding: 25px; 61 | } 62 | 63 | .order-card i { 64 | font-size: 32px; 65 | text-align: center; 66 | margin-right: 5px; 67 | } 68 | 69 | .f-left { 70 | float: left; 71 | } 72 | 73 | .f-right { 74 | float: right; 75 | } 76 | 77 | .text-right span.big { 78 | font-size: 2rem; /* İstediğiniz büyüklüğü ayarlayabilirsiniz */ 79 | margin-right: -5px; 80 | } 81 | 82 | .text-right span.small { 83 | font-size: 1.5rem; /* İstediğiniz küçüklüğü ayarlayabilirsiniz */ 84 | } -------------------------------------------------------------------------------- /indianpong/static/css/color.css: -------------------------------------------------------------------------------- 1 | /* Colors */ 2 | 3 | .bg-c-blue { 4 | background: linear-gradient(45deg,#4099ff,#73b4ff); 5 | } 6 | 7 | .bg-c-green { 8 | background: linear-gradient(45deg,#2ed8b6,#59e0c5); 9 | } 10 | 11 | .bg-c-yellow { 12 | background: linear-gradient(45deg,#FFB64D,#ffcb80); 13 | } 14 | 15 | .bg-c-pink { 16 | background: linear-gradient(45deg,#FF5370,#ff869a); 17 | } 18 | 19 | .bg-c-gold { 20 | background: linear-gradient(45deg, #FFD700, #a17c02); 21 | } 22 | 23 | .bg-c-navy { 24 | background: linear-gradient(45deg, #001F3F, #003366); 25 | } 26 | 27 | .bg-c-purple { 28 | background: linear-gradient(45deg, #800080, #993399); 29 | } 30 | 31 | .bg-c-light-blue { 32 | background: linear-gradient(45deg, #add8e6, #87ceeb); 33 | } 34 | 35 | .bg-c-light-green { 36 | background: linear-gradient(45deg, #42a470, #3b9867); 37 | } 38 | -------------------------------------------------------------------------------- /indianpong/static/css/fonts/CommonPixel.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/CommonPixel.ttf -------------------------------------------------------------------------------- /indianpong/static/css/fonts/Lobster-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/Lobster-Regular.ttf -------------------------------------------------------------------------------- /indianpong/static/css/fonts/Minecraftia-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/Minecraftia-Regular.ttf -------------------------------------------------------------------------------- /indianpong/static/css/fonts/Pixeboy-z8XGD.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/Pixeboy-z8XGD.ttf -------------------------------------------------------------------------------- /indianpong/static/css/fonts/PixelifySans-VariableFont_wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/PixelifySans-VariableFont_wght.ttf -------------------------------------------------------------------------------- /indianpong/static/css/fonts/alagard.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/alagard.ttf -------------------------------------------------------------------------------- /indianpong/static/css/fonts/rainyhearts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/fonts/rainyhearts.ttf -------------------------------------------------------------------------------- /indianpong/static/css/friends-list.css: -------------------------------------------------------------------------------- 1 | /* Friends */ 2 | 3 | .friend-list-header { 4 | font-family: 'Open Sans', sans-serif; 5 | font-size: 1.2em; 6 | font-weight: 600; 7 | } 8 | 9 | .card-friends-list { 10 | background-color: rgba(241, 241, 251, 0.3) !important; 11 | backdrop-filter: blur(3px); /* Arka planı 10 piksel bulanıklaştır */ 12 | padding: 20px; 13 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 14 | border-radius: 8px; 15 | max-width: 1300px; 16 | width: 100%; 17 | max-height: auto; 18 | height: auto; /* Yüksekliği otomatik ayarla */ 19 | max-height: 1100px; 20 | margin: 0 auto; /* Ortalamak için */ 21 | } 22 | 23 | .mr-3:hover { 24 | filter: brightness(50%); 25 | } 26 | 27 | .unfollow-btn { 28 | background-color: #212529; /* Buton arka plan rengi */ 29 | padding: 5px 10px; 30 | border: none; 31 | color: #fff; /* Buton metin rengi */ 32 | border-radius: 5px; 33 | } 34 | 35 | .unfollow-btn:hover { 36 | background-color: #000000; 37 | } 38 | 39 | 40 | .avatar.avatar-xl { 41 | width: 5rem; 42 | height: 5rem; 43 | } 44 | 45 | .avatar { 46 | width: 2rem; 47 | height: 2rem; 48 | line-height: 2rem; 49 | border-radius: 50%; 50 | display: inline-block; 51 | background: #ced4da no-repeat center/cover; 52 | position: relative; 53 | text-align: center; 54 | color: #868e96; 55 | font-weight: 600; 56 | vertical-align: bottom; 57 | } 58 | 59 | .tile-link { 60 | position: absolute; 61 | cursor: pointer; 62 | width: 100%; 63 | height: 100%; 64 | left: 0; 65 | top: 0; 66 | z-index: 30; 67 | } 68 | 69 | .card.friends { 70 | margin-bottom: 1em; 71 | } 72 | 73 | .friends-list nav { 74 | text-align: center; 75 | display: flex; 76 | justify-content: center; 77 | align-items: center; 78 | margin-top: 20px; 79 | } 80 | 81 | @media screen and (max-width: 767px) { 82 | .friends-list .card { 83 | width: 100%; /* Telefonlarda kartları genişletmek için */ 84 | margin-bottom: 10px; /* Kartlar arası boşluk eklemek için */ 85 | } 86 | 87 | .friends-list .row { 88 | display: flex; 89 | flex-wrap: wrap; 90 | justify-content: space-around; /* Sütunları hizalamak için */ 91 | } 92 | 93 | .friends-list .col-md-6 { 94 | flex: 0 0 calc(50% - 10px); /* Telefonlarda iki sütunlu olacak şekilde ayarlamak */ 95 | margin-right: 10px; 96 | margin-bottom: 10px; 97 | } 98 | 99 | .col-md-6.col-xl-3 { 100 | flex: 0 0 100%; 101 | max-width: 100%; 102 | } 103 | } 104 | 105 | @media screen and (min-width: 1200px) { 106 | .avatar.avatar-xl { 107 | width: 7rem; 108 | height: 7rem; 109 | } 110 | 111 | .avatar { 112 | width: 3rem; 113 | height: 3rem; 114 | line-height: 3rem; 115 | } 116 | 117 | .friends-list nav { 118 | margin-top: 40px; 119 | } 120 | 121 | /* Diğer büyük ekran stilleri buraya eklenebilir */ 122 | } 123 | 124 | @media screen and (max-width: 1199px) and (min-width: 768px) { 125 | .avatar.avatar-xl { 126 | width: 5rem; 127 | height: 5rem; 128 | } 129 | 130 | .avatar { 131 | width: 2.5rem; 132 | height: 2.5rem; 133 | line-height: 2.5rem; 134 | } 135 | 136 | .friends-list nav { 137 | margin-top: 30px; 138 | } 139 | 140 | /* Diğer orta büyüklükte ekran stilleri buraya eklenebilir */ 141 | } 142 | 143 | /* Küçük ekranlar için stiller */ 144 | @media screen and (max-width: 767px) { 145 | .avatar.avatar-xl { 146 | width: 4rem; 147 | height: 4rem; 148 | } 149 | 150 | .avatar { 151 | width: 2rem; 152 | height: 2rem; 153 | line-height: 2rem; 154 | } 155 | 156 | .friends-list nav { 157 | margin-top: 20px; 158 | } 159 | 160 | .card-friends-list { 161 | height: 1350px; 162 | max-height: 1350px; 163 | } 164 | } 165 | 166 | .page-link { 167 | cursor:pointer; 168 | } 169 | 170 | .page-link-search { 171 | cursor:auto !important; 172 | color: tomato; 173 | } 174 | 175 | .page-item.active .page-link-friends, 176 | .page-link-friends.active { 177 | background-color: #ff9500 !important; 178 | border-color: #ff9500 !important; 179 | color: #fff !important; 180 | font-size: 1em !important; 181 | } 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /indianpong/static/css/game.css: -------------------------------------------------------------------------------- 1 | /* Game */ 2 | 3 | .ai-btn { 4 | margin-top: 0.5em; 5 | } 6 | 7 | .opponent-btn { 8 | margin-top: 1em; 9 | margin-bottom: 0.5em; 10 | } 11 | 12 | .pong-game-text { 13 | text-align: center; 14 | } 15 | 16 | .custom-text { 17 | text-align: center; 18 | top: 50%; 19 | left: 50%; 20 | margin-bottom: 2em; 21 | } 22 | 23 | .ponggamebtn { 24 | font-size: 36px; 25 | font-family: 'Rajdhani', sans-serif; 26 | text-align: center; 27 | line-height: 85px; 28 | color: #fff; 29 | margin: 0 auto; 30 | width: 350px; 31 | height: 85px; 32 | background: linear-gradient(#1d7751, #0e382c); 33 | border: 3px #25793b solid; 34 | border-radius: 5px; 35 | text-shadow: 0 0 20px rgba(255,255,255,0.3); 36 | transition: .1s; 37 | transform: scale(1); 38 | cursor: pointer; 39 | box-shadow: 0 0 50px rgba(0,117,9,0.5); 40 | overflow: hidden; 41 | } 42 | 43 | .ponggamebtn:hover { 44 | text-shadow: 0 0 20px rgba(255,255,255,0.5); 45 | transform: scale(1.05); 46 | } 47 | 48 | .ponggamebtn:active { 49 | background: linear-gradient(#1f8258, #114435); 50 | text-shadow: 0 0 20px rgba(255,255,255,0.5); 51 | transform: scale(1); 52 | box-shadow: 0 0 75px rgba(43,137,68,0.5); 53 | } 54 | 55 | .ponggamebtn:after { 56 | content: ""; 57 | position: relative; 58 | top: -120px; 59 | left: -90px; 60 | display: block; 61 | width: 35px; 62 | height: 150px; 63 | background: rgba(255, 255, 255, 0.5); 64 | transform: rotate(35deg); 65 | transition: none; 66 | } 67 | 68 | .ponggamebtn:hover:after { 69 | left: 400px; 70 | transition: .3s ease-in-out; 71 | } 72 | 73 | .ponggamebtn-ai { 74 | font-size: 36px; 75 | font-family: 'Rajdhani', sans-serif; 76 | text-align: center; 77 | line-height: 85px; 78 | color: #fff; 79 | margin: 0 auto; 80 | width: 350px; 81 | height: 85px; 82 | background: linear-gradient(#1d6d77, #0e2e38); 83 | border: 3px #2195a4 solid; 84 | border-radius: 5px; 85 | text-shadow: 0 0 20px rgba(255,255,255,0.3); 86 | transition: .1s; 87 | transform: scale(1); 88 | cursor: pointer; 89 | box-shadow: 0 0 50px rgba(0,117,9,0.5); 90 | overflow: hidden; 91 | } 92 | 93 | .ponggamebtn-ai:hover { 94 | text-shadow: 0 0 20px rgba(255,255,255,0.5); 95 | transform: scale(1.05); 96 | } 97 | 98 | .ponggamebtn-ai:active { 99 | background: linear-gradient(#1f8258, #114435); 100 | text-shadow: 0 0 20px rgba(255,255,255,0.5); 101 | transform: scale(1); 102 | box-shadow: 0 0 75px rgba(43,137,68,0.5); 103 | } 104 | 105 | .ponggamebtn-ai:after { 106 | content: ""; 107 | position: relative; 108 | top: -120px; 109 | left: -90px; 110 | display: block; 111 | width: 35px; 112 | height: 150px; 113 | background: rgba(255, 255, 255, 0.5); 114 | transform: rotate(35deg); 115 | transition: none; 116 | } 117 | 118 | .ponggamebtn-ai:hover:after { 119 | left: 400px; 120 | transition: .3s ease-in-out; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /indianpong/static/css/in-game.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Pixeboy-z8XGD'; 3 | src: url('fonts/Pixeboy-z8XGD.ttf'); 4 | } 5 | 6 | 7 | .left-card { 8 | width: 300px; 9 | height: auto; 10 | background-color: #ddd; 11 | padding: 10px; 12 | margin-right: 20px; /* İstediğiniz boşluk değerini ayarlayabilirsiniz */ 13 | margin-left: 1em; 14 | margin-top: 2em; 15 | float: left; 16 | } 17 | 18 | .custom-table { 19 | border-collapse: collapse; 20 | width: 100%; 21 | } 22 | 23 | .game-info-menu { 24 | display: flex; 25 | justify-content: space-between; 26 | color: tomato; 27 | 28 | } 29 | 30 | .game-info-menu-local { 31 | position: absolute; 32 | top: 0; 33 | right: 0; 34 | } 35 | 36 | .custom-table th, .custom-table td { 37 | border: 1px solid #ddd; 38 | padding: 8px; 39 | text-align: left; 40 | } 41 | 42 | .custom-table img { 43 | border-radius: 50%; 44 | border: 1px soldi #ffffff; 45 | width: 28px; 46 | height: 28px; 47 | object-fit: cover; /* Ya da 'contain' kullanabilirsiniz */ 48 | } 49 | 50 | .custom-table tr:hover { 51 | background-color: #b6b6b6; 52 | } 53 | 54 | .custom-table .btn-outline-success { 55 | padding: 4px 8px; 56 | font-size: 14px; 57 | } 58 | 59 | .custom-table .btn-outline-primary { 60 | padding: 4px 8px; 61 | font-size: 14px; 62 | } 63 | 64 | .custom-table .btn-outline-danger { 65 | padding: 4px 8px; 66 | font-size: 14px; 67 | } 68 | 69 | .pagination { 70 | display: flex; 71 | list-style: none; 72 | padding: 0; 73 | } 74 | 75 | .pagination a { 76 | color: rgb(0, 0, 0); 77 | padding: 8px 16px; 78 | text-decoration: none; 79 | transition: background-color .3s; 80 | } 81 | 82 | .pagination a:hover { 83 | background-color: #ffffff; 84 | } 85 | 86 | .canvas-container { 87 | float: left; 88 | } 89 | 90 | #myCanvas { 91 | border: 1px solid #ffffff; 92 | background-image: url("https://s1.dmcdn.net/v/NGyfI1X-BUVhMfsej/x1080"); 93 | background-repeat: no-repeat; 94 | } 95 | 96 | #countdownContainer { 97 | position: relative; 98 | } 99 | 100 | 101 | .countdown { 102 | position: absolute; 103 | top: 50%; 104 | left: 50%; 105 | transform: translate(-50%, -50%); 106 | text-align: center; 107 | font-family: Arial, sans-serif; 108 | } 109 | 110 | .countdown p { 111 | font-family: "VT323", monospace; 112 | font-size: 20px; 113 | font-weight: bold; 114 | margin-top: -20px; 115 | color: palegreen; 116 | } 117 | 118 | .countdown h1 { 119 | font-size: 48px; 120 | font-family: 'Pixeboy-z8XGD', sans-serif; 121 | color: #ffffff; 122 | margin-bottom: 10px; 123 | } 124 | 125 | .countdown h2 { 126 | font-size: 24px; 127 | color: #ffffff; 128 | font-family: "VT323", monospace; 129 | margin-bottom: 20px; 130 | } 131 | 132 | .countdown-timer { 133 | font-size: 72px; 134 | color: #ffffff; 135 | 136 | font-family: 'Pixeboy-z8XGD', sans-serif; 137 | 138 | } 139 | 140 | .ai-game { 141 | overflow: hidden; 142 | } 143 | 144 | .slider-container { 145 | position: absolute; 146 | width: 100%; 147 | left: 510px; 148 | top: -25px; 149 | } 150 | 151 | 152 | 153 | .modal-backdrop { 154 | display: none !important; /* Overlay'i kaldırır */ 155 | } 156 | .modal { 157 | background-color: rgba(0,0,0,0.5); /* Modal arka planını yarı şeffaf yapar */ 158 | } 159 | 160 | 161 | 162 | .slider { 163 | -webkit-appearance: none; 164 | /* width: 100%; */ 165 | height: 10px; 166 | border-radius: 5px; 167 | background: #ffffff; 168 | outline: none; 169 | opacity: 0.9; 170 | -webkit-transition: .2s; 171 | transition: opacity .2s; 172 | } 173 | 174 | .slider::-webkit-slider-thumb { 175 | -webkit-appearance: none; 176 | appearance: none; 177 | width: 15px; 178 | height: 15px; 179 | border-radius: 50%; 180 | background: tomato; 181 | cursor: pointer; 182 | } 183 | 184 | .slider::-moz-range-thumb { 185 | width: 25px; 186 | height: 25px; 187 | border-radius: 50%; 188 | background: tomato; 189 | cursor: pointer; 190 | } -------------------------------------------------------------------------------- /indianpong/static/css/leader-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/css/leader-bg.png -------------------------------------------------------------------------------- /indianpong/static/css/match-history.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,600); 2 | 3 | .mhistory-card-header { 4 | margin-left: 1.8em; 5 | margin-top: -3em; 6 | } 7 | 8 | .mhistory-header { 9 | color:white !important; 10 | font-family: 'Open Sans', sans-serif; 11 | font-size: 1.2em; 12 | font-weight: 600; 13 | } 14 | 15 | .match-history-pong { 16 | font-family: 'Open Sans', sans-serif; 17 | margin: 1em auto; /* Merkezlemek için margin kullanıyoruz */ 18 | margin-top: 0.5em; 19 | max-width: 1200px; 20 | text-align: center; 21 | width: 100%; /* Make the table take up 100% of the container */ 22 | } 23 | 24 | .match-history-pong nav { 25 | text-align: center; 26 | display: flex; 27 | justify-content: center; 28 | align-items: center; 29 | margin-top: 20px; /* İhtiyaca göre ayarlayabilirsiniz */ 30 | } 31 | 32 | .card-mhistory-table { 33 | background: #012B39; 34 | border-radius: 0.25em; 35 | border-collapse: collapse; 36 | overflow-x: auto; 37 | margin: 1em auto; /* "card" elemanının genişliğine göre ortalamak için */ 38 | max-width: 1300px; /* "card" elemanıyla aynı max-width değeri */ 39 | width: 100%; 40 | } 41 | 42 | .card-mhistory-table th { 43 | border-bottom: 1px solid #364043; 44 | color: #46c9f1; 45 | font-size: 0.85em; 46 | font-weight: 600; 47 | padding: 0.5em 1em; 48 | } 49 | 50 | .card-mhistory-table thead { 51 | background-color: #061d24; 52 | } 53 | 54 | .card-mhistory-table td { 55 | color: #fff; 56 | padding: 0.65em 1em; 57 | } 58 | 59 | .card-mhistory-table tr .lose { 60 | color: red; 61 | font-weight: 400; 62 | } 63 | 64 | .card-mhistory-table tr .won { 65 | color: green; 66 | font-weight: 400; 67 | } 68 | 69 | .card-mhistory-table tr .mhistory-username { 70 | font-weight: 400; 71 | } 72 | 73 | 74 | .select-history { 75 | position: absolute; 76 | top: 10px; 77 | right: 5px; 78 | margin-top: 0.3em; 79 | text-align: center; 80 | } 81 | 82 | .select-history .changer-btn { 83 | background-color: transparent; 84 | border: 1px solid #000000; 85 | height: 30px; 86 | width: 50px; 87 | margin: 0 5px; /* Butonlar arasındaki boşluğu ayarlar */ 88 | display: inline-block; /* Butonları aynı satırda görüntüler */ 89 | vertical-align: top; /* Dikey hizalamayı ayarlar */ 90 | border-radius: 8px; 91 | } 92 | 93 | 94 | .select-history .changer-btn:hover { 95 | background-color: #ffa66b; 96 | box-shadow: -20px 50px 50px rgba(0,0,0,0.2); 97 | border: none; 98 | color: palegreen; /* Metni gizler */ 99 | transition: none; /* Geçiş efektini kapatır */ 100 | } 101 | 102 | 103 | .match-history-rps { 104 | display: none; 105 | font-family: 'Open Sans', sans-serif; 106 | margin: 1em auto; /* Merkezlemek için margin kullanıyoruz */ 107 | margin-top: 0.5em; 108 | max-width: 1200px; 109 | text-align: center; 110 | width: 100%; /* Make the table take up 100% of the container */ 111 | } 112 | 113 | 114 | .match-history-rps nav { 115 | text-align: center; 116 | display: flex; 117 | justify-content: center; 118 | align-items: center; 119 | margin-top: 20px; /* İhtiyaca göre ayarlayabilirsiniz */ 120 | } 121 | 122 | 123 | .match-history-card { 124 | background-color:white !important; 125 | backdrop-filter: blur(3px); /* Arka planı 10 piksel bulanıklaştır */ 126 | padding: 20px; 127 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 128 | border-radius: 8px; 129 | max-width: 1300px; 130 | max-height: 500px !important; 131 | height: 400px; 132 | width: 100%; 133 | margin: 0 auto; /* Ortalamak için */ 134 | } 135 | 136 | .page-item.active .page-link-history, 137 | .page-link-history.active { 138 | background-color: #ff9500 !important; 139 | border-color: #ff9500 !important; 140 | color: #fff !important; 141 | font-size: 1em !important; 142 | } -------------------------------------------------------------------------------- /indianpong/static/css/mediaquery.css: -------------------------------------------------------------------------------- 1 | /* Media Query for screens smaller than 600 pixels */ 2 | @media (max-width: 600px) { 3 | .big-text { 4 | font-size: 4em; 5 | } 6 | 7 | .small-text { 8 | font-size: 0.8em; 9 | } 10 | 11 | .PixellButton { 12 | width: 150px; 13 | height: 40px; 14 | } 15 | } 16 | 17 | .snow { 18 | position: fixed; 19 | background-color: #fff; 20 | /* Kar tanelerinin rengi */ 21 | border-radius: 50%; 22 | pointer-events: none; 23 | z-index: 2; 24 | } 25 | 26 | @keyframes snowRain { 27 | from { 28 | transform: translateY(-100vh); 29 | } 30 | 31 | to { 32 | transform: translateY(100vh); 33 | } 34 | } 35 | 36 | 37 | .PixellButton:active { 38 | background-color: rgb(75, 195, 75); 39 | transform: translateY(3px); 40 | width: 148px; 41 | border-right: 4px solid darkgreen; 42 | border-bottom: 5px solid darkgreen; 43 | } 44 | 45 | 46 | @media only screen and (max-width: 850px) { 47 | .PixellButton { 48 | background-color: rgb(90, 208, 90); 49 | 50 | border-top: 1px rgb(90, 208, 90); 51 | border-left: 1px rgb(90, 208, 90); 52 | 53 | border-color: rgb(56, 180, 7); 54 | border-right: 6px solid darkgreen; 55 | border-bottom: 8px solid darkgreen; 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /indianpong/static/css/modal.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'PixelifySans'; 3 | src: url('fonts/PixelifySans-VariableFont_wght.ttf'); 4 | } 5 | 6 | .modal { 7 | font-family: 'PixelifySans'; 8 | } 9 | 10 | .modal.show .modal-dialog { 11 | max-width: 30%; 12 | } 13 | 14 | .modal-header { 15 | padding-bottom: 0; 16 | } 17 | 18 | .modal-body { 19 | padding-top: 0; 20 | } 21 | 22 | .modal-body h3 { 23 | border-bottom: 1px solid; 24 | font-size: 1.5rem; 25 | } 26 | 27 | .modal-controls { 28 | padding: 1rem 0px; 29 | display: flex; 30 | justify-content: space-between; 31 | } 32 | 33 | .modal-controls .col:first-child { 34 | font-weight: bold; 35 | } 36 | 37 | .modal-keys{ 38 | 39 | padding: 0.1em 0.5em; 40 | background-color: rgb(75, 73, 73); 41 | border: 3px solid rgb(49, 49, 49); 42 | color: rgb(224, 224, 224); 43 | } 44 | -------------------------------------------------------------------------------- /indianpong/static/css/profile.css: -------------------------------------------------------------------------------- 1 | /* Profile Page */ 2 | 3 | .nav-item { 4 | margin-left: 5px; 5 | margin-right: 5px; 6 | } 7 | 8 | .navbar-nav.ml-auto .nav-item:hover, 9 | .navbar-nav.ml-auto .nav-item:hover > .nav-link { 10 | background-color: #5c5be5; 11 | box-shadow: 0px 15px 11px -6px #7a7a7d; 12 | color: #fff; /* İsterseniz metin rengini de ayarlayabilirsiniz */ 13 | } 14 | 15 | .stats-info-pong { 16 | margin-top: 10px; 17 | 18 | } 19 | 20 | .stats-info-rps { 21 | margin-top: 10px; 22 | display: none; 23 | } 24 | 25 | 26 | .unfollow-btn { 27 | background-color: #212529; /* Buton arka plan rengi */ 28 | width: 300px !important; 29 | height: 38px !important; 30 | border: none; 31 | color: #fff; /* Buton metin rengi */ 32 | border-radius: 5px; 33 | } 34 | 35 | .unfollow-btn:hover { 36 | background-color: #000000; 37 | } 38 | 39 | .stats { 40 | /* Add your styles for stats here */ 41 | margin-bottom: -7px; 42 | } 43 | 44 | .stats-p { 45 | /* Add your styles for stats-p here */ 46 | font-size: 14px; 47 | color: #000000; 48 | font-weight: 500; 49 | text-align: left; 50 | } 51 | 52 | .stats .bi-dice-1-fill { color: #ff5733; } /* Oyunlar oynandığında */ 53 | .stats .bi-trophy-fill { color: #ffd700; } /* Kazanıldığında */ 54 | .stats .bi-emoji-frown-fill { color: #ff1100; } /* Kaybedildiğinde */ 55 | .stats .bi-award-fill { color: #00b907; } /* Kazanma oranı %50'den büyük olduğunda */ 56 | .stats .bi-bucket-fill { color: #f44336; } /* Kaybetme oranı %50'den büyük olduğunda */ 57 | .stats .bi-clock-fill { color: #00bcd4; } /* Ortalama oyun süresi */ 58 | .stats .bi-emoji-wink-fill { color:#3fb067 } 59 | 60 | .stats-result-p { 61 | /* Add your styles for stats-result-p here */ 62 | font-size: 14px; 63 | color: #000000; 64 | font-weight: 700; 65 | right: 0; 66 | position: absolute; 67 | margin-right: 2.5em; 68 | } 69 | 70 | .stats-p, .stats-result-p { 71 | display: inline-block; 72 | } 73 | 74 | .profile-slashed-info { 75 | font-size: 10px; 76 | } 77 | 78 | .switcher-btn { 79 | position: fixed; 80 | right: 15; 81 | top: 15; 82 | margin-bottom: 5px; 83 | border-radius: 25%; 84 | background-color: transparent; 85 | border: 1px solid tomato; 86 | } 87 | 88 | 89 | .switcher-game { 90 | text-align: center; 91 | position: absolute; 92 | top: 10px; 93 | right: 5px; 94 | } 95 | 96 | .switcher-game .switch-btn { 97 | background-color: transparent; 98 | border: 1px solid #000000; 99 | height: 30px; 100 | width: 50px; 101 | margin: 0 5px; /* Butonlar arasındaki boşluğu ayarlar */ 102 | display: inline-block; /* Butonları aynı satırda görüntüler */ 103 | vertical-align: top; /* Dikey hizalamayı ayarlar */ 104 | border-radius: 8px; 105 | } 106 | 107 | .switcher-game .switch-btn:hover { 108 | background-color: #ffa66b; 109 | box-shadow: -20px 50px 50px rgba(0,0,0,0.2); 110 | border: none; 111 | color: palegreen; /* Metni gizler */ 112 | transition: none; /* Geçiş efektini kapatır */ 113 | } 114 | 115 | .page-item.active .page-link-profile, 116 | .page-link-profile.active { 117 | background-color: #ff9500 !important; 118 | border-color: #ff9500 !important; 119 | color: #fff !important; 120 | font-size: 1.17em !important; 121 | } 122 | 123 | .page-link { 124 | cursor:pointer; 125 | } 126 | 127 | .page-link-search { 128 | cursor:auto !important; 129 | color: tomato; 130 | } 131 | 132 | .page-item.active .page-link-rankings, 133 | .page-link-rankings.active { 134 | background-color: #ff9500 !important; 135 | border-color: #ff9500 !important; 136 | color: #fff !important; 137 | font-size: 1em !important; 138 | } -------------------------------------------------------------------------------- /indianpong/static/css/remote-player.css: -------------------------------------------------------------------------------- 1 | .pongCanvas { 2 | display: flex; 3 | border: 8px solid rgb(178, 178, 178); 4 | border-style: ridge; 5 | width: 900px; 6 | height: 600px; 7 | margin-top: 30px; 8 | background-color: gray; 9 | } 10 | 11 | .matchmaking-button { 12 | display: flex; 13 | text-align: center; 14 | margin-bottom: 1em; 15 | } 16 | 17 | .other-button { 18 | display: flex; 19 | text-align: center; 20 | margin-bottom: 1em; 21 | } 22 | 23 | 24 | .game-over-remote { 25 | display: none; 26 | position: absolute; 27 | width: 300px; 28 | top: 50%; 29 | left: 55%; 30 | transform: translate(-50%, -50%); 31 | padding: 20px; 32 | background-color: rgba(0, 0, 0, 0.8); 33 | text-align: center; 34 | font-family: Arial, sans-serif; 35 | border-radius: 10px; 36 | } 37 | 38 | 39 | .game-over-remote p { 40 | font-family: 'Pixeboy-z8XGD', sans-serif; 41 | font-size: 20px; 42 | font-weight: bold; 43 | margin-top: -20px; 44 | color: palegreen; 45 | } 46 | 47 | .game-over-remote h1 { 48 | font-size: 48px; 49 | font-family: 'Pixeboy-z8XGD', sans-serif; 50 | margin-bottom: 10px; 51 | } 52 | 53 | .game-over-remote h2 { 54 | font-size: 24px; 55 | color: #ffffff; 56 | font-family: 'Pixeboy-z8XGD', sans-serif; 57 | margin-bottom: 20px; 58 | } 59 | 60 | 61 | .left-card { 62 | width: 300px; 63 | height: 600px; 64 | background-color: #ddd; 65 | padding: 10px; 66 | margin-right: 2em; /* İstediğiniz boşluk değerini ayarlayabilirsiniz */ 67 | margin-left: 1em; 68 | margin-top: 2em; 69 | float: left; 70 | } 71 | 72 | .form-check-input[type="checkbox"] { 73 | transform: scale(1.2); /* Büyüklüğü istediğiniz oranda ayarlayabilirsiniz */ 74 | } 75 | 76 | .selectedmode { 77 | font-size: 14px; 78 | font-weight: bold; 79 | text-align: center; 80 | color:tomato; 81 | } 82 | 83 | .game-mode-info { 84 | display: none; 85 | font-size: 11px !important; 86 | text-align: center; 87 | color: rgb(0, 136, 255); 88 | } 89 | 90 | .game-mode-info-select { 91 | display: block; 92 | text-align: center; 93 | } 94 | 95 | .abilitiesInfo { 96 | display: none; 97 | position: absolute; 98 | top: 50%; 99 | left: 50%; 100 | transform: translate(-50%, -50%); 101 | text-align: center; 102 | padding: 20px; 103 | background-color: rgba(1, 2, 1, 0.5); 104 | width: 700px; 105 | height: 500px; 106 | border-radius: 10px; 107 | } 108 | 109 | .invite-button { 110 | border-color: #26b948; 111 | color: #28a745; 112 | text-align: center; 113 | border-radius: 6px; 114 | background-color: transparent; 115 | width: 32px; 116 | height: 32px; 117 | } 118 | 119 | .invite-button:hover { 120 | background-color: #28a745; 121 | color: white; 122 | } 123 | 124 | 125 | .accept-button { 126 | display: none; 127 | border-color: #007bff; 128 | margin-left: 5px; 129 | color: #007bff; 130 | text-align: center; 131 | border-radius: 6px; 132 | background-color: transparent; 133 | width: 32px; 134 | height: 32px; 135 | } 136 | 137 | .accept-button:hover { 138 | background-color: #007bff; 139 | color: white; 140 | } 141 | 142 | .decline-button { 143 | display: none; 144 | border-color: #dc3545; 145 | margin-left: 5px; 146 | color: #dc3545; 147 | text-align: center; 148 | border-radius: 6px; 149 | background-color: transparent; 150 | width: 32px; 151 | height: 32px; 152 | } 153 | 154 | .decline-button:hover { 155 | background-color: #dc3545; 156 | color: white; 157 | } 158 | 159 | 160 | .custom-table { 161 | border-collapse: collapse; 162 | width: 100%; 163 | } 164 | 165 | .custom-table th, .custom-table td { 166 | border: 1px solid #ddd; 167 | padding: 3px; 168 | text-align: center; 169 | } 170 | 171 | .custom-table tr:hover { 172 | background-color: #b6b6b6; 173 | } 174 | 175 | 176 | .canvas-container { 177 | float: left; 178 | } 179 | 180 | 181 | .toast-close:hover { 182 | cursor: pointer; 183 | color: #000; 184 | } -------------------------------------------------------------------------------- /indianpong/static/css/room-list.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Black+Ops+One&family=Honk&family=Jacquarda+Bastarda+9&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Silkscreen:wght@400;700&display=swap'); 2 | /* Room List */ 3 | 4 | :root { 5 | --card-height: 300px; 6 | --card-width: calc(var(--card-height) / 1.5); 7 | } 8 | 9 | .room-wrapper { 10 | max-width: 1000px; 11 | margin: auto; 12 | text-align: left; 13 | display: flex; 14 | flex-wrap: wrap; 15 | } 16 | 17 | .pong-room, .rps-room { 18 | margin-top: 4em; 19 | } 20 | 21 | .pong-room a, .rps-room a { 22 | text-decoration: none; 23 | } 24 | 25 | 26 | .game-room-card { 27 | width: var(--card-width); 28 | height: var(--card-height); 29 | position: relative; 30 | display: flex; 31 | justify-content: center; 32 | align-items: flex-end; 33 | padding: 0 36px; 34 | perspective: 2500px; 35 | margin: 0 25px; 36 | } 37 | 38 | .cover-image { 39 | width: 100%; 40 | max-height: 300px !important; 41 | height: 300px; 42 | object-fit: cover; 43 | filter: brightness(0.5); 44 | } 45 | 46 | .cover-image-started { 47 | width: 100%; 48 | max-height: 300px !important; 49 | height: 300px; 50 | object-fit: cover; 51 | filter: hue-rotate(170deg) brightness(0.5); 52 | } 53 | 54 | .cover-image-ended { 55 | width: 100%; 56 | max-height: 300px !important; 57 | height: 300px; 58 | object-fit: cover; 59 | filter: grayscale(80%) brightness(0.5); 60 | } 61 | 62 | .wrapper-rooms { 63 | transition: all 0.5s; 64 | position: absolute; 65 | width: 100%; 66 | z-index: -1; 67 | } 68 | 69 | .game-room-card:hover .wrapper-rooms { 70 | transform: perspective(900px) translateY(-5%) rotateX(25deg) translateZ(0); 71 | box-shadow: 2px 35px 32px -8px rgba(0, 0, 0, 0.75); 72 | -webkit-box-shadow: 2px 35px 32px -8px rgba(0, 0, 0, 0.75); 73 | -moz-box-shadow: 2px 35px 32px -8px rgba(0, 0, 0, 0.75); 74 | } 75 | 76 | .wrapper-rooms::before, 77 | .wrapper-rooms::after { 78 | content: ""; 79 | opacity: 0; 80 | width: 100%; 81 | height: 80px; 82 | transition: all 0.5s; 83 | position: absolute; 84 | left: 0; 85 | } 86 | .wrapper-rooms::before { 87 | top: 0; 88 | height: 100%; 89 | background-image: linear-gradient( 90 | to top, 91 | transparent 46%, 92 | rgba(12, 13, 19, 0.5) 68%, 93 | rgba(12, 13, 19) 97% 94 | ); 95 | } 96 | .wrapper-rooms::after { 97 | bottom: 0; 98 | opacity: 1; 99 | background-image: linear-gradient( 100 | to bottom, 101 | transparent 46%, 102 | rgba(12, 13, 19, 0.5) 68%, 103 | rgba(12, 13, 19) 97% 104 | ); 105 | } 106 | 107 | .game-room-card:hover .wrapper-rooms::before, 108 | .wrapper-rooms::after { 109 | opacity: 1; 110 | } 111 | 112 | .game-room-card:hover .wrapper-rooms::after { 113 | height: 120px; 114 | } 115 | 116 | .title-room { 117 | width: 100%; 118 | font-family: "Roboto", sans-serif; 119 | font-weight: bold; 120 | text-align: center; 121 | font-style: normal; 122 | color:white; 123 | transition: transform 0.5s; 124 | 125 | } 126 | 127 | .title-room h4 { 128 | margin-bottom: -2px; 129 | } 130 | 131 | .title-room p { 132 | margin-top: -6px; 133 | } 134 | 135 | .game-room-card:hover .title { 136 | transform: translate3d(0%, -50px, 100px); 137 | } 138 | 139 | .character { 140 | width: 100%; 141 | opacity: 0; 142 | transition: all 0.5s; 143 | position: absolute; 144 | z-index: -1; 145 | } 146 | 147 | .game-room-card:hover .character { 148 | opacity: 1; 149 | transform: translate3d(0%, -30%, 100px); 150 | } 151 | 152 | 153 | .page-link { 154 | cursor:pointer; 155 | } 156 | 157 | .page-link-search { 158 | cursor:auto !important; 159 | color: tomato; 160 | } 161 | 162 | .page-item.active .page-link-roomlist, 163 | .page-link-roomlist.active { 164 | background-color: #ff9500 !important; 165 | border-color: #ff9500 !important; 166 | color: #fff !important; 167 | font-size: 1em !important; 168 | } 169 | -------------------------------------------------------------------------------- /indianpong/static/css/scrollbar.css: -------------------------------------------------------------------------------- 1 | /* width */ 2 | ::-webkit-scrollbar { 3 | width: 10px; 4 | } 5 | 6 | /* Track */ 7 | ::-webkit-scrollbar-track { 8 | background: #453A4E; 9 | } 10 | 11 | /* Handle */ 12 | ::-webkit-scrollbar-thumb { 13 | background: #F99601; 14 | } 15 | 16 | /* Handle on hover */ 17 | ::-webkit-scrollbar-thumb:hover { 18 | background: rgb(252, 171, 51); 19 | } -------------------------------------------------------------------------------- /indianpong/static/fonts/CommonPixel.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/fonts/CommonPixel.ttf -------------------------------------------------------------------------------- /indianpong/static/fonts/Lobster-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/fonts/Lobster-Regular.ttf -------------------------------------------------------------------------------- /indianpong/static/fonts/Minecraftia-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/fonts/Minecraftia-Regular.ttf -------------------------------------------------------------------------------- /indianpong/static/fonts/Pixeboy-z8XGD.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/fonts/Pixeboy-z8XGD.ttf -------------------------------------------------------------------------------- /indianpong/static/fonts/alagard.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/fonts/alagard.ttf -------------------------------------------------------------------------------- /indianpong/static/fonts/rainyhearts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/fonts/rainyhearts.ttf -------------------------------------------------------------------------------- /indianpong/static/js/base-chat.js: -------------------------------------------------------------------------------- 1 | export function getChat(username) { 2 | if (!username) { 3 | return; 4 | } 5 | 6 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 7 | 8 | fetch(`/start_chat/${username}`, { 9 | method: 'POST', 10 | body: JSON.stringify({ username: username }), 11 | headers: { 12 | 'Content-Type': 'application/json', 13 | 'X-CSRFToken': csrftoken 14 | }, 15 | }) 16 | .then(response => { 17 | if (!response.ok) { 18 | throw new Error(`HTTP error! Status: ${response.status}`); 19 | } 20 | return response.json(); 21 | }) 22 | .then(data => { 23 | if (!data.room_id) { 24 | throw new Error('Invalid response: missing room_id'); 25 | } 26 | 27 | const roomId = data.room_id; 28 | const newUrl = `/chat/${roomId}/`; 29 | swapApp(newUrl); 30 | }) 31 | .catch(error => { 32 | console.error('Error:', error.message); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /indianpong/static/js/burger.js: -------------------------------------------------------------------------------- 1 | export function initializeBurger () { 2 | document.querySelector(".burger-menu").addEventListener("click", function () { 3 | var navLinks = document.querySelector(".nav-links"); 4 | if (navLinks.classList.contains("show")) { 5 | navLinks.classList.remove("show"); 6 | } else { 7 | navLinks.classList.add("show"); 8 | } 9 | }); 10 | } -------------------------------------------------------------------------------- /indianpong/static/js/create-tournament.js: -------------------------------------------------------------------------------- 1 | export function createTournament() { 2 | 3 | 4 | function showToast(content, status, iconClass) { 5 | const liveToast = document.getElementById('liveToast'); 6 | var toastContent = document.querySelector('#liveToast .fw-semibold'); 7 | var toastIcon = document.querySelector('.toast-body .i-class i'); 8 | 9 | toastIcon.className = iconClass; 10 | liveToast.classList.remove('text-bg-danger'); 11 | liveToast.className = 'toast'; 12 | liveToast.classList.add(status); 13 | 14 | toastContent.textContent = content; 15 | const toast = new bootstrap.Toast(liveToast); 16 | toast.show(); 17 | setTimeout(function() { 18 | toast.hide(); 19 | }, 8000); 20 | } 21 | var form = document.getElementById('TournamentForm'); 22 | var formData = new FormData(form); 23 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 24 | fetch('/tournament-create', { 25 | method: 'POST', 26 | headers: { 27 | 'X-CSRFToken': csrftoken 28 | }, 29 | body: formData 30 | }) 31 | .then(response => response.text()) 32 | .then(data => { 33 | if (data.includes("/tournament-room/")) 34 | swapApp(data); 35 | else { 36 | showToast(`${data}`, `text-bg-danger`, `bi bi-bug-fill`); 37 | } 38 | }) 39 | .catch(error => { 40 | console.error(error); 41 | }); 42 | } -------------------------------------------------------------------------------- /indianpong/static/js/login.js: -------------------------------------------------------------------------------- 1 | export function initializeLogin() { 2 | const passwordInput = document.getElementById('id_password'); 3 | const toggleButton = document.getElementById('togglePassword'); 4 | 5 | toggleButton.addEventListener('mousedown', function() { 6 | passwordInput.type = 'text'; 7 | toggleButton.classList.remove('bi-eye-slash-fill'); 8 | toggleButton.classList.add('bi-eye-fill'); 9 | }); 10 | 11 | toggleButton.addEventListener('mouseup', function() { 12 | passwordInput.type = 'password'; 13 | toggleButton.classList.remove('bi-eye-fill'); 14 | toggleButton.classList.add('bi-eye-slash-fill'); 15 | }); 16 | passwordInput.addEventListener('input', function() { 17 | toggleButton.style.display = this.value.trim() !== '' ? 'block' : 'none'; 18 | }); 19 | } 20 | 21 | function showToast(content, status, iconClass) { 22 | const liveToast = document.getElementById('liveToast'); 23 | var toastContent = document.querySelector('#liveToast .fw-semibold'); 24 | var toastIcon = document.querySelector('.toast-body .i-class i'); 25 | 26 | toastIcon.className = iconClass; 27 | liveToast.classList.remove('text-bg-danger'); 28 | liveToast.className = 'toast'; 29 | liveToast.classList.add(status); 30 | 31 | toastContent.textContent = content; 32 | 33 | const toast = new bootstrap.Toast(liveToast); 34 | toast.show(); 35 | } 36 | 37 | export function makeLogin(check) { 38 | if(!check) 39 | return; 40 | var form = document.getElementById('loginForm'); 41 | var formData = new FormData(form); 42 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 43 | fetch('/login', { 44 | method: 'POST', 45 | headers: { 46 | 'X-CSRFToken': csrftoken 47 | }, 48 | body: formData 49 | }) 50 | .then(response => response.text()) 51 | .then(data => { 52 | if (data == "dashboard") 53 | swapApp('/dashboard'); 54 | else { 55 | showToast(`${data}`, `text-bg-danger`, `bi bi-bug-fill`); 56 | } 57 | }) 58 | .catch(error => { 59 | console.error(error); 60 | }); 61 | } -------------------------------------------------------------------------------- /indianpong/static/js/profile.js: -------------------------------------------------------------------------------- 1 | var isRPSVisibleHistory = true; 2 | 3 | export function matchHistoryChanger(status) { 4 | 5 | if (!status) 6 | return; 7 | var switcherBtn = document.querySelector(".changer-btn"); 8 | var historyPong = document.getElementById('match-history-pong'); 9 | var historyRPS = document.getElementById('match-history-rps'); 10 | isRPSVisibleHistory = !isRPSVisibleHistory; 11 | 12 | if (isRPSVisibleHistory) { 13 | // Ping pong istatistiklerini göster 14 | historyPong.style.display = 'block'; 15 | historyRPS.style.display = 'none'; 16 | switcherBtn.innerHTML = '🏓'; // HTML içeriğine Unicode karakterini ekleyin 17 | } else { 18 | // RPS istatistiklerini göster 19 | historyPong.style.display = 'none'; 20 | historyRPS.style.display = 'block'; 21 | switcherBtn.innerHTML = '✂️'; // HTML içeriğine Unicode karakterini ekleyin 22 | } 23 | 24 | // Durumu tersine çevir 25 | } 26 | 27 | var isRPSVisibleStats = true; 28 | 29 | export function toggleGame(status) { 30 | if (!status) 31 | return; 32 | var switcherBtn = document.querySelector(".switch-btn"); 33 | var statsPong = document.getElementById('stats-info-pong'); 34 | var statsRPS = document.getElementById('stats-info-rps'); 35 | isRPSVisibleStats = !isRPSVisibleStats; 36 | 37 | if (isRPSVisibleStats) { 38 | // Ping pong istatistiklerini göster 39 | statsPong.style.display = 'block'; 40 | statsRPS.style.display = 'none'; 41 | switcherBtn.innerHTML = '🏓'; // HTML içeriğine Unicode karakterini ekleyin 42 | } else { 43 | // RPS istatistiklerini göster 44 | statsPong.style.display = 'none'; 45 | statsRPS.style.display = 'block'; 46 | switcherBtn.innerHTML = '✂️'; // HTML içeriğine Unicode karakterini ekleyin 47 | } 48 | 49 | // Durumu tersine çevir 50 | } 51 | 52 | export function followButton(username) { 53 | if(!username) 54 | return; 55 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 56 | var button = document.getElementById('followbtn'); 57 | var button2 = document.getElementById('unfollowbtn'); 58 | fetch(`/follow_unfollow/${username}`, { 59 | method: 'POST', 60 | headers: { 61 | 'Content-Type': 'application/json', 62 | 'X-CSRFToken': csrftoken 63 | }, 64 | body: JSON.stringify({ action: "follow" }) 65 | }) 66 | .then(response => response.json()) 67 | .then(data => { 68 | if (data['status'] === 'ok') { 69 | button.style.display = 'none'; 70 | button2.style.display = 'block'; 71 | } 72 | }); 73 | } 74 | 75 | export function unfollowButton(username) { 76 | if(!username) 77 | return; 78 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 79 | var button = document.getElementById('unfollowbtn'); 80 | var button2 = document.getElementById('followbtn'); 81 | fetch(`/follow_unfollow/${username}`, { 82 | method: 'POST', 83 | headers: { 84 | 'Content-Type': 'application/json', 85 | 'X-CSRFToken': csrftoken 86 | }, 87 | body: JSON.stringify({ action: "unfollow" }) 88 | }) 89 | .then(response => response.json()) 90 | .then(data => { 91 | if (data['status'] === 'ok') { 92 | button.style.display = 'none'; 93 | button2.style.display = 'block'; 94 | } 95 | }); 96 | } 97 | -------------------------------------------------------------------------------- /indianpong/static/js/search.js: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | const cookieValue = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)'); 3 | return cookieValue ? cookieValue.pop() : ''; 4 | } 5 | 6 | export function initializeSearch() { 7 | 8 | const followButtons = document.querySelectorAll(".button-follow"); 9 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 10 | followButtons.forEach((button) => { 11 | button.addEventListener('click', (e) => { 12 | const username = e.target.getAttribute('data-username'); 13 | const lang = getCookie('selectedLanguage'); 14 | let action = e.target.innerHTML.trim(); 15 | if (action == "अनुसरण करना" || action == "Seguir" || action == "Takip Et" || action == "Follow") { 16 | action = "follow" 17 | } else if (action == "अनफ़ॉलो" || action == "Deixar" || action == "Takipten Çık" || action == "Unfollow") { 18 | action = "unfollow" 19 | } 20 | fetch(`/follow_unfollow/${username}`, { 21 | method: 'POST', 22 | headers: { 23 | 'Content-Type': 'application/json', 24 | 'X-CSRFToken': csrftoken 25 | }, 26 | body: JSON.stringify({ action: action }) 27 | }) 28 | .then(response => response.json()) 29 | .then(data => { 30 | if (data['status'] === 'ok') { 31 | if (lang == 'hi') { 32 | e.target.innerHTML = data['action'] === 'follow' ? 'अनफ़ॉलो' : 'अनुसरण करना'; 33 | e.target.style.backgroundColor = data['action'] === 'follow' ? 'black' : '#dc3545'; 34 | } 35 | else if(lang == 'tr') { 36 | e.target.innerHTML = data['action'] === 'follow' ? 'Takipten Çık' : 'Takip Et'; 37 | e.target.style.backgroundColor = data['action'] === 'follow' ? 'black' : '#dc3545'; 38 | } 39 | else if (lang == 'pt') { 40 | e.target.innerHTML = data['action'] === 'follow' ? 'Deixar' : 'Seguir'; 41 | e.target.style.backgroundColor = data['action'] === 'follow' ? 'black' : '#dc3545'; 42 | } 43 | else { 44 | e.target.innerHTML = data['action'] === 'follow' ? 'Unfollow' : 'Follow'; 45 | e.target.style.backgroundColor = data['action'] === 'follow' ? 'black' : '#dc3545'; 46 | } 47 | } 48 | }); 49 | }); 50 | }); 51 | } 52 | 53 | export function makeSearch(action) { 54 | if (!action) 55 | return; 56 | 57 | var form = document.getElementById('searchForm'); 58 | var formData = new FormData(form); 59 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 60 | fetch('/search', { 61 | method: 'POST', 62 | headers: { 63 | 'X-CSRFToken': csrftoken 64 | }, 65 | body: formData 66 | }) 67 | .then(response => response.text()) 68 | .then(data => { 69 | document.body.innerHTML = data; 70 | initializeSearch(); 71 | }) 72 | .catch(error => { 73 | console.error(error); 74 | }); 75 | } -------------------------------------------------------------------------------- /indianpong/static/js/signup.js: -------------------------------------------------------------------------------- 1 | export function initializeSignup() { 2 | const passwordInput1 = document.getElementById('id_password1'); 3 | const passwordInput2 = document.getElementById('id_password2'); 4 | const toggleButton1 = document.getElementById('togglePassword1'); 5 | const toggleButton2 = document.getElementById('togglePassword2'); 6 | 7 | toggleButton1.addEventListener('mousedown', function() { 8 | passwordInput1.type = 'text'; 9 | toggleButton1.classList.remove('bi-eye-slash-fill'); 10 | toggleButton1.classList.add('bi-eye-fill'); 11 | }); 12 | 13 | toggleButton1.addEventListener('mouseup', function() { 14 | passwordInput1.type = 'password'; 15 | toggleButton1.classList.remove('bi-eye-fill'); 16 | toggleButton1.classList.add('bi-eye-slash-fill'); 17 | }); 18 | 19 | toggleButton2.addEventListener('mousedown', function() { 20 | passwordInput2.type = 'text'; 21 | toggleButton2.classList.remove('bi-eye-slash-fill'); 22 | toggleButton2.classList.add('bi-eye-fill'); 23 | }); 24 | 25 | toggleButton2.addEventListener('mouseup', function() { 26 | passwordInput2.type = 'password'; 27 | toggleButton2.classList.remove('bi-eye-fill'); 28 | toggleButton2.classList.add('bi-eye-slash-fill'); 29 | }); 30 | 31 | passwordInput1.addEventListener('input', function() { 32 | toggleButton1.style.display = this.value.trim() !== '' ? 'block' : 'none'; 33 | }); 34 | 35 | passwordInput2.addEventListener('input', function() { 36 | toggleButton2.style.display = this.value.trim() !== '' ? 'block' : 'none'; 37 | }); 38 | 39 | function getCookie(name) { 40 | const cookieValue = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)'); 41 | return cookieValue ? cookieValue.pop() : ''; 42 | } 43 | 44 | const fileInput = document.getElementById('id_avatar'); 45 | if (fileInput) { 46 | fileInput.addEventListener('change', function(event) { 47 | const selectedLanguage = getCookie('selectedLanguage'); 48 | var file = this.files[0]; 49 | if (file && file.size > 2 * 1024 * 1024) { 50 | var messages = { 51 | 'en': "Photo must be under 2MB!", 52 | 'tr': "Fotoğraf 2MB'dan küçük olmalıdır!", 53 | 'hi': "फोटो 2MB से कम होना चाहिए!", 54 | 'pt': "A foto deve ter menos de 2MB!" 55 | }; 56 | var message = messages[selectedLanguage] || "Photo must be under 2MB!"; 57 | showToast(message, "text-bg-danger", "bi bi-image"); 58 | this.value = ''; 59 | } 60 | else { 61 | var messages = { 62 | 'en': "Photo added!", 63 | 'tr': "Fotoğraf eklendi!", 64 | 'hi': "फोटो जोड़ दी गई!", 65 | 'pt': "Foto adicionada!" 66 | }; 67 | var message = messages[selectedLanguage] || "Photo added!"; 68 | showToast(message, "text-bg-success", "bi bi-image"); 69 | } 70 | }); 71 | } 72 | } 73 | 74 | export function makeRegister(check) { 75 | if (!check) 76 | return; 77 | const selectedLanguage = getCookie('selectedLanguage'); 78 | if (document.getElementById('gdprCheckbox').checked == false) { 79 | if (selectedLanguage == 'en') 80 | showToast("Please accept the terms and conditions", "text-bg-danger", "bi bi-exclamation-triangle-fill"); 81 | else if (selectedLanguage == 'tr') 82 | showToast("Lütfen şartları ve koşulları kabul edin", "text-bg-danger", "bi bi-exclamation-triangle-fill"); 83 | else if (selectedLanguage == 'hi') 84 | showToast("कृपया नियम और शर्तों को स्वीकार करें", "text-bg-danger", "bi bi-exclamation-triangle-fill"); 85 | else if (selectedLanguage == 'pt') 86 | showToast("Por favor, aceite os termos e condições", "text-bg-danger", "bi bi-exclamation-triangle-fill"); 87 | return; 88 | } 89 | var form = document.getElementById('registerForm'); 90 | var formData = new FormData(form); 91 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 92 | 93 | if (formData.get['username'] == 'IndianAI') { 94 | if (selectedLanguage == 'en') 95 | showToast("Username is not allowed", "text-bg-danger", "bi bi-person-x-fill"); 96 | else if (selectedLanguage == 'tr') 97 | showToast("Kullanıcı adı izin verilmiyor", "text-bg-danger", "bi bi-person-x-fill"); 98 | else if (selectedLanguage == 'hi') 99 | showToast("उपयोगकर्ता नाम अनुमत नहीं है", "text-bg-danger", "bi bi-person-x-fill"); 100 | else if (selectedLanguage == 'pt') 101 | showToast("Nome de usuário não permitido", "text-bg-danger", "bi bi-person-x-fill"); 102 | } 103 | fetch('/signup', { 104 | method: 'POST', 105 | headers: { 106 | 'X-CSRFToken': csrftoken 107 | }, 108 | body: formData 109 | }) 110 | .then(response => response.text()) 111 | .then(data => { 112 | if (data == "login") { 113 | swapApp('/login'); 114 | } else { 115 | document.body.innerHTML = data; 116 | } 117 | }) 118 | .catch(error => { 119 | console.error(error); 120 | }); 121 | } 122 | 123 | -------------------------------------------------------------------------------- /indianpong/static/js/store.js: -------------------------------------------------------------------------------- 1 | function initializeStore() { 2 | 3 | const storeInfos = document.getElementsByClassName('store-info'); // .store-info'ya erişim 4 | const smallWalletNames = document.getElementsByClassName('small-wallet-name'); 5 | 6 | for (let i = 0; i < smallWalletNames.length; i++) { 7 | smallWalletNames[i].addEventListener('mouseover', () => { 8 | storeInfos[i].style.visibility = 'visible'; 9 | }); 10 | 11 | smallWalletNames[i].addEventListener('mouseout', () => { 12 | storeInfos[i].style.visibility = 'hidden'; 13 | }); 14 | } 15 | } 16 | 17 | function showToast(content, status, iconClass) { 18 | const liveToast = document.getElementById('liveToast'); 19 | var toastContent = document.querySelector('#liveToast .fw-semibold'); 20 | var toastIcon = document.querySelector('.toast-body .i-class i'); 21 | 22 | toastIcon.className = iconClass; 23 | liveToast.classList.remove('text-bg-danger'); 24 | liveToast.className = 'toast'; 25 | liveToast.classList.add(status); 26 | 27 | toastContent.textContent = content; 28 | 29 | const toast = new bootstrap.Toast(liveToast); 30 | toast.show(); 31 | 32 | } 33 | 34 | function submitStoreItemForm(username, itemName, formId, price) { 35 | const cookie = document.cookie.split('; ').find(row => row.startsWith('selectedLanguage=')); 36 | const lang = cookie ? cookie.split('=')[1] : 'en'; 37 | const form = document.getElementById('store_item_form' + formId); 38 | const formData = new FormData(form); 39 | var csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken')).split('=')[1]; 40 | fetch(`/store/${username}/`, { 41 | method: form.method, 42 | body: formData, 43 | headers: { 44 | 'X-CSRFToken': csrftoken 45 | } 46 | }) 47 | .then(response => response.text()) 48 | .then(data => { 49 | // hide the item after it is bought 50 | const productCard = document.getElementById('product-card-' + formId); 51 | productCard.style.display = 'none'; 52 | //update the wallet amount with price 53 | const walletAmount = document.querySelector('.wallet-amount'); 54 | walletAmount.textContent = (parseInt(walletAmount.textContent) - price) + 'N₩'; 55 | document.body.innerHTML = data; 56 | if (lang === 'tr') 57 | showToast(`${itemName} öğesini başarıyla satın aldın!`, `text-bg-success`, `bi bi-shop`); 58 | else if (lang === 'hi') 59 | showToast(`आपने ${itemName} आइटम सफलतापूर्वक खरीद लिया है!`, `text-bg-success`, `bi bi-shop`); 60 | else if (lang === 'pt') 61 | showToast(`Você comprou com sucesso o item ${itemName}!`, `text-bg-success`, `bi bi-shop`); 62 | else 63 | showToast(`You have successfully bought ${itemName} item!`, `text-bg-success`, `bi bi-shop`); 64 | }) 65 | .catch((error) => { 66 | console.error('Error:', error); 67 | }); 68 | } -------------------------------------------------------------------------------- /indianpong/static/music/defeat-sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/defeat-sound.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/fast-and-furious.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/fast-and-furious.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/frozen-ball.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/frozen-ball.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/one_beep.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/one_beep.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/one_beep_2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/one_beep_2.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/one_beep_2_left.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/one_beep_2_left.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/one_beep_2_right.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/one_beep_2_right.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/pong-defeat-sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/pong-defeat-sound.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/pong-music.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/pong-music.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/pong-victory-sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/pong-victory-sound.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-cheater.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-cheater.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-defeat.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-defeat.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-drawonce.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-drawonce.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-godthings.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-godthings.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-loseonce.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-loseonce.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-paper.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-paper.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-rock.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-rock.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-scissors.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-scissors.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-win.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-win.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/rps-winonce.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/rps-winonce.mp3 -------------------------------------------------------------------------------- /indianpong/static/music/victory-sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleizean/ft_transcendence/de707d37c3443249f6068f5d315805c5c8d94d6b/indianpong/static/music/victory-sound.mp3 -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 1024; 3 | } 4 | 5 | http { 6 | gzip on; 7 | gzip_types text/plain text/css application/json application/x-javascript text/xml image/svg+xml application/xml application/xml+rss text/javascript application/javascript; 8 | 9 | include mime.types; 10 | 11 | server { 12 | listen 8000; 13 | server_name localhost; 14 | location / { 15 | return 301 https://$host:8443$request_uri; 16 | } 17 | } 18 | 19 | server { 20 | listen 8443 ssl; 21 | server_name localhost; 22 | 23 | ssl_certificate /etc/nginx/ssl/cert.pem; 24 | ssl_certificate_key /etc/nginx/ssl/key.pem; 25 | 26 | location /static/ { 27 | alias /indianpong/staticfiles/; 28 | } 29 | 30 | location /media/ { 31 | alias /indianpong/media/; 32 | } 33 | 34 | location /ws/ { 35 | proxy_pass http://web:8001; 36 | proxy_http_version 1.1; 37 | proxy_set_header Upgrade $http_upgrade; 38 | proxy_set_header Connection "upgrade"; 39 | } 40 | 41 | location / { 42 | proxy_pass http://web:8001; 43 | proxy_set_header Host $host; 44 | proxy_set_header X-Real-IP $remote_addr; 45 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 46 | proxy_set_header X-Forwarded-Proto $scheme; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==5.0 2 | Pillow==11.0.0 3 | channels==4.0.0 4 | daphne==4.0.0 5 | psycopg2-binary 6 | requests 7 | 8 | --------------------------------------------------------------------------------