diff --git a/checker/api/__init__.py b/checker/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/checker/api/serializers.py b/checker/api/serializers.py new file mode 100644 index 0000000..69d410a --- /dev/null +++ b/checker/api/serializers.py @@ -0,0 +1,14 @@ +from django.core.files.uploadedfile import InMemoryUploadedFile +from rest_framework import serializers + +from checker.models import Docx + + +class DocxSerializer(serializers.ModelSerializer): + class Meta: + model = Docx + fields = ["uuid", "file"] + extra_kwargs = {"uuid": {"read_only": True}} + + def validate_file(self, file: InMemoryUploadedFile): + return file diff --git a/checker/api/views.py b/checker/api/views.py new file mode 100644 index 0000000..871e153 --- /dev/null +++ b/checker/api/views.py @@ -0,0 +1,11 @@ +from rest_framework import generics +from rest_framework.parsers import MultiPartParser, FormParser + +from checker.api.serializers import DocxSerializer +from checker.models import Docx + + +class ListCreateDocxApiView(generics.ListCreateAPIView): + parser_classes = [FormParser, MultiPartParser] + serializer_class = DocxSerializer + queryset = Docx.objects.all() diff --git a/checker/apps.py b/checker/apps.py index 8e67ea3..27f5685 100644 --- a/checker/apps.py +++ b/checker/apps.py @@ -4,3 +4,6 @@ from django.apps import AppConfig class CheckerConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "checker" + + def ready(self): + import checker.signals diff --git a/checker/migrations/0001_initial.py b/checker/migrations/0001_initial.py new file mode 100644 index 0000000..839e5bf --- /dev/null +++ b/checker/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 4.1 on 2022-08-26 14:23 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Docx", + fields=[ + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ("file", models.FileField(upload_to="")), + ], + ), + ] diff --git a/checker/models.py b/checker/models.py index 71a8362..49b0d5c 100644 --- a/checker/models.py +++ b/checker/models.py @@ -1,3 +1,11 @@ +import uuid as uuid from django.db import models # Create your models here. + + +class Docx(models.Model): + uuid = models.UUIDField( + default=uuid.uuid4, editable=False, unique=True, primary_key=True + ) + file = models.FileField(upload_to="") diff --git a/checker/services/__init__.py b/checker/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/checker/services/file.py b/checker/services/file.py new file mode 100644 index 0000000..e69de29 diff --git a/checker/services/validators.py b/checker/services/validators.py new file mode 100644 index 0000000..e69de29 diff --git a/checker/signals.py b/checker/signals.py new file mode 100644 index 0000000..2e72a0d --- /dev/null +++ b/checker/signals.py @@ -0,0 +1,12 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver + +from checker.models import Docx +from checker.tasks import process_file + + +@receiver(post_save, sender=Docx) +def create_player(sender, instance, created, **kwargs): + if created: + process_file.delay(file=instance) + return diff --git a/checker/tasks.py b/checker/tasks.py new file mode 100644 index 0000000..5dd864e --- /dev/null +++ b/checker/tasks.py @@ -0,0 +1,8 @@ +from celery import shared_task + +from checker.models import Docx + + +@shared_task +def process_file(file: Docx): + return diff --git a/checker/tests.py b/checker/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/checker/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/checker/views.py b/checker/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/checker/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/conf/__init__.py b/conf/__init__.py index e69de29..5568b6d 100644 --- a/conf/__init__.py +++ b/conf/__init__.py @@ -0,0 +1,5 @@ +# This will make sure the app is always imported when +# Django starts so that shared_task will use this app. +from .celery import app as celery_app + +__all__ = ("celery_app",) diff --git a/conf/api_router.py b/conf/api_router.py index 2012ebe..b6cdc86 100644 --- a/conf/api_router.py +++ b/conf/api_router.py @@ -1 +1,8 @@ -urlpatterns = [] \ No newline at end of file +from django.urls import path, include + +from checker.api.views import ListCreateDocxApiView + +urlpatterns = [ + path("health/", include("health_check.urls")), + path("docx/", ListCreateDocxApiView.as_view(), name="list_create_docx") +] diff --git a/conf/celery.py b/conf/celery.py new file mode 100644 index 0000000..4690ed2 --- /dev/null +++ b/conf/celery.py @@ -0,0 +1,23 @@ +import os + +from celery import Celery + +# Set the default Django settings module for the 'celery' program. +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "conf.settings.local") + +app = Celery("mistake_checker_hack_backend") + +# Using a string here means the worker doesn't have to serialize +# the configuration object to child processes. +# - namespace='CELERY' means all celery-related configuration keys +# should have a `CELERY_` prefix. +app.config_from_object("django.conf:settings", namespace="CELERY") + +# Load task modules from all registered Django apps. +app.autodiscover_tasks() + + +# TODO REMOVE THIS +@app.task(bind=True) +def debug_task(self): + print(f"Request: {self.request!r}") diff --git a/conf/settings/base.py b/conf/settings/base.py index c743296..3172e49 100644 --- a/conf/settings/base.py +++ b/conf/settings/base.py @@ -61,6 +61,7 @@ THIRD_PARTY_APPS = [ "rest_framework", "drf_yasg", "corsheaders", + "django_celery_results" ] HEALTH_CHECKS = [ @@ -188,8 +189,14 @@ REST_FRAMEWORK = { "rest_framework_simplejwt.authentication.JWTAuthentication", ), "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), - "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", } # django-cors-headers CORS_ALLOW_ALL_ORIGINS = True + + +# Celery +CELERY_BROKER_URL = 'redis://localhost:6379/0' +CELERY_TIMEZONE = "Europe/Moscow" +CELERY_TASK_TRACK_STARTED = True +CELERY_TASK_TIME_LIMIT = 30 * 60 diff --git a/conf/settings/local.py b/conf/settings/local.py index 4ebf6cf..ef8738b 100644 --- a/conf/settings/local.py +++ b/conf/settings/local.py @@ -51,7 +51,6 @@ REST_FRAMEWORK = { "rest_framework_simplejwt.authentication.JWTAuthentication", ), "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.AllowAny",), - "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", } # STATIC diff --git a/docker-compose.yml b/docker-compose.yml index cd3c52f..902dc26 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,4 +12,9 @@ services: ports: - "5432:5432" - network_mode: "host" \ No newline at end of file + network_mode: "host" + + redis: + image: "redis:alpine" + ports: + - "6379:6379" \ No newline at end of file diff --git a/requirements/base.txt b/requirements/base.txt index b401351..6258319 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,5 +7,11 @@ djangorestframework-simplejwt==5.2.0 django-health-check==3.16.5 django-cors-headers==3.13.0 drf-yasg==1.21.3 +celery==5.2.7 +Redis==4.3.4 +django_celery_results==2.4.0 + psutil -dj-database-url \ No newline at end of file +dj-database-url +uuid +python-docx \ No newline at end of file