From 8fe03d97328decec0645e0a7a87d1d94afabf43a Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Thu, 9 Feb 2023 14:38:02 +0200 Subject: [PATCH 01/13] socket server setup and handle comment event --- backend/comments/__init__.py | 0 backend/comments/admin.py | 3 ++ backend/comments/apps.py | 6 ++++ backend/comments/consumers.py | 37 +++++++++++++++++++++++ backend/comments/migrations/__init__.py | 0 backend/comments/models.py | 3 ++ backend/comments/routing.py | 6 ++++ backend/comments/tests.py | 0 backend/comments/views.py | 4 +++ backend/configs/environment.py | 26 +++++++++++++++++ backend/slides/tests.py | 13 +++++---- backend/slidy_api/asgi.py | 21 ++++++------- backend/slidy_api/settings.py | 39 ++++++++++++++++++------- backend/slidy_api/urls.py | 2 +- backend/users/tests.py | 12 ++++---- backend/users/views.py | 6 ++-- 16 files changed, 143 insertions(+), 35 deletions(-) create mode 100644 backend/comments/__init__.py create mode 100644 backend/comments/admin.py create mode 100644 backend/comments/apps.py create mode 100644 backend/comments/consumers.py create mode 100644 backend/comments/migrations/__init__.py create mode 100644 backend/comments/models.py create mode 100644 backend/comments/routing.py create mode 100644 backend/comments/tests.py create mode 100644 backend/comments/views.py create mode 100644 backend/configs/environment.py diff --git a/backend/comments/__init__.py b/backend/comments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/comments/admin.py b/backend/comments/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/backend/comments/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/backend/comments/apps.py b/backend/comments/apps.py new file mode 100644 index 0000000..a90cc97 --- /dev/null +++ b/backend/comments/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CommentsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'comments' diff --git a/backend/comments/consumers.py b/backend/comments/consumers.py new file mode 100644 index 0000000..cee4d6b --- /dev/null +++ b/backend/comments/consumers.py @@ -0,0 +1,37 @@ +import json +from channels.generic.websocket import AsyncWebsocketConsumer + + +class CommentsConsumer(AsyncWebsocketConsumer): + async def connect(self): + self.room_group_name = 'owner' + + await self.channel_layer.group_add( + self.room_group_name, + self.channel_name + ) + + await self.accept() + + async def receive(self, text_data): + text_data_json = json.loads(text_data) + comment = text_data_json['message'] + + await self.channel_layer.group_send( + self.room_group_name, + { + 'type': 'broadcast_comment', + 'message': comment + } + ) + + async def broadcast_comment(self, event): + comment = event['message'] + + await self.send(text_data=json.dumps({ + 'type': 'chat', + 'message': comment + })) + + +chat_consumer = CommentsConsumer.as_asgi() diff --git a/backend/comments/migrations/__init__.py b/backend/comments/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/comments/models.py b/backend/comments/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/backend/comments/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/backend/comments/routing.py b/backend/comments/routing.py new file mode 100644 index 0000000..2c267b9 --- /dev/null +++ b/backend/comments/routing.py @@ -0,0 +1,6 @@ +from django.urls import re_path +from . import consumers + +websocket_urlpatterns = [ + re_path(r'ws/socket-server/', consumers.CommentsConsumer.as_asgi()) +] \ No newline at end of file diff --git a/backend/comments/tests.py b/backend/comments/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/comments/views.py b/backend/comments/views.py new file mode 100644 index 0000000..ff1f27d --- /dev/null +++ b/backend/comments/views.py @@ -0,0 +1,4 @@ +from django.shortcuts import render + +def index(request): + return render(request, 'index.html') \ No newline at end of file diff --git a/backend/configs/environment.py b/backend/configs/environment.py new file mode 100644 index 0000000..9b11690 --- /dev/null +++ b/backend/configs/environment.py @@ -0,0 +1,26 @@ +import os + +CLOUDINARY_NAME = os.environ.get('CLOUDINARY_CLOUD_NAME') + +CLOUDINARY_API_KEY = os.environ.get('CLOUDINARY_API_KEY') + +CLOUDINARY_API_SECRET = os.environ.get('CLOUDINARY_API_SECRET') + +DEFAULT_AVATAR = os.environ.get('DEFAULT_AVATAR') + +DB_NAME = os.environ.get('DB_NAME') + +DB_USER = os.environ.get('DB_USER') + +DB_PASSWORD = os.environ.get('DB_PASSWORD') + +DB_HOST = os.environ.get('DB_HOST') + +DB_PORT = os.environ.get('DB_PORT') + +SECRET_KEY = os.environ.get('SECRET_KEY') + +REDIS_HOST = os.environ.get('REDIS_HOST') + +REDIS_PORT = os.environ.get('REDIS_PORT') + diff --git a/backend/slides/tests.py b/backend/slides/tests.py index a7b9427..961b1c4 100644 --- a/backend/slides/tests.py +++ b/backend/slides/tests.py @@ -93,7 +93,7 @@ def test_delete_slide(self): response = self.client.post(reverse("slides-list"), data=data) response = self.client.delete( - reverse("slides-detail", kwargs={'pk': 1}), data=data) + reverse("slides-detail", kwargs={'pk': self.slide.id}), data=data) self.assertEqual(response.status_code, 204) @@ -118,10 +118,11 @@ def test_delete_others_slide(self): } response = self.client.post(reverse("slides-list"), data=data) + new_slide = response.json() self.client.credentials(HTTP_AUTHORIZATION=self.token) response = self.client.delete( - reverse("slides-detail", kwargs={'pk': 2}), data=data) + reverse("slides-detail", kwargs={'pk': new_slide['data']['id']}), data=data) result = response.json() self.assertEqual(response.status_code, 403) @@ -149,7 +150,7 @@ def test_delete_not_existed_slide(self): def test_retrieve_slide(self): self.client.credentials(HTTP_AUTHORIZATION=self.token) - response = self.client.get(reverse('slides-detail', kwargs={'pk': 1})) + response = self.client.get(reverse('slides-detail', kwargs={'pk': self.slide.id})) result = response.json() self.assertEqual(response.status_code, 200) @@ -161,6 +162,7 @@ def test_not_existed_retrieve_slide(self): response = self.client.get(reverse('slides-detail', kwargs={'pk': 4})) result = response.json() + self.assertEqual(response.status_code, 404) self.assertIn(result['detail'], 'Not found.') @@ -188,7 +190,7 @@ def test_update_own_slides(self): } response = self.client.patch( - reverse('slides-detail', kwargs={'pk': 1}), data=update_data) + reverse('slides-detail', kwargs={'pk': self.slide.id}), data=update_data) result = response.json() self.assertEqual(response.status_code, 200) @@ -218,6 +220,7 @@ def test_update_others_slides(self): } response = self.client.post(reverse("slides-list"), data=data) + new_slides = response.json() update_data = { "title": "updated title", @@ -227,7 +230,7 @@ def test_update_others_slides(self): self.client.credentials(HTTP_AUTHORIZATION=self.token) response = self.client.patch( - reverse("slides-detail", kwargs={'pk': 2}), data=update_data) + reverse("slides-detail", kwargs={'pk': new_slides['data']['id']}), data=update_data) result = response.json() diff --git a/backend/slidy_api/asgi.py b/backend/slidy_api/asgi.py index 61fa8c1..47dbb3e 100644 --- a/backend/slidy_api/asgi.py +++ b/backend/slidy_api/asgi.py @@ -1,16 +1,17 @@ -""" -ASGI config for slidy_api project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -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, URLRouter +from channels.auth import AuthMiddlewareStack +import comments.routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'slidy_api.settings') -application = get_asgi_application() +application = ProtocolTypeRouter({ + 'http':get_asgi_application(), + 'websocket': ( + URLRouter( + comments.routing.websocket_urlpatterns + ) + ) +}) \ No newline at end of file diff --git a/backend/slidy_api/settings.py b/backend/slidy_api/settings.py index 00d6d37..a0cf37c 100644 --- a/backend/slidy_api/settings.py +++ b/backend/slidy_api/settings.py @@ -11,6 +11,7 @@ """ from pathlib import Path +from configs import environment import os import cloudinary @@ -23,7 +24,7 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.environ.get('SECRET_KEY') +SECRET_KEY = environment.SECRET_KEY # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -33,6 +34,7 @@ # Application definition INSTALLED_APPS = [ + 'channels', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -42,6 +44,7 @@ # Internal Apps 'users', 'slides', + 'comments', # Third Party Packages 'rest_framework', 'rest_framework.authtoken', @@ -50,6 +53,8 @@ 'requests' ] +ASGI_APPLICATION = 'slidy_api.asgi.application' + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -78,16 +83,28 @@ }, ] -WSGI_APPLICATION = 'slidy_api.wsgi.application' - +ASGI_APPLICATION = 'slidy_api.asgi.application' +CHANNEL_LAYERS = { + 'default': { + "BACKEND": "channels_redis.core.RedisChannelLayer", + 'CONFIG': { + 'hosts': [(environment.REDIS_HOST, environment.REDIS_PORT)], + } + } +} + # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': environment.DB_NAME, + 'USER': environment.DB_USER, + 'PASSWORD': environment.DB_PASSWORD, + 'HOST': environment.DB_HOST, + 'PORT': environment.DB_PORT, } } @@ -145,10 +162,12 @@ ] } -DEFAULT_AVATAR = os.environ.get('DEFAULT_AVATAR') +DEFAULT_AVATAR = environment.DEFAULT_AVATAR cloudinary.config( - cloud_name = os.environ.get('CLOUDINARY_CLOUD_NAME'), - api_key = os.environ.get('CLOUDINARY_API_KEY'), - api_secret = os.environ.get('CLOUDINARY_API_SECRET') -) \ No newline at end of file + cloud_name = environment.CLOUDINARY_NAME, + api_key = environment.CLOUDINARY_API_KEY, + api_secret = environment.CLOUDINARY_API_SECRET +) + +serve_static = True \ No newline at end of file diff --git a/backend/slidy_api/urls.py b/backend/slidy_api/urls.py index 70fd4b3..c57ab01 100644 --- a/backend/slidy_api/urls.py +++ b/backend/slidy_api/urls.py @@ -4,5 +4,5 @@ urlpatterns = [ path('admin/', admin.site.urls, name='admin'), path('api/v1/auth/', include('users.urls')), - path('api/v1/', include('slidy_api.routers')) + path('api/v1/', include('slidy_api.routers')), ] diff --git a/backend/users/tests.py b/backend/users/tests.py index 00a2c40..19269d1 100644 --- a/backend/users/tests.py +++ b/backend/users/tests.py @@ -1,4 +1,5 @@ from rest_framework.test import APITestCase + from .models import User from knox.models import AuthToken @@ -16,7 +17,7 @@ def setUp(self): self.token = f'Token {str(AuthToken.objects.create(user=self.user)[1])}' - def test_get__users_without_slides(self): + def test_get_users_without_slides(self): response = self.client.get(reverse('users-list')) result = response.json() @@ -24,7 +25,7 @@ def test_get__users_without_slides(self): self.assertIsInstance(result, list) self.assertEqual(result[0]['first_name'], 'fadi') - def test_get__users_with_slides(self): + def test_get_users_with_slides(self): response = self.client.get(reverse('users-list') + '?slides=true') result = response.json() @@ -149,7 +150,7 @@ def test_update_own_avatar(self): } response = self.client.put( - reverse('users-detail', kwargs={'pk': 1}), data=data) + reverse('users-detail', kwargs={'pk': self.user.id}), data=data) result = response.json() self.assertEqual(response.status_code, 200) @@ -157,13 +158,14 @@ def test_update_own_avatar(self): def test_update_other_avatar(self): - self.client.post(reverse('sign-up'), data={ + new_user_response = self.client.post(reverse('sign-up'), data={ "username": "ahmedsaleh", "password": "Test123456!!", "email": "ahmedsaleh@gmail.com", "first_name": "Ahmed", "last_name": "Saleh" }) + new_user = new_user_response.json() self.client.credentials(HTTP_AUTHORIZATION=self.token) @@ -172,7 +174,7 @@ def test_update_other_avatar(self): } response = self.client.put( - reverse('users-detail', kwargs={'pk': 2}), data=data) + reverse('users-detail', kwargs={'pk': new_user['data']['id']}), data=data) result = response.json() self.assertEqual(response.status_code, 403) diff --git a/backend/users/views.py b/backend/users/views.py index f1633d6..61861a2 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -79,10 +79,8 @@ def post(self, request, *args, **kwargs): return Response({ "status_code": 200, "message": "success", - "data": { - "user": self.get_serializer(user).data, - "token": AuthToken.objects.create(user)[1] - } + "data": UserSerializer(user).data, + "token": AuthToken.objects.create(user)[1], }, status=status.HTTP_200_OK) From 23361775c6996bd0ecb13dabf9e2f08eeb917a6c Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Thu, 9 Feb 2023 14:40:00 +0200 Subject: [PATCH 02/13] add new installed packages to the requirments --- requirments.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/requirments.txt b/requirments.txt index 65da0f2..34dcd33 100644 --- a/requirments.txt +++ b/requirments.txt @@ -5,6 +5,10 @@ django-cors-headers django-rest-knox PyYAML cloudinary -requests=2.6.0 +requests==2.6.0 uplink -markdown \ No newline at end of file +markdown +channels==3.0.5 +channels-radis +psycopg2-binary +pytest \ No newline at end of file From 4a00cf6caa3fc5c9a138f60bf58d496678b0fea4 Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:21:30 +0200 Subject: [PATCH 03/13] setup ci/cd with postgres --- backend/slidy_api/settings.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/backend/slidy_api/settings.py b/backend/slidy_api/settings.py index a0cf37c..4e68587 100644 --- a/backend/slidy_api/settings.py +++ b/backend/slidy_api/settings.py @@ -96,17 +96,30 @@ # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': environment.DB_NAME, - 'USER': environment.DB_USER, - 'PASSWORD': environment.DB_PASSWORD, - 'HOST': environment.DB_HOST, - 'PORT': environment.DB_PORT, +DB_USERNAME = environment.DB_USER +DB_PASSWORD = environment.DB_PASSWORD +DB_HOST = environment.DB_HOST +DB_PORT = environment.DB_PORT +DB_NAME= environment.DB_NAME +DB_IS_AVAIL = all([ + DB_USERNAME, + DB_PASSWORD, + DB_HOST, + DB_PORT, + DB_NAME +]) + +if DB_IS_AVAIL: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': DB_NAME, + 'USER': DB_USERNAME, + 'PASSWORD': DB_PASSWORD, + 'HOST': DB_HOST, + 'PORT': DB_PORT, + } } -} # Password validation From a5d1847fce0f64788dcaab5a18e2a482a1b73f01 Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:22:44 +0200 Subject: [PATCH 04/13] change channels version --- .github/workflows/django.yml | 24 ++++++++++++++++++++++++ requirements.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 54f34d8..c10f462 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -10,10 +10,28 @@ jobs: build: runs-on: ubuntu-latest + env: + MY_POSTGRES_USER: someuser + MY_POSTGRES_PASSWORD: somepassword + MY_POSTGRES_DB: somedbname strategy: max-parallel: 4 matrix: python-version: [3.7, 3.8, 3.9] + services: + postgres_main: + image: postgres:12 + env: + POSTGRES_USER: ${{ secrets.POSTGRES_USER }} + POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} + POSTGRES_DB: ${{ secrets.POSTGRES_DB }} + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 steps: - uses: actions/checkout@v3 @@ -33,6 +51,12 @@ jobs: CLOUDINARY_CLOUD_NAME: ${{ secrets.CLOUDINARY_CLOUD_NAME }} CLOUDINARY_API_KEY: ${{ secrets.CLOUDINARY_API_KEY }} CLOUDINARY_API_SECRET: ${{ secrets.CLOUDINARY_API_SECRET }} + DB_USERNAME: ${{ secrets.POSTGRES_USER }} + DB_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} + DB_HOST: ${{ secrets.POSTGRES_HOST }} + DB_DATABASE: ${{ secrets.POSTGRES_DB }} + DB_PORT: ${{ secrets.POSTGRES_PORT }} + run: | cd backend python manage.py test \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 454ccf9..7621277 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,6 @@ requests uplink markdown cloudinary -channels==3.0.5 +channels channels-radis psycopg2-binary From adec6123a958a931a1608048b1fb2b466c4b8b02 Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:24:33 +0200 Subject: [PATCH 05/13] fix syntax error in ymal file --- .github/workflows/django.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index c10f462..171e045 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest - env: + env: MY_POSTGRES_USER: someuser MY_POSTGRES_PASSWORD: somepassword MY_POSTGRES_DB: somedbname From 7c624bee4beb206dc70379b5b10691054518e940 Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:28:11 +0200 Subject: [PATCH 06/13] add channels-redis version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7621277..8a66584 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,5 +10,5 @@ uplink markdown cloudinary channels -channels-radis +channels_redis==2.0.0 psycopg2-binary From c844a67e587f2e75d4a3e065712526ed129d1a47 Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:39:41 +0200 Subject: [PATCH 07/13] fix dependancies conflict --- requirements.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 8a66584..c6c8b12 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -django +django>=4.0.0,<4.1.0 django-dotenv djangorestframework django-cors-headers @@ -9,6 +9,7 @@ requests uplink markdown cloudinary -channels -channels_redis==2.0.0 +asgiref>=3.6.0 +channels==3.0.5 +channels_redis==4.0.0 psycopg2-binary From 899af974b187d1646134c6203c7c5f618406112c Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:40:54 +0200 Subject: [PATCH 08/13] remove restrication on django version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c6c8b12..0777c1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -django>=4.0.0,<4.1.0 +django django-dotenv djangorestframework django-cors-headers From 55807a82fad7e4bdc668b91776a701ef820ea753 Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:51:53 +0200 Subject: [PATCH 09/13] fix database connection --- backend/configs/environment.py | 10 +++++----- backend/slidy_api/settings.py | 33 ++++++++++----------------------- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/backend/configs/environment.py b/backend/configs/environment.py index 9b11690..eac12e9 100644 --- a/backend/configs/environment.py +++ b/backend/configs/environment.py @@ -8,15 +8,15 @@ DEFAULT_AVATAR = os.environ.get('DEFAULT_AVATAR') -DB_NAME = os.environ.get('DB_NAME') +DB_NAME = os.environ.get('POSTGRES_DB') -DB_USER = os.environ.get('DB_USER') +DB_USER = os.environ.get('POSTGRES_USER') -DB_PASSWORD = os.environ.get('DB_PASSWORD') +DB_PASSWORD = os.environ.get('POSTGRES_PASSWORD') -DB_HOST = os.environ.get('DB_HOST') +DB_HOST = os.environ.get('POSTGRES_HOST') -DB_PORT = os.environ.get('DB_PORT') +DB_PORT = os.environ.get('POSTGRES_PORT') SECRET_KEY = os.environ.get('SECRET_KEY') diff --git a/backend/slidy_api/settings.py b/backend/slidy_api/settings.py index 4e68587..a0cf37c 100644 --- a/backend/slidy_api/settings.py +++ b/backend/slidy_api/settings.py @@ -96,30 +96,17 @@ # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases -DB_USERNAME = environment.DB_USER -DB_PASSWORD = environment.DB_PASSWORD -DB_HOST = environment.DB_HOST -DB_PORT = environment.DB_PORT -DB_NAME= environment.DB_NAME -DB_IS_AVAIL = all([ - DB_USERNAME, - DB_PASSWORD, - DB_HOST, - DB_PORT, - DB_NAME -]) - -if DB_IS_AVAIL: - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': DB_NAME, - 'USER': DB_USERNAME, - 'PASSWORD': DB_PASSWORD, - 'HOST': DB_HOST, - 'PORT': DB_PORT, - } + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': environment.DB_NAME, + 'USER': environment.DB_USER, + 'PASSWORD': environment.DB_PASSWORD, + 'HOST': environment.DB_HOST, + 'PORT': environment.DB_PORT, } +} # Password validation From 6333ffe72143edf1a4a0c7db87758372fffce57c Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 15:57:20 +0200 Subject: [PATCH 10/13] fix job-scope enviroment veriables --- .github/workflows/django.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 171e045..528bd87 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest env: - MY_POSTGRES_USER: someuser - MY_POSTGRES_PASSWORD: somepassword - MY_POSTGRES_DB: somedbname + MY_POSTGRES_USER: "someuser" + MY_POSTGRES_PASSWORD: "somepassword" + MY_POSTGRES_DB: "somedbname" strategy: max-parallel: 4 matrix: From 17189f9a3cef41236ba86771c001b2e243376e5c Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 16:06:50 +0200 Subject: [PATCH 11/13] fix database connection for actions --- backend/configs/environment.py | 2 +- backend/slidy_api/settings.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/backend/configs/environment.py b/backend/configs/environment.py index eac12e9..64b5495 100644 --- a/backend/configs/environment.py +++ b/backend/configs/environment.py @@ -8,7 +8,7 @@ DEFAULT_AVATAR = os.environ.get('DEFAULT_AVATAR') -DB_NAME = os.environ.get('POSTGRES_DB') +DB_DATABASE = os.environ.get('POSTGRES_DB') DB_USER = os.environ.get('POSTGRES_USER') diff --git a/backend/slidy_api/settings.py b/backend/slidy_api/settings.py index a0cf37c..1b724b7 100644 --- a/backend/slidy_api/settings.py +++ b/backend/slidy_api/settings.py @@ -96,11 +96,24 @@ # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases +DB_USERNAME= environment.DB_USER +DB_PASSWORD= environment.DB_PASSWORD +DB_HOST= environment.DB_HOST +DB_PORT= environment.DB_PORT +DB_DATABASE= environment.DB_DATABASE + +DB_IS_AVAIL = all([ + DB_USERNAME, + DB_PASSWORD, + DB_HOST, + DB_PORT, + DB_DATABASE +]) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': environment.DB_NAME, + 'NAME': environment.DB_DATABASE, 'USER': environment.DB_USER, 'PASSWORD': environment.DB_PASSWORD, 'HOST': environment.DB_HOST, From b96d559bc64da158c88c68f21b0fe6e575294bbf Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 16:09:04 +0200 Subject: [PATCH 12/13] add condidtion to db settings --- backend/slidy_api/settings.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/backend/slidy_api/settings.py b/backend/slidy_api/settings.py index 1b724b7..25f003d 100644 --- a/backend/slidy_api/settings.py +++ b/backend/slidy_api/settings.py @@ -110,16 +110,18 @@ DB_DATABASE ]) -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': environment.DB_DATABASE, - 'USER': environment.DB_USER, - 'PASSWORD': environment.DB_PASSWORD, - 'HOST': environment.DB_HOST, - 'PORT': environment.DB_PORT, +if DB_IS_AVAIL: + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': environment.DB_DATABASE, + 'USER': environment.DB_USER, + 'PASSWORD': environment.DB_PASSWORD, + 'HOST': environment.DB_HOST, + 'PORT': environment.DB_PORT, + } } -} # Password validation From 234f0053f8681d608dc1bb6bb141aa06364acd5f Mon Sep 17 00:00:00 2001 From: fadezak100 Date: Mon, 13 Feb 2023 17:15:06 +0200 Subject: [PATCH 13/13] add new work pipeline script --- .github/workflows/django.yml | 104 +++++++++++++++++----------------- backend/slidy_api/settings.py | 20 +------ 2 files changed, 54 insertions(+), 70 deletions(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 528bd87..85a370a 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -1,62 +1,60 @@ -name: Django CI +name: CI -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] +on: [push] jobs: - build: + test: runs-on: ubuntu-latest - env: - MY_POSTGRES_USER: "someuser" - MY_POSTGRES_PASSWORD: "somepassword" - MY_POSTGRES_DB: "somedbname" - strategy: - max-parallel: 4 - matrix: - python-version: [3.7, 3.8, 3.9] + services: - postgres_main: - image: postgres:12 + postgres: + image: postgres:11 env: - POSTGRES_USER: ${{ secrets.POSTGRES_USER }} - POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} - POSTGRES_DB: ${{ secrets.POSTGRES_DB }} - ports: - - 5432:5432 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: ['5432:5432'] + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Run Tests - env: - DEBUG: "0" - SECRET_KEY: ${{ secrets.SECRET_KEY }} - DEFAULT_AVATAR: ${{ secrets.DEFAULT_AVATAR }} - CLOUDINARY_CLOUD_NAME: ${{ secrets.CLOUDINARY_CLOUD_NAME }} - CLOUDINARY_API_KEY: ${{ secrets.CLOUDINARY_API_KEY }} - CLOUDINARY_API_SECRET: ${{ secrets.CLOUDINARY_API_SECRET }} - DB_USERNAME: ${{ secrets.POSTGRES_USER }} - DB_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} - DB_HOST: ${{ secrets.POSTGRES_HOST }} - DB_DATABASE: ${{ secrets.POSTGRES_DB }} - DB_PORT: ${{ secrets.POSTGRES_PORT }} - - run: | - cd backend - python manage.py test \ No newline at end of file + - uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + + - uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + if: steps.cache.outputs.cache-hit != 'true' + + - name: Run Tests + env: + DATABASE_URL: 'postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/postgres' + DEBUG: "0" + SECRET_KEY: ${{ secrets.SECRET_KEY }} + DEFAULT_AVATAR: ${{ secrets.DEFAULT_AVATAR }} + CLOUDINARY_CLOUD_NAME: ${{ secrets.CLOUDINARY_CLOUD_NAME }} + CLOUDINARY_API_KEY: ${{ secrets.CLOUDINARY_API_KEY }} + CLOUDINARY_API_SECRET: ${{ secrets.CLOUDINARY_API_SECRET }} + DB_USERNAME: ${{ secrets.POSTGRES_USER }} + DB_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} + DB_HOST: ${{ secrets.POSTGRES_HOST }} + DB_DATABASE: ${{ secrets.POSTGRES_DB }} + DB_PORT: ${{ secrets.POSTGRES_PORT }} + REDIS_HOST: localhost + REDIS_PORT: 6379 + run: | + cd backend + python manage.py test \ No newline at end of file diff --git a/backend/slidy_api/settings.py b/backend/slidy_api/settings.py index 25f003d..26aa1d4 100644 --- a/backend/slidy_api/settings.py +++ b/backend/slidy_api/settings.py @@ -96,23 +96,9 @@ # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases -DB_USERNAME= environment.DB_USER -DB_PASSWORD= environment.DB_PASSWORD -DB_HOST= environment.DB_HOST -DB_PORT= environment.DB_PORT -DB_DATABASE= environment.DB_DATABASE - -DB_IS_AVAIL = all([ - DB_USERNAME, - DB_PASSWORD, - DB_HOST, - DB_PORT, - DB_DATABASE -]) - -if DB_IS_AVAIL: - - DATABASES = { + + +DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': environment.DB_DATABASE,