diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..fa80c9e --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +transcendence diff --git a/Makefile b/Makefile index 2e38507..9472533 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ build: up: @docker-compose -f docker-compose.yml up -d - @echo "๐Ÿ›œ $(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)https://localhost$(RESET) ๐Ÿ›œ" + @echo "๐Ÿ›œ $(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)https://localhost:80$(RESET) ๐Ÿ›œ" down: @docker-compose -f docker-compose.yml down @@ -51,7 +51,7 @@ stop: start: @echo "$(FG_GREEN)Started$(RESET)" @docker-compose -f docker-compose.yml start - @echo "$(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)http://localhost$(RESET)" + @echo "$(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)http://localhost:80$(RESET)" re: @echo "$(FG_GREEN)Restarted$(RESET)" @@ -70,6 +70,7 @@ clean: fclean: @$(MAKE) down @docker system prune -af --volumes + @docker volume rm transcendence_db_data @echo "๐Ÿงน $(FG_BLUE)Fully cleaned up$(RESET) ๐Ÿงน" .PHONY: all build up down stop start re log clean fclean diff --git a/backend/Dockerfile b/backend/Dockerfile index fce60ef..d42c73a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y \ WORKDIR /app -COPY ./django/ . +COPY . . RUN chmod -R 755 /app CMD ["sh", "docker-run-server.sh"] diff --git a/backend/django/ansanking/urls.py b/backend/django/ansanking/urls.py deleted file mode 100644 index 66c01e7..0000000 --- a/backend/django/ansanking/urls.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.urls import path -from .views import ansan_king - -urlpatterns = [ - path('ansan-king/', ansan_king, name='ansan-king'), -] diff --git a/backend/django/ansanking/views.py b/backend/django/ansanking/views.py deleted file mode 100644 index f613eed..0000000 --- a/backend/django/ansanking/views.py +++ /dev/null @@ -1,7 +0,0 @@ -from rest_framework.decorators import api_view -from rest_framework.response import Response - -@api_view(['GET']) -def ansan_king(request): - data = {"message": "AnsanKing!!"} - return Response(data) diff --git a/backend/django/docker-run-server.sh b/backend/django/docker-run-server.sh deleted file mode 100644 index c1de956..0000000 --- a/backend/django/docker-run-server.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -pip install --upgrade pip - -if [ -f "requirements.txt" ]; then - pip install -r requirements.txt - echo "Installed packages from requirements.txt." -else - echo "requirements.txt not found." -fi - -echo "Applying migrations..." -python manage.py makemigrations -python manage.py migrate - -# Create a superuser -echo "Creating superuser..." -DJANGO_SUPERUSER_USERNAME=$DJANGO_SUPERUSER_USERNAME -DJANGO_SUPERUSER_PASSWORD=$DJANGO_SUPERUSER_PASSWORD -DJANGO_SUPERUSER_EMAIL=$DJANGO_SUPERUSER_EMAIL - -python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true - -echo "Starting development server..." -python manage.py runserver 0.0.0.0:8000 diff --git a/backend/docker-run-server.sh b/backend/docker-run-server.sh new file mode 100644 index 0000000..86099c5 --- /dev/null +++ b/backend/docker-run-server.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +pip install --upgrade pip + +if [ -f "requirements.txt" ]; then + cnt=$(pip freeze | grep -f requirements.txt | wc -l) + if [ $cnt -lt $(cat requirements.txt | wc -l) ]; then + pip install -r requirements.txt + echo "Installed packages from requirements.txt." + else + echo "Packages from requirements.txt are already installed." + fi +else + echo "requirements.txt not found." + exit 1 +fi + +echo "Applying migrations..." +python manage.py makemigrations +python manage.py migrate + +# Create a superuser +DJANGO_SUPERUSER_USERNAME=$DJANGO_SUPERUSER_USERNAME +DJANGO_SUPERUSER_PASSWORD=$DJANGO_SUPERUSER_PASSWORD +DJANGO_SUPERUSER_EMAIL=$DJANGO_SUPERUSER_EMAIL + +USER_EXISTS=$(python manage.py shell -c " +from django.contrib.auth import get_user_model; +User = get_user_model(); +print(User.objects.filter(username='admin').exists()) +") + +echo "USER_EXISTS: $USER_EXISTS" + +if [ "$USER_EXISTS" = "False" ]; then + echo "Creating superuser..." + python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +fi + +echo "Starting development server..." +python manage.py runserver 0.0.0.0:8000 diff --git a/backend/django/ansanking/__init__.py b/backend/login/__init__.py similarity index 100% rename from backend/django/ansanking/__init__.py rename to backend/login/__init__.py diff --git a/backend/django/ansanking/admin.py b/backend/login/admin.py similarity index 100% rename from backend/django/ansanking/admin.py rename to backend/login/admin.py diff --git a/backend/django/ansanking/apps.py b/backend/login/apps.py similarity index 62% rename from backend/django/ansanking/apps.py rename to backend/login/apps.py index 0a5a67c..ebd58e7 100644 --- a/backend/django/ansanking/apps.py +++ b/backend/login/apps.py @@ -1,6 +1,6 @@ from django.apps import AppConfig -class AnsankingConfig(AppConfig): +class LoginConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'ansanking' + name = 'login' diff --git a/backend/django/ansanking/migrations/__init__.py b/backend/login/migrations/__init__.py similarity index 100% rename from backend/django/ansanking/migrations/__init__.py rename to backend/login/migrations/__init__.py diff --git a/backend/django/ansanking/models.py b/backend/login/models.py similarity index 100% rename from backend/django/ansanking/models.py rename to backend/login/models.py diff --git a/backend/django/ansanking/tests.py b/backend/login/tests.py similarity index 100% rename from backend/django/ansanking/tests.py rename to backend/login/tests.py diff --git a/backend/login/urls.py b/backend/login/urls.py new file mode 100644 index 0000000..9e708a9 --- /dev/null +++ b/backend/login/urls.py @@ -0,0 +1,12 @@ +from django.urls import path +from .views import ( + login, + callback, + validate_token +) + +urlpatterns = [ + path('login/', login), + path('callback/', callback), + path('validate/', validate_token), +] diff --git a/backend/login/views.py b/backend/login/views.py new file mode 100644 index 0000000..35549da --- /dev/null +++ b/backend/login/views.py @@ -0,0 +1,107 @@ +from django.shortcuts import redirect +from django.views.decorators.csrf import csrf_exempt +from django.middleware.csrf import get_token +from django.http import JsonResponse +from django.conf import settings +from users.models import User +from rest_framework.decorators import api_view +from datetime import datetime, timedelta +import requests +import jwt +import os + + +@api_view(["GET"]) +def login(request): + oauth_url = "https://api.intra.42.fr/oauth/authorize" + redirect_uri = "http://localhost:8000/api/callback/" + client_id = os.getenv("OAUTH_CLIENT_ID") + state = os.getenv("OAUTH_STATE") # CSRF ๋ฐฉ์ง€์šฉ ๋žœ๋ค ๋ฌธ์ž์—ด + return redirect(f"{oauth_url}?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}") + + +@api_view(["GET"]) +def callback(request): + code = request.GET.get("code") + if not code: + return redirect("http://localhost:5173") + + token_url = "https://api.intra.42.fr/oauth/token" + redirect_uri = "http://localhost:8000/api/callback/" + client_id = os.getenv("OAUTH_CLIENT_ID") + client_secret = os.getenv("OAUTH_CLIENT_SECRET") + + data = { + "grant_type": "authorization_code", + "code": code, + "client_id": client_id, + "client_secret": client_secret, + "redirect_uri": redirect_uri, + } + + + response = requests.post(token_url, data=data) + if response.status_code != 200: + return redirect("http://localhost:5173") + + token_data = response.json() + access_token = token_data.get("access_token") + + # Access Token์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ + user_info = requests.get("https://api.intra.42.fr/v2/me", headers={"Authorization": f"Bearer {access_token}"}) + if user_info.status_code != 200: + return redirect("http://localhost:5173") + + user_data = user_info.json() + + # ์‚ฌ์šฉ์ž ์ •๋ณด ์ฒ˜๋ฆฌ (์˜ˆ: DB ์ €์žฅ) + nickname = user_data.get("login") # 42 API์—์„œ ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ด๋ฆ„ + email = user_data.get("email") # 42 API์—์„œ ์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ + img_url = user_data.get("image", {}).get("link") # 42 API์—์„œ ์‚ฌ์šฉ์ž ์ด๋ฏธ์ง€ URL + is_2FA = user_data.get("is_2fa", False) # 2FA ์—ฌ๋ถ€ + is_online = False # ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์„ค์ • (์˜จ๋ผ์ธ ์ƒํƒœ๋Š” API์—์„œ ์ œ๊ณตํ•˜์ง€ ์•Š์Œ) + + # ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ ๋˜๋Š” ์—…๋ฐ์ดํŠธ + user, created = User.objects.update_or_create( + nickname=nickname, defaults={ + "email": email, + "img_url": img_url, + "is_2FA": is_2FA, + "is_online": is_online} + ) + + # ์ƒ์„ฑ๋œ ๊ฒฝ์šฐ, ์ถ”๊ฐ€ ๋กœ์ง (์˜ˆ: ํ™˜์˜ ๋ฉ”์‹œ์ง€ ๋“ฑ) + if created: + print(f"์ƒˆ ์‚ฌ์šฉ์ž ์ƒ์„ฑ: {nickname}") + else: + print(f"๊ธฐ์กด ์‚ฌ์šฉ์ž ์—…๋ฐ์ดํŠธ: {nickname}") + + # JWT ํ† ํฐ ์ƒ์„ฑ + payload = { + "id": user.user_id, + "nickname": user.nickname, + "exp": datetime.utcnow() + timedelta(hours=24), # ํ† ํฐ ์œ ํšจ ์‹œ๊ฐ„ ์„ค์ • + } + token = jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256") + + response = redirect("http://localhost:5173") + response.set_cookie("jwt", token, httponly=True, secure=True, samesite='Lax') + + return response + +@csrf_exempt +def validate_token(request): + # CSRF ํ† ํฐ ๋ฐœ๊ธ‰ + get_token(request) + + token = request.COOKIES.get('jwt') + if not token: + return JsonResponse({"isValid": False}) + + try: + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) + return JsonResponse({"isValid": True, "user": payload}) + except jwt.ExpiredSignatureError: + return JsonResponse({"isValid": False, "error": "Token has expired"}) + except jwt.InvalidTokenError: + return JsonResponse({"isValid": False, "error": "Invalid token"}) diff --git a/backend/django/manage.py b/backend/manage.py similarity index 100% rename from backend/django/manage.py rename to backend/manage.py diff --git a/backend/django/requirements.txt b/backend/requirements.txt similarity index 67% rename from backend/django/requirements.txt rename to backend/requirements.txt index 683f125..7c3ef6d 100644 --- a/backend/django/requirements.txt +++ b/backend/requirements.txt @@ -1,15 +1,22 @@ asgiref==3.8.1 +certifi==2024.7.4 +charset-normalizer==3.3.2 Django==4.2.14 django-cors-headers==4.4.0 djangorestframework==3.15.2 +djangorestframework-simplejwt==5.3.1 drf-yasg==1.21.7 +idna==3.7 inflection==0.5.1 packaging==24.1 psycopg2-binary==2.9.9 +PyJWT==2.9.0 python-dotenv==1.0.1 pytz==2024.1 PyYAML==6.0.1 +requests==2.31.0 setuptools==71.1.0 sqlparse==0.5.1 typing_extensions==4.12.2 uritemplate==4.1.1 +urllib3==2.2.2 diff --git a/backend/django/run-server.sh b/backend/run-server.sh similarity index 62% rename from backend/django/run-server.sh rename to backend/run-server.sh index 0bffca7..26765a1 100755 --- a/backend/django/run-server.sh +++ b/backend/run-server.sh @@ -6,13 +6,9 @@ DOT_ENV_FILE=".env" # ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์˜ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ cd "$(dirname "$0")" -if [ -f "$DOT_ENV_FILE" ]; then - echo "$DOT_ENV_FILE already exists." -else - cp ../../$DOT_ENV_FILE . +cp ../$DOT_ENV_FILE . echo "Copied $DOT_ENV_FILE." sed -i '' 's/^DB_HOST=.*$/DB_HOST=localhost/' .env -fi # TEST: .env ํŒŒ์ผ์˜ ๋ณ€์ˆ˜๋“ค์„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์„ค์ • (์Šˆํผ ์œ ์ €๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”) if [ -f "$DOT_ENV_FILE" ]; then @@ -20,10 +16,9 @@ if [ -f "$DOT_ENV_FILE" ]; then echo "Exported .env variables to environment." else echo ".env file not found." + exit 1 fi -rm $DOT_ENV_FILE - if [ ! -d "$ENV_DIR" ]; then python3 -m venv $ENV_DIR echo "Virtual environment created at $ENV_DIR." @@ -37,10 +32,16 @@ source $ENV_DIR/bin/activate echo "Virtual environment activated." if [ -f "requirements.txt" ]; then - pip install -r requirements.txt - echo "Installed packages from requirements.txt." + cnt=$(pip freeze | grep -f requirements.txt | wc -l) + if [ $cnt -lt $(cat requirements.txt | wc -l) ]; then + pip install -r requirements.txt + echo "Installed packages from requirements.txt." + else + echo "Packages from requirements.txt are already installed." + fi else echo "requirements.txt not found." + exit 1 fi echo "Applying migrations..." @@ -48,12 +49,22 @@ python manage.py makemigrations python manage.py migrate # Create a superuser -echo "Creating superuser..." DJANGO_SUPERUSER_USERNAME=$DJANGO_SUPERUSER_USERNAME DJANGO_SUPERUSER_PASSWORD=$DJANGO_SUPERUSER_PASSWORD DJANGO_SUPERUSER_EMAIL=$DJANGO_SUPERUSER_EMAIL -python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +USER_EXISTS=$(python manage.py shell -c " +from django.contrib.auth import get_user_model; +User = get_user_model(); +print(User.objects.filter(username='admin').exists()) +") + +if [ "$USER_EXISTS" = "False" ]; then + echo "Creating superuser..." + python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +fi echo "Starting development server..." +clear + python manage.py runserver localhost:8000 diff --git a/backend/django/transcendence/__init__.py b/backend/transcendence/__init__.py similarity index 100% rename from backend/django/transcendence/__init__.py rename to backend/transcendence/__init__.py diff --git a/backend/django/transcendence/asgi.py b/backend/transcendence/asgi.py similarity index 100% rename from backend/django/transcendence/asgi.py rename to backend/transcendence/asgi.py diff --git a/backend/django/transcendence/settings.py b/backend/transcendence/settings.py similarity index 87% rename from backend/django/transcendence/settings.py rename to backend/transcendence/settings.py index 6ac1166..ba70d33 100644 --- a/backend/django/transcendence/settings.py +++ b/backend/transcendence/settings.py @@ -1,27 +1,18 @@ -""" -Django settings for transcendence project. - -Generated by 'django-admin startproject' using Django 4.2.14. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.2/ref/settings/ -""" - from pathlib import Path import os +# TEST: ๋กœ์ปฌ์—์„œ ํ…Œ์ŠคํŠธํ•  ๋•Œ ์‚ฌ์šฉ, docker-compose ์ด์šฉ ์‹œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์•Œ์•„์„œ ์„ค์ •๋จ +from dotenv import load_dotenv + +load_dotenv() # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-0s%66@!5og-abujy%dd)7og^4xxnmd(2wggfpv)exue6f-p1&w' +SECRET_KEY = os.getenv('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -41,10 +32,17 @@ 'rest_framework', "corsheaders", 'drf_yasg', - 'ansanking', - "users", + 'rest_framework_simplejwt', + "users.apps.UsersConfig", + "login.apps.LoginConfig", ] +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ) +} + MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', @@ -59,6 +57,10 @@ CORS_ORIGIN_ALLOW_ALL = True # TEST: ๋ชจ๋“  ๋„๋ฉ”์ธ ํ—ˆ์šฉ (๋ณด์•ˆ ์ทจ์•ฝ) +CSRF_TRUSTED_ORIGINS = [ + "http://localhost:5173", +] + CORS_ALLOWED_ORIGINS = [ "http://localhost:5173", ] @@ -70,6 +72,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', + # feature01-42OAuth_Login ์—์„œ ์ถ”๊ฐ€๋จ ์›๋ž˜ [] ๋กœ ๋น„์–ด์žˆ์—ˆ์Œ 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { @@ -89,10 +92,6 @@ # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases -# TEST: ๋กœ์ปฌ์—์„œ ํ…Œ์ŠคํŠธํ•  ๋•Œ ์‚ฌ์šฉ -from dotenv import load_dotenv -load_dotenv() - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', diff --git a/backend/django/transcendence/urls.py b/backend/transcendence/urls.py similarity index 52% rename from backend/django/transcendence/urls.py rename to backend/transcendence/urls.py index f262c11..46e1346 100644 --- a/backend/django/transcendence/urls.py +++ b/backend/transcendence/urls.py @@ -1,31 +1,12 @@ -""" -URL configuration for transcendence project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/4.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" from django.contrib import admin -from django.urls import path, re_path +from django.urls import path, re_path, include +from django.http import HttpResponse from rest_framework import permissions from drf_yasg.views import get_schema_view from drf_yasg import openapi -from django.urls import include -from django.http import HttpResponse -from users import views -# ํ™ˆ ํŽ˜์ด์ง€ ๋ทฐ ํ•จ์ˆ˜ ์ถ”๊ฐ€ -def home(request): - return HttpResponse("Hello, world!") +def index(request): + return HttpResponse("It works!") # Swagger ์„ค์ • schema_view = get_schema_view( @@ -43,11 +24,11 @@ def home(request): # URL ํŒจํ„ด ์„ค์ • urlpatterns = [ + path('', index), path('admin/', admin.site.urls), - path('', home, name='home'), - path('api/', include('ansanking.urls')), re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), path('api/', include('users.urls')), + path('api/', include('login.urls')), ] diff --git a/backend/django/transcendence/wsgi.py b/backend/transcendence/wsgi.py similarity index 100% rename from backend/django/transcendence/wsgi.py rename to backend/transcendence/wsgi.py diff --git a/backend/django/users/__init__.py b/backend/users/__init__.py similarity index 100% rename from backend/django/users/__init__.py rename to backend/users/__init__.py diff --git a/backend/django/users/admin.py b/backend/users/admin.py similarity index 100% rename from backend/django/users/admin.py rename to backend/users/admin.py diff --git a/backend/django/users/apps.py b/backend/users/apps.py similarity index 100% rename from backend/django/users/apps.py rename to backend/users/apps.py diff --git a/backend/django/users/migrations/0001_initial.py b/backend/users/migrations/0001_initial.py similarity index 96% rename from backend/django/users/migrations/0001_initial.py rename to backend/users/migrations/0001_initial.py index 32e3aae..46f36f5 100644 --- a/backend/django/users/migrations/0001_initial.py +++ b/backend/users/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.14 on 2024-07-28 11:28 +# Generated by Django 4.2.14 on 2024-08-04 18:19 from django.db import migrations, models import django.db.models.deletion @@ -28,6 +28,7 @@ class Migration(migrations.Migration): fields=[ ('user_id', models.AutoField(primary_key=True, serialize=False)), ('nickname', models.CharField(max_length=255)), + ('email', models.EmailField(max_length=255)), ('img_url', models.URLField(blank=True)), ('is_2FA', models.BooleanField(default=False)), ('is_online', models.BooleanField(default=False)), diff --git a/backend/django/users/migrations/__init__.py b/backend/users/migrations/__init__.py similarity index 100% rename from backend/django/users/migrations/__init__.py rename to backend/users/migrations/__init__.py diff --git a/backend/django/users/models.py b/backend/users/models.py similarity index 97% rename from backend/django/users/models.py rename to backend/users/models.py index 360175e..424a631 100644 --- a/backend/django/users/models.py +++ b/backend/users/models.py @@ -4,6 +4,7 @@ class User(models.Model): user_id = models.AutoField(primary_key=True) nickname = models.CharField(max_length=255) + email = models.EmailField(max_length=255) img_url = models.URLField(blank=True) is_2FA = models.BooleanField(default=False) is_online = models.BooleanField(default=False) diff --git a/backend/django/users/serializers.py b/backend/users/serializers.py similarity index 100% rename from backend/django/users/serializers.py rename to backend/users/serializers.py diff --git a/backend/django/users/tests.py b/backend/users/tests.py similarity index 100% rename from backend/django/users/tests.py rename to backend/users/tests.py diff --git a/backend/django/users/urls.py b/backend/users/urls.py similarity index 100% rename from backend/django/users/urls.py rename to backend/users/urls.py diff --git a/backend/django/users/views.py b/backend/users/views.py similarity index 100% rename from backend/django/users/views.py rename to backend/users/views.py diff --git a/clear_db.sh b/clear_db.sh new file mode 100755 index 0000000..201bbcd --- /dev/null +++ b/clear_db.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +docker rm -f postgres && docker volume rm db_data diff --git a/docker-compose.yml b/docker-compose.yml index 590e64e..db7b017 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,6 +35,10 @@ services: - DB_PASSWORD=${DB_PASSWORD} - DB_HOST=${DB_HOST} - DB_PORT=${DB_PORT} + - SECRET_KEY=${SECRET_KEY} + - DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME} + - DJANGO_SUPERUSER_EMAIL=${DJANGO_SUPERUSER_EMAIL} + - DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD} restart: on-failure # TEST: ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ํฌํŠธ๋ฅผ ์—ด์–ด๋‘  ports: diff --git a/frontend/vite/.gitignore b/frontend/.gitignore similarity index 100% rename from frontend/vite/.gitignore rename to frontend/.gitignore diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 491657f..0470861 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -4,7 +4,7 @@ FROM node:22.5-alpine3.19 WORKDIR /app # 3. package.json ๋ฐ package-lock.json์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. -COPY vite/package*.json ./ +COPY package*.json ./ # 4. ์˜์กด์„ฑ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. RUN npm install && \ @@ -12,7 +12,7 @@ RUN npm install && \ apk add --no-cache curl # 5. ๋‚˜๋จธ์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์†Œ์Šค๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. -COPY vite/ . +COPY . . # 6. Vite ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. CMD ["npm", "run", "dev"] diff --git a/frontend/vite/index.html b/frontend/index.html similarity index 100% rename from frontend/vite/index.html rename to frontend/index.html diff --git a/frontend/vite/package-lock.json b/frontend/package-lock.json similarity index 100% rename from frontend/vite/package-lock.json rename to frontend/package-lock.json diff --git a/frontend/vite/package.json b/frontend/package.json similarity index 100% rename from frontend/vite/package.json rename to frontend/package.json diff --git a/frontend/vite/src/app.js b/frontend/src/app.js similarity index 100% rename from frontend/vite/src/app.js rename to frontend/src/app.js diff --git a/frontend/vite/src/components/AddCal.js b/frontend/src/components/AddCal.js similarity index 100% rename from frontend/vite/src/components/AddCal.js rename to frontend/src/components/AddCal.js diff --git a/frontend/vite/src/components/Default.js b/frontend/src/components/Default.js similarity index 100% rename from frontend/vite/src/components/Default.js rename to frontend/src/components/Default.js diff --git a/frontend/vite/src/components/Friends-Info.js b/frontend/src/components/Friends-Info.js similarity index 100% rename from frontend/vite/src/components/Friends-Info.js rename to frontend/src/components/Friends-Info.js diff --git a/frontend/vite/src/components/Friends.js b/frontend/src/components/Friends.js similarity index 100% rename from frontend/vite/src/components/Friends.js rename to frontend/src/components/Friends.js diff --git a/frontend/src/components/Home-Login.js b/frontend/src/components/Home-Login.js new file mode 100644 index 0000000..662d885 --- /dev/null +++ b/frontend/src/components/Home-Login.js @@ -0,0 +1,41 @@ +import { Component } from "../core/Component.js"; +import { changeUrl } from "../core/router.js"; + +export class Login extends Component { + + template () { + return ` +
+

