From a0cbb04a9a6e6e805e1d00b501ccb4c1c922321f Mon Sep 17 00:00:00 2001 From: ericantosch Date: Mon, 19 Jun 2023 17:48:13 +0200 Subject: [PATCH] Finishing project --- .vscode/settings.json | 2 +- webApp/Backend/docker-compose.yml | 2 - webApp/Backend/sensor/mqtt.py | 61 ++++++++++++++------------ webApp/Backend/sensor/tests.py | 73 ++++++++++++++++++++++++++----- webApp/Backend/sensor/views.py | 19 ++++++++ 5 files changed, 116 insertions(+), 41 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a1508f6..6f526ca 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "[python]": { - "editor.defaultFormatter": "ms-python.black-formatter" + "editor.defaultFormatter": "ms-python.python" }, "python.formatting.provider": "none", "editor.formatOnSave": true, diff --git a/webApp/Backend/docker-compose.yml b/webApp/Backend/docker-compose.yml index 7e970bf..46a9cb9 100644 --- a/webApp/Backend/docker-compose.yml +++ b/webApp/Backend/docker-compose.yml @@ -11,8 +11,6 @@ services: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_DB=postgres - ports: - - "5432:5432" web: build: . diff --git a/webApp/Backend/sensor/mqtt.py b/webApp/Backend/sensor/mqtt.py index 3c9bcd6..4bf11d7 100644 --- a/webApp/Backend/sensor/mqtt.py +++ b/webApp/Backend/sensor/mqtt.py @@ -1,9 +1,16 @@ import uuid import datetime +from django.forms import ValidationError import paho.mqtt.client as mqtt import json import os import base64 +from django.db import IntegrityError +from sensor.models import SensorData, Container +from sensor.models import SensorData, Container + + + # Confiugure as needed USERNAME="mqtest2@thingsnet" @@ -18,33 +25,33 @@ TTN_MQTT_SERVER = "mobi35.inet.haw-hamburg.de" -# def postToDatabase(time, data, dataType, owner): -# """ -# The function then creates a new SensorData object using the SensorData.objects.create() method. -# The SensorData object has five fields: id, sensor_type, sensor_data, sensor_time, and owner. -# The id field is a UUID field that serves as the primary key for the table. -# The sensor_type field is a character field that stores the type of sensor. The sensor_data field is a character field that stores the data from the sensor. -# The sensor_time field is a date-time field that stores the time the data was recorded. -# The owner field is a foreign key to the Container model, which represents the container that the sensor is attached to. -# """ -# owner_instance = Container.objects.get(container_id=owner) -# if time is None or data is None or dataType is None or owner_instance is None: -# raise (ValueError("One or more parameters are None")) -# try: -# entry = SensorData.objects.create( -# id=uuid.uuid4(), -# sensor_type=dataType, -# sensor_data=data, -# sensor_time=time, -# owner=owner_instance, -# ) -# entry.save() -# except ValueError as e: -# print(e) -# except IntegrityError as e: -# print(e) -# except ValidationError as e: -# print(e) +def postToDatabase(time, data, dataType, owner): + """ + The function then creates a new SensorData object using the SensorData.objects.create() method. + The SensorData object has five fields: id, sensor_type, sensor_data, sensor_time, and owner. + The id field is a UUID field that serves as the primary key for the table. + The sensor_type field is a character field that stores the type of sensor. The sensor_data field is a character field that stores the data from the sensor. + The sensor_time field is a date-time field that stores the time the data was recorded. + The owner field is a foreign key to the Container model, which represents the container that the sensor is attached to. + """ + owner_instance = Container.objects.get(container_id=owner) + if time is None or data is None or dataType is None or owner_instance is None: + raise (ValueError("One or more parameters are None")) + try: + entry = SensorData.objects.create( + id=uuid.uuid4(), + sensor_type=dataType, + sensor_data=data, + sensor_time=time, + owner=owner_instance, + ) + entry.save() + except ValueError as e: + print(e) + except IntegrityError as e: + print(e) + except ValidationError as e: + print(e) # The callback for when the client receives a CONNACK response from the server. diff --git a/webApp/Backend/sensor/tests.py b/webApp/Backend/sensor/tests.py index e687c71..a13fe10 100644 --- a/webApp/Backend/sensor/tests.py +++ b/webApp/Backend/sensor/tests.py @@ -1,8 +1,10 @@ import datetime import uuid from django.urls import reverse +from rest_framework.routers import DefaultRouter from rest_framework import status -from rest_framework.test import APITestCase +from rest_framework.test import APITestCase, URLPatternsTestCase +from django.urls import include, path from .models import Container, SensorData, User from sensor.serializer import ContainerSerializer, SensorSerializer, UserSerializer @@ -10,13 +12,21 @@ test_id = uuid.uuid4() test_date = datetime.datetime.now() test_container = Container.objects.create(container_id=uuid.uuid4(), container_start="Berlin", container_destination="Hamburg", container_content="Bananas", container_door_closed=True, container_time=test_date) +router = DefaultRouter() + +class ContainerViewSetTests(APITestCase, URLPatternsTestCase): + urlpatterns = [ + path('', include(router.urls)), + ] + + def setUp(self): + self.container = Container.objects.create(container_id=uuid.uuid4(), container_start="Berlin", container_destination="Hamburg", container_content="Bananas", container_door_closed=True, container_time=datetime.datetime.now()) -class ContainerListTests(APITestCase): def test_list_containers(self): """ Ensure we can list all containers """ - url = reverse('container_list') + url = reverse('container-list') response = self.client.get(url) data = response.json() self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -24,21 +34,62 @@ def test_list_containers(self): serializer = ContainerSerializer(containers, many=True) self.assertEqual(data, serializer.data) - - -class SensorListTests(APITestCase): - def test_list_sensors(self): + def test_retrieve_container(self): """ - Ensure we can list all sensor data + Ensure we can retrieve a single container """ - url = reverse('sensor_list') + url = reverse('container-detail', args=[self.container.container_id]) response = self.client.get(url) data = response.json() self.assertEqual(response.status_code, status.HTTP_200_OK) - sensors = SensorData.objects.all() - serializer = SensorSerializer(sensors, many=True) + serializer = ContainerSerializer(self.container) self.assertEqual(data, serializer.data) + def test_create_container(self): + """ + Ensure we can create a new container + """ + url = reverse('container-list') + data = { + 'container_id': uuid.uuid4(), + 'container_start': 'Berlin', + 'container_destination': 'Hamburg', + 'container_content': 'Apples', + 'container_door_closed': True, + 'container_time': datetime.datetime.now() + } + response = self.client.post(url, data, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + container = Container.objects.get(container_id=data['container_id']) + serializer = ContainerSerializer(container) + self.assertEqual(response.json(), serializer.data) + + def test_update_container(self): + """ + Ensure we can update an existing container + """ + url = reverse('container-detail', args=[self.container.id]) + data = { + 'container_content': 'Oranges', + 'container_door_closed': False + } + response = self.client.patch(url, data, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.container.refresh_from_db() + self.assertEqual(self.container.container_content, data['container_content']) + self.assertEqual(self.container.container_door_closed, data['container_door_closed']) + + def test_delete_container(self): + """ + Ensure we can delete an existing container + """ + url = reverse('container-detail', args=[self.container.id]) + response = self.client.delete(url) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertFalse(Container.objects.filter(id=self.container.id).exists()) + + + class SensorDetailTests(APITestCase): def test_retrieve_sensor(self): diff --git a/webApp/Backend/sensor/views.py b/webApp/Backend/sensor/views.py index 44d00b2..4a3138e 100644 --- a/webApp/Backend/sensor/views.py +++ b/webApp/Backend/sensor/views.py @@ -9,6 +9,8 @@ from rest_framework import generics, viewsets from django.views.decorators.csrf import csrf_exempt, csrf_protect from rest_framework import generics +from rest_framework.authentication import TokenAuthentication +from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView from .models import SensorData, Container, User from .serializer import SensorSerializer, ContainerSerializer, UserSerializer @@ -75,6 +77,23 @@ def post(self, request): return JsonResponse(serializer.data["sensor_data"], safe=False) +class IsUserLoggedIn(APIView): + """ + Retrieve user login status + """ + authentication_classes = [TokenAuthentication] + permission_classes = [IsAuthenticated] + def get(self, request): + """ + Return the user login status + """ + if request.user.is_authenticated: + return JsonResponse({"loggedIn": True}) + else: + return JsonResponse({"loggedIn": False}) + + + class SensorByType(APIView): """ Retrieve sensor data by type and/or container