diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..3047fd07 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.venv +docker-compose.yml +.idea +__pycache__ +*.pyc +*.pyo +.git +migration/ +*.md +tests/ +.github +*.log +.pytest_cache +staticfiles/ \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 00000000..a7b478e3 --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +POSTGRES_PASSWORD=cinema_service +POSTGRES_USER=cinema_service +POSTGRES_DB=cinema_service +POSTGRES_HOST=db +POSTGRES_PORT=5432 +PGDATA=/var/lib/postgresql/data \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..782203b6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.11.6-alpine3.18 +LABEL maintainer="yakovenkoanton2007@gmail.com" + +ENV PYTHONUNBUFFERED=1 + +WORKDIR app/ + +COPY requirements.txt requirements.txt + +RUN pip install -r requirements.txt + +COPY . . +RUN mkdir -p /files/media + +RUN adduser \ + --disabled-password \ + --no-create-home \ + my_user + +RUN chown -R my_user /files/media +RUN chmod 755 /files/media + +USER my_user \ No newline at end of file diff --git a/cinema/management/__init__.py b/cinema/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cinema/management/commands/__init__.py b/cinema/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cinema/management/commands/wait_for_db.py b/cinema/management/commands/wait_for_db.py new file mode 100644 index 00000000..2ef3a0b6 --- /dev/null +++ b/cinema/management/commands/wait_for_db.py @@ -0,0 +1,18 @@ +import time + +from django.core.management.base import BaseCommand +from django.db import connection, OperationalError + + +class Command(BaseCommand): + def handle(self, *args, **options): + self.stdout.write("Waiting for database...") + while True: + try: + with connection.cursor() as cursor: + cursor.execute("SELECT 1") + self.stdout.write(self.style.SUCCESS("Database available!")) + break + except OperationalError: + self.stdout.write("Database unavailable, waiting 2 seconds...") + time.sleep(2) diff --git a/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py b/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py new file mode 100644 index 00000000..438e3c71 --- /dev/null +++ b/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 5.2.14 on 2026-05-20 12:02 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cinema', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name='movie', + name='actors', + field=models.ManyToManyField(blank=True, related_name='movies', to='cinema.actor'), + ), + migrations.AlterField( + model_name='movie', + name='genres', + field=models.ManyToManyField(blank=True, related_name='movies', to='cinema.genre'), + ), + migrations.AlterField( + model_name='moviesession', + name='cinema_hall', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.cinemahall'), + ), + migrations.AlterField( + model_name='moviesession', + name='movie', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.movie'), + ), + migrations.AlterField( + model_name='order', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 90dde772..7591d567 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -9,6 +9,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ +import os from datetime import timedelta from pathlib import Path @@ -27,8 +28,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] - +ALLOWED_HOSTS = ["0.0.0.0", "localhost", "127.0.0.1"] INTERNAL_IPS = [ "127.0.0.1", ] @@ -81,13 +81,25 @@ WSGI_APPLICATION = "cinema_service.wsgi.application" -# Database +# Database SQLite # https://docs.djangoproject.com/en/4.0/ref/settings/#databases +# DATABASES = { +# "default": { +# "ENGINE": "django.db.backends.sqlite3", +# "NAME": BASE_DIR / "db.sqlite3", +# } +# } + +# Database PostgresSQL DATABASES = { "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ.get("POSTGRES_DB"), + "USER": os.environ.get("POSTGRES_USER"), + "PASSWORD": os.environ.get("POSTGRES_PASSWORD"), + "HOST": os.environ.get("POSTGRES_HOST"), + "PORT": os.environ.get("POSTGRES_PORT"), } } @@ -134,7 +146,7 @@ STATIC_URL = "static/" MEDIA_URL = "/media/" -MEDIA_ROOT = BASE_DIR / "media" +MEDIA_ROOT = "/files/media/" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field @@ -147,7 +159,7 @@ "rest_framework.throttling.AnonRateThrottle", "rest_framework.throttling.UserRateThrottle", ], - "DEFAULT_THROTTLE_RATES": {"anon": "10/day", "user": "30/day"}, + "DEFAULT_THROTTLE_RATES": {"anon": "10/day", "user": "1000/day"}, "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework_simplejwt.authentication.JWTAuthentication", ), @@ -167,7 +179,7 @@ } SIMPLE_JWT = { - "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), "ROTATE_REFRESH_TOKENS": False, } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..adb42de6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +services: + cinema_service: + build: + context: . + image: yakovenkoanton/cinema_service + env_file: + - .env + ports: + - "8000:8000" + volumes: + - ./:/app + - my_media:/files/media/ + command: > + sh -c "python manage.py wait_for_db && python manage.py migrate && python manage.py runserver 0.0.0.0:8000" + depends_on: + db: + condition: service_healthy + + db: + image: postgres:16.0-alpine3.17 + restart: always + env_file: + - .env + ports: + - "5433:5432" + volumes: + - my_db:$PGDATA + +volumes: + my_db: + my_media: \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2dc12c67..622155ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ djangorestframework djangorestframework-simplejwt drf-spectacular Pillow +psycopg2-binary