LOGIN

+
+ `; + } + + setEvent () { + this.addEvent('click', '#login', () => { + // ๋กœ๊ทธ์ธ ์š”์ฒญ + window.location.href = 'http://localhost:8000/api/login'; + }); + + // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์š”์ฒญ + this.checkAuth(); + } + + checkAuth() { + fetch('http://localhost:8000/api/validate', { + method: 'GET', + credentials: 'include', // ์ฟ ํ‚ค๋ฅผ ํฌํ•จํ•˜์—ฌ ์š”์ฒญ + }) + .then(response => response.json()) + .then(data => { + if (data.isValid) { + changeUrl('/main'); + } else { + console.error('Authentication failed'); + } + }) + .catch(error => { + console.error('Error:', error); + }); + } +} diff --git a/frontend/vite/src/components/Home.js b/frontend/src/components/Home.js similarity index 100% rename from frontend/vite/src/components/Home.js rename to frontend/src/components/Home.js diff --git a/frontend/vite/src/components/List.js b/frontend/src/components/List.js similarity index 100% rename from frontend/vite/src/components/List.js rename to frontend/src/components/List.js diff --git a/frontend/vite/src/components/Main-Menu.js b/frontend/src/components/Main-Menu.js similarity index 100% rename from frontend/vite/src/components/Main-Menu.js rename to frontend/src/components/Main-Menu.js diff --git a/frontend/vite/src/components/Main.js b/frontend/src/components/Main.js similarity index 100% rename from frontend/vite/src/components/Main.js rename to frontend/src/components/Main.js diff --git a/frontend/vite/src/core/Component.js b/frontend/src/core/Component.js similarity index 100% rename from frontend/vite/src/core/Component.js rename to frontend/src/core/Component.js diff --git a/frontend/vite/src/core/observer.js b/frontend/src/core/observer.js similarity index 100% rename from frontend/vite/src/core/observer.js rename to frontend/src/core/observer.js diff --git a/frontend/vite/src/core/router.js b/frontend/src/core/router.js similarity index 100% rename from frontend/vite/src/core/router.js rename to frontend/src/core/router.js diff --git a/frontend/vite/style.css b/frontend/style.css similarity index 100% rename from frontend/vite/style.css rename to frontend/style.css diff --git a/frontend/vite/vite.config.js b/frontend/vite.config.js similarity index 86% rename from frontend/vite/vite.config.js rename to frontend/vite.config.js index 05ec39f..8e33216 100644 --- a/frontend/vite/vite.config.js +++ b/frontend/vite.config.js @@ -9,7 +9,6 @@ export default defineConfig({ // TEST: ํ‰๊ฐ€ ์‹œ 80๋ฒˆ ํฌํŠธ๋กœ ๋ณ€๊ฒฝ (nginx๋ฅผ ๊ฑฐ์ณ api๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก) target: "http://localhost:8000", changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ""), }, }, }, diff --git a/frontend/vite/src/components/Home-Login.js b/frontend/vite/src/components/Home-Login.js deleted file mode 100644 index 719d117..0000000 --- a/frontend/vite/src/components/Home-Login.js +++ /dev/null @@ -1,19 +0,0 @@ -import { Component } from "../core/Component.js"; -import { changeUrl } from "../core/router.js"; - -export class Login extends Component { - - template () { - return ` -
-

LOGIN

-
- `; - } - - setEvent () { - this.addEvent('click', '#login', () => { - changeUrl("/main"); - }); - } -} \ No newline at end of file diff --git a/run_backend.sh b/run_backend.sh index 2f860d6..73d46f7 100755 --- a/run_backend.sh +++ b/run_backend.sh @@ -2,8 +2,11 @@ # TEST: ๊ฐœ๋ฐœ ์‹œ ๋กœ์ปฌ ์‹คํ–‰์šฉ -docker volume create 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 +# Check if the container is not running +if [ -z "$(docker ps -q -f name=postgres)" ]; then + docker volume create 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 +fi -sh backend/django/run-server.sh +sh backend/run-server.sh diff --git a/run_frontend.sh b/run_frontend.sh index b0eb41f..38a6b06 100755 --- a/run_frontend.sh +++ b/run_frontend.sh @@ -1,9 +1,3 @@ #!/bin/bash - # TEST: ๊ฐœ๋ฐœ ์‹œ ๋กœ์ปฌ ์‹คํ–‰์šฉ - -cd frontend/vite - -npm install - -npm run dev +cd frontend && npm install && npm run dev