From 27bab78aa05d046d39bdaf51c0ca225c23effde1 Mon Sep 17 00:00:00 2001 From: dmytro Date: Sun, 5 Jan 2025 18:35:14 +0200 Subject: [PATCH] feat: dockerize project --- .github/workflows/test.yml | 23 +++++++++++++++-------- book/permissions.py | 5 +++++ borrowing/signals.py | 13 +++++++++++++ borrowing/tasks.py | 17 +++++++++++++++++ borrowing/views.py | 4 +--- compose.yaml | 33 +++++++++++++++++++++++++++++++++ core/settings.py | 10 ++++++++-- core/urls.py | 2 +- 8 files changed, 93 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ba3b49..b16f96a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 + services: + redis: + image: redis:7 + ports: + - 6379:6379 + + steps: - name: Checkout repo uses: actions/checkout@v3 @@ -33,11 +40,11 @@ jobs: - name: make run: poetry run ruff check --output-format=github . -# - name: Run Tests -# env: -# SECRET_KEY: "j+(#!sag4%^ay+oanu&t-&3x@2$!+s%x4u!4%pser4o9)2!ua1" -# ENVIRONMENT: "local" -# STRIPE_SECRET_KEY: "fail" -# STRIPE_PUBLIC_KEY: "fail" -# timeout-minutes: 5 -# run: poetry run python manage.py test + - name: Run Tests + env: + SECRET_KEY: "j+(#!sag4%^ay+oanu&t-&3x@2$!+s%x4u!4%pser4o9)2!ua1" + ENVIRONMENT: "local" + STRIPE_SECRET_KEY: "fail" + STRIPE_PUBLIC_KEY: "fail" + timeout-minutes: 5 + run: poetry run python manage.py test diff --git a/book/permissions.py b/book/permissions.py index cb036f8..fb7876f 100644 --- a/book/permissions.py +++ b/book/permissions.py @@ -2,6 +2,11 @@ class IsAdminOrReadOnly(BasePermission): + """ + Custom permission to allow only admin users to modify data, + while read-only access is granted to all users. + """ + def has_permission(self, request, view): if request.method in SAFE_METHODS: return True diff --git a/borrowing/signals.py b/borrowing/signals.py index 98ca6af..4d13d92 100644 --- a/borrowing/signals.py +++ b/borrowing/signals.py @@ -6,6 +6,19 @@ @receiver(post_save, sender=Borrowing) def handle_borrowing_creation(instance, created, **kwargs): + """ + Signal handler to send a notification when a new Borrowing instance is created. + + This function listens for the post_save signal of the Borrowing model. If a new + borrowing record is created, it sends a Telegram notification with the book title + and expected return date. + + Args: + instance (Borrowing): The instance of Borrowing that was saved. + created (bool): Indicates if the instance was created (True) or updated (False). + **kwargs: Additional keyword arguments. + + """ if created: message = ( f"New borrowing for book: {instance.book.title}, " diff --git a/borrowing/tasks.py b/borrowing/tasks.py index d31e992..8dcca31 100644 --- a/borrowing/tasks.py +++ b/borrowing/tasks.py @@ -8,6 +8,23 @@ @shared_task def send_message(): + """ + Celery task to send reminders for overdue borrowings. + + This task checks for borrowings that are overdue (expected return date has passed) + and have not yet been returned. For each overdue borrowing, it sends a Telegram + notification to remind the user. + + The notification includes details such as the user's name, book title, borrow date, + and the number of days the borrowing is overdue. + + Args: + None + + Returns: + None + """ + today = datetime.date.today() overdue_borrowings = Borrowing.objects.filter( expected_return_date__lte=today, diff --git a/borrowing/views.py b/borrowing/views.py index d2a1922..e822f1d 100644 --- a/borrowing/views.py +++ b/borrowing/views.py @@ -113,9 +113,7 @@ def return_book(self, request, pk=None): "/api/borrowings/", status=status.HTTP_302_FOUND ) - payment = Payment.objects.filter(type="FINE", borrowing=borrowing)[ - 0 - ] + payment = Payment.objects.filter(type="FINE", borrowing=borrowing)[0] return HttpResponseRedirect( payment.session_url, status=status.HTTP_302_FOUND diff --git a/compose.yaml b/compose.yaml index 9c594b9..0deeebe 100644 --- a/compose.yaml +++ b/compose.yaml @@ -10,6 +10,7 @@ services: - ENVIRONMENT=docker depends_on: - db + - redis command: > sh -c "python manage.py wait_for_db && python manage.py migrate && @@ -25,5 +26,37 @@ services: volumes: - my_db:/var/lib/postgresql/data + redis: + image: redis:7 + restart: always + ports: + - "6379:6379" + + celery-worker: + build: + context: . + depends_on: + - redis + - library + env_file: + - .env + environment: + - ENVIRONMENT=docker + command: > + sh -c "celery -A core worker --loglevel=info --pool=solo" + + celery-beat: + build: + context: . + depends_on: + - redis + - library + env_file: + - .env + environment: + - ENVIRONMENT=docker + command: > + sh -c "python manage.py migrate django_celery_beat && celery -A core beat --loglevel=info" + volumes: my_db: diff --git a/core/settings.py b/core/settings.py index 0f351d4..ddfeb4a 100644 --- a/core/settings.py +++ b/core/settings.py @@ -185,11 +185,17 @@ # Celery settings -CELERY_BROKER_URL = "redis://localhost:6379/0" +if os.environ.get("ENVIRONMENT") == "local": + CELERY_BROKER_URL = "redis://localhost:6379/0" + CELERY_RESULT_BACKEND = "redis://localhost:6379/0" +else: + CELERY_BROKER_URL = "redis://redis:6379/0" + CELERY_RESULT_BACKEND = "redis://redis:6379/0" + CELERY_ACCEPT_CONTENT = ["json"] CELERY_TASK_SERIALIZER = "json" -CELERY_RESULT_BACKEND = "redis://localhost:6379/0" CELERY_TIMEZONE = "Europe/Kiev" +CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler" CELERY_BEAT_SCHEDULE = { "send_message_daily": { diff --git a/core/urls.py b/core/urls.py index c6dafb6..a2c46f6 100644 --- a/core/urls.py +++ b/core/urls.py @@ -26,7 +26,7 @@ urlpatterns = [ path("admin/", admin.site.urls), - path("api/user/", include("user.urls", namespace="user")), + path("api/users/", include("user.urls", namespace="user")), path("api/borrowings/", include("borrowing.urls", namespace="borrowing")), path("api/payments/", include("payment.urls", namespace="payment")), path("api/schema/", SpectacularAPIView.as_view(), name="schema"),