diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6db8bf9 --- /dev/null +++ b/.env.example @@ -0,0 +1,33 @@ +POSTGRES_USER= +POSTGRES_PASSWORD= + +DB_NAME= +DB_USER= +DB_PASSWORD= +DB_HOST= +DB_PORT= + +DJANGO_SUPERUSER_USERNAME= +DJANGO_SUPERUSER_PASSWORD= +DJANGO_SUPERUSER_EMAIL= + +OAUTH_URL=https://api.intra.42.fr/oauth/authorize +OAUTH_CLIENT_ID= +OAUTH_CLIENT_SECRET= +OAUTH_REDIRECT_URI= +OAUTH_TOKEN_URL=https://api.intra.42.fr/oauth/token +OAUTH_USER_INFO_URL=https://api.intra.42.fr/v2/me +OAUTH_STATE= + +SECRET_KEY= + +EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST= +EMAIL_PORT= +EMAIL_HOST_USER= +EMAIL_HOST_PASSWORD= +DEFAULT_FROM_EMAIL= + +CONTRACT_ADDRESS= +RPC_URL= +PRIVATE_KEY= diff --git a/.gitignore b/.gitignore index 398e72d..3f30a02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,4 @@ -# OS -.DS_Store - -# Nginx -default.conf - -# vite -node_modules/ - -# Django -0001_initial.py +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # Byte-compiled / optimized / DLL files __pycache__/ @@ -72,6 +62,7 @@ cover/ local_settings.py db.sqlite3 db.sqlite3-journal +0001_initial.py # Flask stuff: instance/ @@ -106,12 +97,18 @@ ipython_config.py # install all needed dependencies. #Pipfile.lock +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock +poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. @@ -134,7 +131,12 @@ celerybeat.pid *.sage.py # Environments +# Environment files .env +.env.local* +.env.test* +.env.development* +.env.production* .venv env/ venv/ @@ -172,3 +174,25 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# PyPI configuration file +.pypirc + +# Miscellaneous files +.DS_Store +*.pem + +# VSCode specific files +.vscode/ +tempCodeRunnerFile.* + +# Git related files +*.patch + +# Python specific files +.venv +__pycache__/ + +# My specific files +review.md +default.conf diff --git a/Makefile b/Makefile index a0beb26..c89a9ec 100644 --- a/Makefile +++ b/Makefile @@ -29,53 +29,44 @@ RESET := \033[0m all: @sh nginx/make_config.sh - @$(MAKE) build + @cp .env.production ./frontend/.env + @cp .env.production ./backend/.env + @cp .env.production .env @$(MAKE) up -build: - @echo "🐳 $(FG_BLUE)Building images$(RESET) 🐳" - @docker-compose -f docker-compose.yml build - @echo "πŸ›  $(FG_GREEN)Built images$(RESET) πŸ› " - up: - @docker-compose -f docker-compose.yml up -d + @docker compose -p transcendence -f docker-compose.yml up --build -d @echo "πŸ›œ $(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)https://localhost$(RESET) πŸ›œ" down: - @docker-compose -f docker-compose.yml down + @docker compose -p transcendence -f docker-compose.yml down @echo "🚫 $(FG_RED)Disconnected$(RESET) 🚫" stop: - @docker-compose -f docker-compose.yml stop + @docker compose -p transcendence -f docker-compose.yml stop @echo "πŸ›‘ $(FG_YELLOW)Stopped$(RESET) πŸ›‘" start: @echo "$(FG_GREEN)Started$(RESET)" - @docker-compose -f docker-compose.yml start + @docker compose -p transcendence -f docker-compose.yml start @echo "$(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)https://localhost$(RESET)" re: @echo "$(FG_GREEN)Restarted$(RESET)" - @$(MAKE) fclean + @$(MAKE) clean @$(MAKE) all log: @echo "πŸ“„ $(FG_CYAN)Logs$(RESET) πŸ“„" - @docker-compose -f docker-compose.yml logs -f + @docker compose -p transcendence -f docker-compose.yml logs -f clean: @$(MAKE) down @docker system prune -af --volumes @echo "🧹 $(FG_BLUE)Cleaned up$(RESET) 🧹" -fclean: - @$(MAKE) down - @docker system prune -af --volumes - @docker volume rm transcendence_db_data - @echo "🧹 $(FG_BLUE)Fully cleaned up$(RESET) 🧹" - populatedb: @docker exec -it backend python manage.py populatedb -.PHONY: all build up down stop start re log clean fclean populatedb +.PHONY: all build up down stop start re log clean populatedb diff --git a/backend/transcendence/settings.py b/backend/transcendence/settings.py index e9d719a..0b20e20 100644 --- a/backend/transcendence/settings.py +++ b/backend/transcendence/settings.py @@ -6,7 +6,6 @@ from rest_framework.response import Response - # TEST: λ‘œμ»¬μ—μ„œ ν…ŒμŠ€νŠΈν•  λ•Œ μ‚¬μš©, docker-compose 이용 μ‹œ ν™˜κ²½λ³€μˆ˜λ‘œ μ•Œμ•„μ„œ 섀정됨 from dotenv import load_dotenv @@ -19,23 +18,23 @@ # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.getenv('SECRET_KEY') -OAUTH_REDIRECT_URI = os.getenv('OAUTH_REDIRECT_URI') - -OAUTH_URL = os.getenv('OAUTH_URL') -OAUTH_TOKEN_URL = os.getenv('OAUTH_TOKEN_URL') -OAUTH_USER_INFO_URL = os.getenv('OAUTH_USER_INFO_URL') -OAUTH_CLIENT_ID = os.getenv('OAUTH_CLIENT_ID') -OAUTH_CLIENT_SECRET = os.getenv('OAUTH_CLIENT_SECRET') -OAUTH_STATE = os.getenv('OAUTH_STATE') - -EMAIL_BACKEND = os.getenv('EMAIL_BACKEND') -EMAIL_HOST = os.getenv('EMAIL_HOST') -EMAIL_PORT = os.getenv('EMAIL_PORT') +SECRET_KEY = os.getenv("SECRET_KEY") +OAUTH_REDIRECT_URI = os.getenv("OAUTH_REDIRECT_URI") + +OAUTH_URL = os.getenv("OAUTH_URL") +OAUTH_TOKEN_URL = os.getenv("OAUTH_TOKEN_URL") +OAUTH_USER_INFO_URL = os.getenv("OAUTH_USER_INFO_URL") +OAUTH_CLIENT_ID = os.getenv("OAUTH_CLIENT_ID") +OAUTH_CLIENT_SECRET = os.getenv("OAUTH_CLIENT_SECRET") +OAUTH_STATE = os.getenv("OAUTH_STATE") + +EMAIL_BACKEND = os.getenv("EMAIL_BACKEND") +EMAIL_HOST = os.getenv("EMAIL_HOST") +EMAIL_PORT = os.getenv("EMAIL_PORT") EMAIL_USE_TLS = True -EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER') -EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD') -DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL') +EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER") +EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") +DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL") # SECURITY WARNING: don't run with debug turned on in production! @@ -47,64 +46,67 @@ # Application definition INSTALLED_APPS = [ - "daphne", - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', + "daphne", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "rest_framework", "corsheaders", - 'drf_yasg', - 'rest_framework_simplejwt', + "drf_yasg", + "rest_framework_simplejwt", "users", "login.apps.LoginConfig", "game", ] + + def custom_exception_handler(exc, context): - view = context.get('view', None) - func_name = view.__class__.__name__ if view else 'UnknownFunction' + view = context.get("view", None) + func_name = view.__class__.__name__ if view else "UnknownFunction" logger = logging.getLogger(func_name) - logger.error(f"Exception: {exc.__class__.__name__} - {str(exc)} \n Context: {context}") + logger.error( + f"Exception: {exc.__class__.__name__} - {str(exc)} \n Context: {context}" + ) response = exception_handler(exc, context) if response is not None: return response else: - return Response({'Unkwon Error': 'An error occurred.'}, status=500) + return Response({"Unkwon Error": "An error occurred."}, status=500) + REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework_simplejwt.authentication.JWTAuthentication', + "DEFAULT_AUTHENTICATION_CLASSES": ( + "rest_framework_simplejwt.authentication.JWTAuthentication", ), - 'EXCEPTION_HANDLER': 'transcendence.custom_exception_handler.custom_exception_handler', + "EXCEPTION_HANDLER": "transcendence.custom_exception_handler.custom_exception_handler", } MIDDLEWARE = [ - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] CORS_ORIGIN_ALLOW_ALL = True # TEST: λͺ¨λ“  도메인 ν—ˆμš© (λ³΄μ•ˆ μ·¨μ•½) CSRF_TRUSTED_ORIGINS = [ - "http://localhost:5173", + "http://localhost:5173", ] -ALLOWED_HOSTS = [ - "*" -] +ALLOWED_HOSTS = ["*"] CORS_ALLOWED_ORIGINS = [ "http://localhost:5173", @@ -112,41 +114,41 @@ def custom_exception_handler(exc, context): CORS_ALLOW_CREDENTIALS = True # μΏ ν‚€ ν—ˆμš© -SESSION_COOKIE_HTTPONLY = True # μΏ ν‚€λ₯Ό HTTP둜만 전솑 +SESSION_COOKIE_HTTPONLY = True # μΏ ν‚€λ₯Ό HTTP둜만 전솑 -ROOT_URLCONF = 'transcendence.urls' +ROOT_URLCONF = "transcendence.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', + "BACKEND": "django.template.backends.django.DjangoTemplates", # feature01-42OAuth_Login μ—μ„œ 좔가됨 μ›λž˜ [] 둜 λΉ„μ–΄μžˆμ—ˆμŒ - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'transcendence.wsgi.application' +WSGI_APPLICATION = "transcendence.wsgi.application" # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.getenv('DB_NAME'), - 'USER': os.getenv('DB_USER'), - 'PASSWORD': os.getenv('DB_PASSWORD'), - 'HOST': os.getenv('DB_HOST', 'localhost'), - 'PORT': os.getenv('DB_PORT', '5432'), + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.getenv("DB_NAME"), + "USER": os.getenv("DB_USER"), + "PASSWORD": os.getenv("DB_PASSWORD"), + "HOST": os.getenv("DB_HOST", "postgres"), + "PORT": os.getenv("DB_PORT", "5432"), } } @@ -156,16 +158,16 @@ def custom_exception_handler(exc, context): AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -173,9 +175,9 @@ def custom_exception_handler(exc, context): # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ -LANGUAGE_CODE = 'ko-kr' +LANGUAGE_CODE = "ko-kr" -TIME_ZONE = 'Asia/Seoul' +TIME_ZONE = "Asia/Seoul" USE_I18N = True @@ -185,12 +187,12 @@ def custom_exception_handler(exc, context): # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ -STATIC_URL = 'static/' +STATIC_URL = "static/" # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # Daphne ASGI_APPLICATION = "transcendence.asgi.application" diff --git a/db/Dockerfile b/db/Dockerfile index e25303e..76b5868 100644 --- a/db/Dockerfile +++ b/db/Dockerfile @@ -1,12 +1,5 @@ FROM postgres:13 -# ν™˜κ²½ λ³€μˆ˜ μ„€μ • (선택 사항) -ENV POSTGRES_USER=admin -ENV POSTGRES_PASSWORD=superuser -ENV DB_NAME=transcendence -ENV DB_USER=ppadmin -ENV DB_PASSWORD=password123 - COPY init-db.sh /docker-entrypoint-initdb.d/ EXPOSE 5432 diff --git a/run_backend.sh b/run_backend.sh index cf0278f..ad21886 100755 --- a/run_backend.sh +++ b/run_backend.sh @@ -1,6 +1,7 @@ #!/bin/bash # TEST: 개발 μ‹œ 둜컬 μ‹€ν–‰μš© +cp .env.local .env # Initialize the environment (arg 1 to clear everything) if [ "$1" == "1" ]; then @@ -16,9 +17,9 @@ fi # Check if the container is not running if [ -z "$(docker ps -aq -f name=postgres)" ]; then - docker volume create db_data + docker volume create transcendence_db_data docker build -t postgres db/ - docker run -d -p 5432:5432 --name postgres --env-file .env -v db_data:/var/lib/postgresql/data postgres + docker run -d -p 5432:5432 --name postgres --env-file .env -v transcendence_db_data:/var/lib/postgresql/data postgres fi ENV_DIR="venv" diff --git a/run_frontend.sh b/run_frontend.sh index 38a6b06..ec411ae 100755 --- a/run_frontend.sh +++ b/run_frontend.sh @@ -1,3 +1,6 @@ #!/bin/bash # TEST: 개발 μ‹œ 둜컬 μ‹€ν–‰μš© + +cp .env.local .env + cd frontend && npm install && npm run dev