diff --git a/chess_backend/asgi.py b/chess_backend/asgi.py index a4c59e0..ed24f6e 100644 --- a/chess_backend/asgi.py +++ b/chess_backend/asgi.py @@ -10,7 +10,11 @@ https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ import os from django.core.asgi import get_asgi_application +from channels.routing import ProtocolTypeRouter os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chess_backend.settings') +django_asgi_app = get_asgi_application() -application = get_asgi_application() +application = ProtocolTypeRouter({ + "http": django_asgi_app, +}) diff --git a/chess_backend/settings.py b/chess_backend/settings.py index d60022a..f5b5ca9 100644 --- a/chess_backend/settings.py +++ b/chess_backend/settings.py @@ -19,7 +19,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-%_8sy196w4hzo9^cp9(@r=i+amh47r4mxfhq_(ok&=c(@%bhmk' +SECRET_KEY = "django-insecure-%_8sy196w4hzo9^cp9(@r=i+amh47r4mxfhq_(ok&=c(@%bhmk" TOKEN_EXP = 2678400 # 31 day # SECURITY WARNING: don't run with debug turned on in production! @@ -30,58 +30,56 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", # Packages "rest_framework", - + "channels", # Apps - "game" + "game", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'chess_backend.urls' +ROOT_URLCONF = "chess_backend.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [BASE_DIR / 'templates'] - , - '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', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "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 = 'chess_backend.wsgi.application' +ASGI_APPLICATION = 'chess_backend.asgi.application' +WSGI_APPLICATION = "chess_backend.wsgi.application" # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } @@ -90,25 +88,25 @@ DATABASES = { 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", }, ] # Internationalization # https://docs.djangoproject.com/en/4.0/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -127,4 +125,4 @@ else: # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/game/admin.py b/game/admin.py index 8c38f3f..b8635f5 100644 --- a/game/admin.py +++ b/game/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin # Register your models here. +from game.models import HeroImageSet + +admin.site.register(HeroImageSet) diff --git a/game/api/v1/serializers.py b/game/api/v1/serializers.py index 784ad93..7b2ef01 100644 --- a/game/api/v1/serializers.py +++ b/game/api/v1/serializers.py @@ -10,9 +10,6 @@ class CreateHeroSerializer(serializers.ModelSerializer): model = Hero fields = ( "type", - "idle_img", - "attack_img", - "die_img", "health", "attack", "speed", diff --git a/game/api/v1/views.py b/game/api/v1/views.py index d0cb1c0..f83cb59 100644 --- a/game/api/v1/views.py +++ b/game/api/v1/views.py @@ -51,10 +51,14 @@ class ListCreateHeroView(GenericAPIView, CreateModelMixin, ListModelMixin): class RetrieveHeroView(RetrieveModelMixin, UpdateAPIView, GenericAPIView): serializer_class = GetHeroSerializer - authentication_classes = (PlayerAuthentication,) lookup_field = "uuid" queryset = Hero.objects.all() + def get_authenticators(self): + if self.request.method != "GET": + self.authentication_classes = [PlayerAuthentication] + return [auth() for auth in self.authentication_classes] + def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) @@ -159,5 +163,7 @@ class RefreshAuthKey(GenericAPIView): def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - access_jwt = sign_jwt({"id": serializer.player_id, "type": "access"}, t_life=3600) + access_jwt = sign_jwt( + {"id": serializer.player_id, "type": "access"}, t_life=3600 + ) return Response({"access_token": access_jwt}, status=status.HTTP_200_OK) diff --git a/game/models.py b/game/models.py index 24379de..2633d17 100644 --- a/game/models.py +++ b/game/models.py @@ -13,7 +13,13 @@ from django.conf import settings from common.generators import generate_charset -HER0_TYPES = [("WIZARD", "wizard"), ("ARCHER", "archer"), ("WARRIOR", "warrior")] +HER0_TYPES = [ + ("WIZARD", "wizard"), + ("ARCHER", "archer"), + ("WARRIOR", "warrior"), + ("KING", "king"), +] +HER0_IMAGE_TYPES = [("DIE", "die"), ("IDLE", "idle"), ("ATTACK", "attack")] class Player(models.Model): @@ -36,30 +42,23 @@ class Player(models.Model): PlayerAuthSession.objects.create(player=self) deck = Deck.objects.create(player=self) types = ( - ["ARCHER" for _ in range(4)] + ["KING"] + + ["ARCHER" for _ in range(4)] + ["WARRIOR" for _ in range(6)] + ["WIZARD" for _ in range(2)] - + [random.choice(HER0_TYPES)[0] for _ in range(4)] + + [random.choice(HER0_TYPES[:3])[0] for _ in range(3)] ) for t in types: hero = Hero() hero.player = self hero.type = t - # TODO: create image pool to generate heroes (awaiting for designer) - with open( - "/home/sanspie/Projects/chess_rpg_backend/media/dummy.jpg", "rb+" - ) as file: - hero.idle_img = File(file, name="dummy.jpg") - hero.attack_img = File(file, name="dummy.jpg") - hero.die_img = File(file, name="dummy.jpg") + hero.health = random.randint(0, 10) + hero.attack = random.randint(0, 10) + hero.speed = random.randint(0, 10) - hero.health = random.randint(0, 10) - hero.attack = random.randint(0, 10) - hero.speed = random.randint(0, 10) - - hero.save() - HeroInDeck.objects.create(deck=deck, hero=hero) + hero.save() + HeroInDeck.objects.create(deck=deck, hero=hero) def get_last_deck(self): return Deck.objects.filter(player=self).last() @@ -94,9 +93,15 @@ class Hero(models.Model): added = models.DateTimeField(auto_now_add=True) type = models.CharField(blank=False, choices=HER0_TYPES, max_length=7) - idle_img = models.ImageField(upload_to="uploads/idle", blank=False) - attack_img = models.ImageField(upload_to="uploads/attack", blank=False) - die_img = models.ImageField(upload_to="uploads/die", blank=False) + idle_img_f = models.ForeignKey( + "HeroImageSet", on_delete=models.CASCADE, related_name="idle_image_fkey" + ) + attack_img_f = models.ForeignKey( + "HeroImageSet", on_delete=models.CASCADE, related_name="attack_image_fkey" + ) + die_img_f = models.ForeignKey( + "HeroImageSet", on_delete=models.CASCADE, related_name="die_image_fkey" + ) health = models.IntegerField( validators=[MinValueValidator(0), MaxValueValidator(10)], blank=False ) @@ -107,9 +112,32 @@ class Hero(models.Model): validators=[MinValueValidator(0), MaxValueValidator(10)], blank=False ) + def idle_img(self): + return self.idle_img_f.image.url + + def attack_img(self): + return self.attack_img_f.image.url + + def die_img(self): + return self.die_img_f.image.url + def __str__(self): return f"{self.type} {self.player.name}" + def save( + self, force_insert=False, force_update=False, using=None, update_fields=None + ): + self.idle_img_f = random.choice( + [x for x in HeroImageSet.objects.filter(hero_type=self.type, type="IDLE")] + ) + self.attack_img_f = random.choice( + [x for x in HeroImageSet.objects.filter(hero_type=self.type, type="ATTACK")] + ) + self.die_img_f = random.choice( + [x for x in HeroImageSet.objects.filter(hero_type=self.type, type="DIE")] + ) + super(Hero, self).save() + class Meta: indexes = [models.Index(fields=["uuid"])] ordering = ["-added"] @@ -119,6 +147,15 @@ class Hero(models.Model): verbose_name_plural = "heroes" +class HeroImageSet(models.Model): + type = models.CharField(max_length=10, choices=HER0_IMAGE_TYPES) + hero_type = models.CharField(blank=False, choices=HER0_TYPES, max_length=7) + image = models.ImageField(upload_to="uploads/") + + def __str__(self): + return f"{self.hero_type} {self.type} image" + + class Deck(models.Model): player = models.ForeignKey( Player, diff --git a/room/__init__.py b/room/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/room/admin.py b/room/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/room/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/room/apps.py b/room/apps.py new file mode 100644 index 0000000..38c33e7 --- /dev/null +++ b/room/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class RoomConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'room' diff --git a/room/migrations/__init__.py b/room/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/room/models.py b/room/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/room/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/room/tests.py b/room/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/room/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/room/views.py b/room/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/room/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.