diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..d7a4bef --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,34 @@ +# Use an official Python runtime as a parent image +FROM python:3.8-slim + +# Set environment variables for Django +ENV DJANGO_SETTINGS_MODULE=plovidba_projekt.settings +ENV PYTHONUNBUFFERED 1 + +# Install PostgreSQL development headers, build tools, and other dependencies +RUN apt-get update && \ + apt-get install -y libpq-dev gcc && \ + apt-get clean + +# Install GDAL +RUN apt-get update \ + && apt-get install -y binutils libproj-dev gdal-bin + +# Install the PostgreSQL client +RUN apt-get update && apt-get install -y postgresql-client + +# Create and set the working directory in the container +WORKDIR /app/plovidba_projekt + +# Copy the requirements file into the container and install dependencies +COPY requirements.txt /app/plovidba_projekt/ +RUN pip install -r requirements.txt + +# Copy the rest of the application code into the container +COPY . /app/plovidba_projekt/ + +# Expose the port the application will run on (if necessary) +# EXPOSE 8000 + +# Define the default command to run when starting the container +CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] \ No newline at end of file diff --git a/Dockerfile.prod b/Dockerfile.prod new file mode 100644 index 0000000..006e7ae --- /dev/null +++ b/Dockerfile.prod @@ -0,0 +1,40 @@ +# Use an official Python runtime as a parent image +FROM python:3.8-slim + +# Set environment variables for Django +ENV DJANGO_SETTINGS_MODULE=plovidba_projekt.settings +ENV PYTHONUNBUFFERED 1 + +# Install PostgreSQL development headers, build tools, and other dependencies +RUN apt-get update && \ + apt-get install -y libpq-dev gcc && \ + apt-get clean + +# Install GDAL +RUN apt-get update \ + && apt-get install -y binutils libproj-dev gdal-bin + +# Install PostgreSQL client and PostGIS extension +RUN apt-get update && \ + apt-get install -y postgresql-client postgis && \ + apt-get clean + +# .Create and set the working directory in the container +RUN mkdir -p /app/plovidba_projekt +WORKDIR /app/plovidba_projekt + +# .Copy the requirements file into the container and install dependencies +COPY requirements.txt /app/plovidba_projekt/ +RUN pip install -r requirements.txt + +# .Copy the rest of the application code into the container +COPY . /app/plovidba_projekt/ + +VOLUME /app/media +VOLUME /app/static + +# Expose the port the application will run on (if necessary) +EXPOSE 8000 + +# Run the Django application using Gunicorn in production mode +CMD ["gunicorn", "plovidba_projekt.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "4"] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..cbb0dbd --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,33 @@ +version: "3" +volumes: + media: + static: +services: + # Development Environment + api_dev: + build: + context: . + dockerfile: Dockerfile.dev + container_name: plovidba_dev_container10 + restart: on-failure + ports: + - "8000:8000" # Map host port 8000 to container port 8000 + volumes: + - .:/app # Mount your application code into the container + env_file: + - .env # Specify the location of your .env files + + # Production Environment + api_prod: + build: + context: . + dockerfile: Dockerfile.prod + container_name: plovidba_prod_container + restart: on-failure + ports: + - "8000:8000" # Map host port 8000 to container port 8000 + env_file: + - C:\Users\Student1\Desktop\plovidba\myenv\plovidba_projekt\plovidba_projekt # Specify the location of your .env file + volumes: + - static:/app/static + - media:/app/media diff --git a/plovidba_aplikacija/__pycache__/serializers.cpython-38.pyc b/plovidba_aplikacija/__pycache__/serializers.cpython-38.pyc index 115b4cc..418e54e 100644 Binary files a/plovidba_aplikacija/__pycache__/serializers.cpython-38.pyc and b/plovidba_aplikacija/__pycache__/serializers.cpython-38.pyc differ diff --git a/plovidba_aplikacija/__pycache__/tests.cpython-38.pyc b/plovidba_aplikacija/__pycache__/tests.cpython-38.pyc new file mode 100644 index 0000000..ed18a3c Binary files /dev/null and b/plovidba_aplikacija/__pycache__/tests.cpython-38.pyc differ diff --git a/plovidba_aplikacija/__pycache__/urls.cpython-38.pyc b/plovidba_aplikacija/__pycache__/urls.cpython-38.pyc index a310f7f..fb35df3 100644 Binary files a/plovidba_aplikacija/__pycache__/urls.cpython-38.pyc and b/plovidba_aplikacija/__pycache__/urls.cpython-38.pyc differ diff --git a/plovidba_aplikacija/__pycache__/views.cpython-38.pyc b/plovidba_aplikacija/__pycache__/views.cpython-38.pyc index 1c8ab69..c957fc9 100644 Binary files a/plovidba_aplikacija/__pycache__/views.cpython-38.pyc and b/plovidba_aplikacija/__pycache__/views.cpython-38.pyc differ diff --git a/plovidba_aplikacija/serializers.py b/plovidba_aplikacija/serializers.py index e67cdb6..0956705 100644 --- a/plovidba_aplikacija/serializers.py +++ b/plovidba_aplikacija/serializers.py @@ -1,10 +1,10 @@ from rest_framework import serializers -from .models import ObjektSigurnosti, Log - -class ObjektSigurnostiSerializer(serializers.ModelSerializer): - class Meta: - model = ObjektSigurnosti - fields = '__all__' +from django.contrib.gis.geos import Point +from .models import ObjektSigurnosti +# class ObjektSigurnostiSerializer(serializers.ModelSerializer): +# class Meta: +# model = ObjektSigurnosti +# fields = '__all__' # class LogSerializer(serializers.ModelSerializer): @@ -12,4 +12,32 @@ class ObjektSigurnostiSerializer(serializers.ModelSerializer): # class Meta: # model = Log -# fields = ('id', 'user', 'user_full_name', 'timestamp', 'akcija', 'opis') \ No newline at end of file +# fields = ('id', 'user', 'user_full_name', 'timestamp', 'akcija', 'opis') + +class PointSerializer(serializers.Serializer): + lat = serializers.FloatField() + lon = serializers.FloatField() + + def to_representation(self, instance): + return {'lat': instance.y, 'lon': instance.x} + +class ObjektSigurnostiSerializer(serializers.ModelSerializer): + lokacija = PointSerializer() + +class ObjektSigurnostiSerializer(serializers.ModelSerializer): + lokacija = PointSerializer() + + class Meta: + model = ObjektSigurnosti + fields = '__all__' + + def to_representation(self, instance): + representation = super().to_representation(instance) + representation['lokacija'] = PointSerializer(instance.lokacija).data + return representation + + def create(self, validated_data): + lokacija_data = validated_data.pop('lokacija') + lokacija = Point(lokacija_data['lon'], lokacija_data['lat'], srid=3765) + objekt = ObjektSigurnosti.objects.create(lokacija=lokacija, **validated_data) + return objekt \ No newline at end of file diff --git a/plovidba_aplikacija/tests.py b/plovidba_aplikacija/tests.py index 7ce503c..8b88534 100644 --- a/plovidba_aplikacija/tests.py +++ b/plovidba_aplikacija/tests.py @@ -1,3 +1,69 @@ from django.test import TestCase +from django.contrib.gis.geos import Point +from django.urls import reverse +from rest_framework import status +from rest_framework.test import APITestCase +from plovidba_aplikacija.models import ObjektSigurnosti +from plovidba_aplikacija.serializers import PointSerializer -# Create your tests here. +# Testiranje listanja objekata +class ObjektSigurnostiListTest(APITestCase): + def test_list_objekti_sigurnosti(self): + url = reverse('objektisigurnosti-list') + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('results', response.data) + +# Testiranje stvaranja objekata +class ObjektSigurnostiCreateTest(APITestCase): + def setUp(self): + self.url = reverse('objektisigurnosti-list') + + def test_create_objekt_sigurnosti(self): + data = { + 'lokacija': {'lat': 45.123, 'lon': 18.456}, + 'naziv': 'test-naziv', + } + response = self.client.post(self.url, data, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + +# Testiranje dohvaćanja pojedinog objekata +class ObjektSigurnostiDetailTest(APITestCase): + def setUp(self): + self.objekt = ObjektSigurnosti.objects.create( + lokacija=Point(18.456, 45.123), + naziv='test-naziv', + ) + self.url = reverse('objektisigurnosti-detail', args=[self.objekt.pk]) + + + def test_get_objekt_sigurnosti(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + # def test_update_objekt_sigurnosti(self): + # data = { + # 'lokacija': {'lat': 15.17517, 'lon': 44.01113}, + # 'naziv' : 'updated-naziv', + + # } + # response = self.client.patch(self.url, data, format='json') + # self.assertEqual(response.status_code, status.HTTP_200_OK) + # # Reload the object from the database + # updated_objekt = ObjektSigurnosti.objects.get(pk=self.objekt.pk) + + # # Check if the values are updated correctly + # self.assertEqual(updated_objekt.lokacija.x, 13.79758) + # self.assertEqual(updated_objekt.lokacija.y, 44.9254) + # self.assertEqual(updated_objekt.naziv, 'updated-naziv') + + +# def test_retrieve_objekt_sigurnosti(self): +# url = reverse('objektisigurnosti-detail', args=[self.objekt.id]) +# response = self.client.get(url) + +# self.assertEqual(response.status_code, status.HTTP_200_OK) + + diff --git a/plovidba_aplikacija/urls.py b/plovidba_aplikacija/urls.py index f03f0a1..f5ef556 100644 --- a/plovidba_aplikacija/urls.py +++ b/plovidba_aplikacija/urls.py @@ -1,6 +1,6 @@ from django.urls import path, include -from .views import ObjektSigurnostiList, ObjektSigurnostiDetail, Log +from .views import ObjektSigurnostiList, ObjektSigurnostiDetail from plovidba_aplikacija import views urlpatterns = [ diff --git a/plovidba_aplikacija/views.py b/plovidba_aplikacija/views.py index 1eec7d7..a575364 100644 --- a/plovidba_aplikacija/views.py +++ b/plovidba_aplikacija/views.py @@ -4,7 +4,7 @@ from rest_framework.generics import ListAPIView from rest_framework.response import Response from rest_framework import status from rest_framework import generics -from .models import ObjektSigurnosti, Log +from .models import ObjektSigurnosti from .serializers import ObjektSigurnostiSerializer from django.shortcuts import get_object_or_404 from rest_framework.pagination import LimitOffsetPagination @@ -34,8 +34,8 @@ def perform_create(self, serializer): #used to customize the behavior when creating an object, and in this case, #it sets the operater field and creates a log entry for the created object. serializer.save(operater=self.request.user) - instance = serializer.instance - self.create_log(instance) + # instance = serializer.instance + # self.create_log(instance) def get_serializer_class(self): if self.request.method == "GET": diff --git a/plovidba_projekt/__pycache__/settings.cpython-38.pyc b/plovidba_projekt/__pycache__/settings.cpython-38.pyc index 6dbd781..bde7ac6 100644 Binary files a/plovidba_projekt/__pycache__/settings.cpython-38.pyc and b/plovidba_projekt/__pycache__/settings.cpython-38.pyc differ diff --git a/plovidba_projekt/settings.py b/plovidba_projekt/settings.py index 38ebdbf..adf68ff 100644 --- a/plovidba_projekt/settings.py +++ b/plovidba_projekt/settings.py @@ -99,6 +99,10 @@ DATABASES = { } } +DATABASES["default"]["TEST"] = { + "NAME": ENV_STR("DATABASE_TEST_NAME", "test_plovidba_dev_db") +} + # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators @@ -173,3 +177,5 @@ TEMP_DIR = os.path.join(BASE_DIR, "temp") DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c86f0d4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,88 @@ +asgiref==3.5.2 +async-timeout==4.0.2 +attrs==22.1.0 +autobahn==23.1.2 +Automat==22.10.0 +backports.zoneinfo==0.2.1 +black==22.8.0 +certifi==2022.6.15 +cffi==1.15.1 +channels==4.0.0 +channels-redis==4.0.0 +charset-normalizer==2.1.1 +click==8.1.3 +click-plugins==1.1.1 +cligj==0.7.2 +constantly==15.1.0 +coreapi==2.3.3 +coreschema==0.0.4 +cryptography +daphne==4.0.0 +defusedxml==0.7.1 +dj-database-url==1.2.0 +dj-rest-auth==2.2.5 +Django==4.1 +django-allauth==0.50.0 +django-cors-headers==3.13.0 +django-environ==0.9.0 +django-filter==22.1 +django-leaflet==0.28.2 +django-sslserver==0.22 +djangorestframework==3.13.1 +djangorestframework-gis==1.0 +djangorestframework-simplejwt==5.2.0 +drf-spectacular==0.24.2 +drf-yasg==1.21.4 +et-xmlfile==1.1.0 +Fiona==1.9.3 +flake8==6.0.0 +hyperlink==21.0.0 +idna==3.3 +importlib-metadata==6.6.0 +importlib-resources==5.10.0 +incremental==22.10.0 +inflection==0.5.1 +itypes==1.2.0 +Jinja2==3.1.2 +jsonschema==4.16.0 +MarkupSafe==2.1.2 +mccabe==0.7.0 +msgpack==1.0.4 +munch==3.0.0 +mypy-extensions==0.4.3 +oauthlib==3.2.0 +openpyxl==3.1.2 +packaging==23.0 +pathspec==0.10.1 +pkgutil-resolve-name==1.3.10 +platformdirs==2.5.2 +psycopg2==2.9.3 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycodestyle==2.10.0 +pycparser==2.21 +pyflakes==3.0.1 +PyJWT==2.4.0 +pyOpenSSL==23.0.0 +pyrsistent==0.18.1 +python3-openid==3.2.0 +pytz==2022.2.1 +PyYAML==6.0 +redis==4.4.2 +requests==2.28.1 +requests-oauthlib==1.3.1 +ruamel.yaml==0.17.21 +ruamel.yaml.clib==0.2.7 +sentry-sdk==1.15.0 +service-identity==21.1.0 +six==1.16.0 +sqlparse==0.4.2 +tomli==2.0.1 +Twisted==22.10.0 +txaio==23.1.1 +typing-extensions==4.3.0 +uritemplate==4.1.1 +urllib3==1.26.12 +zipp==3.9.0 +zope.interface==5.5.2 +gunicorn