diff --git a/.gitignore b/.gitignore index 2887fed..4bb0ce1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ # Python __pycache__/ -**/__pycache__/** *.py[cod] -*pyc *.pyo *.pyd *.so diff --git a/api/admin.py b/api/admin.py index 45e6514..77550fc 100644 --- a/api/admin.py +++ b/api/admin.py @@ -1,8 +1,9 @@ from django.contrib import admin -from .models import User, Prediction, Satellite, TelemetryPacket +from .models import User, Prediction, UserPrediction, Satellite, TelemetryPacket admin.site.register(User) admin.site.register(Prediction) +admin.site.register(UserPrediction) admin.site.register(Satellite) admin.site.register(TelemetryPacket) \ No newline at end of file diff --git a/api/migrations/0002_preditctiontemplate_savedpoint_savedrateprofile_and_more.py b/api/migrations/0002_preditctiontemplate_savedpoint_savedrateprofile_and_more.py deleted file mode 100644 index 0696c23..0000000 --- a/api/migrations/0002_preditctiontemplate_savedpoint_savedrateprofile_and_more.py +++ /dev/null @@ -1,136 +0,0 @@ -# Generated by Django 4.2.23 on 2025-06-25 11:17 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone - - -class Migration(migrations.Migration): - - dependencies = [ - ('api', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='PreditctionTemplate', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=100)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('template_data', models.JSONField(blank=True, default=dict)), - ('is_default', models.BooleanField(default=False)), - ('user', models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'unique_together': {('user', 'name')}, - }, - ), - migrations.CreateModel( - name='SavedPoint', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=100)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('lat', models.FloatField(default=0.0)), - ('lon', models.FloatField(default=0.0)), - ('alt', models.FloatField(default=0.0)), - ('is_default', models.BooleanField(default=False)), - ('user', models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'unique_together': {('user', 'name')}, - }, - ), - migrations.CreateModel( - name='SavedRateProfile', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=100)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('rate_profile_data', models.JSONField(blank=True, default=dict)), - ('is_default', models.BooleanField(default=False)), - ('user', models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'unique_together': {('user', 'name')}, - }, - ), - migrations.RemoveField( - model_name='prediction', - name='deleted_at', - ), - migrations.AddField( - model_name='prediction', - name='request', - field=models.JSONField(default=dict), - ), - migrations.AddField( - model_name='prediction', - name='user', - field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, related_name='predictions', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='satellite', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), - preserve_default=False, - ), - migrations.AddField( - model_name='satellite', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='satellite_images/'), - ), - migrations.AddField( - model_name='satellite', - name='metadata', - field=models.JSONField(blank=True, default=dict), - ), - migrations.AddField( - model_name='satellite', - name='user', - field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='telemetrypacket', - name='raw_data', - field=models.JSONField(blank=True, default=dict), - ), - migrations.AddField( - model_name='telemetrypacket', - name='user', - field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( - model_name='prediction', - name='result', - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name='telemetrypacket', - name='alt', - field=models.FloatField(default=0.0), - ), - migrations.AlterField( - model_name='telemetrypacket', - name='lat', - field=models.FloatField(default=0.0), - ), - migrations.AlterField( - model_name='telemetrypacket', - name='lon', - field=models.FloatField(default=0.0), - ), - migrations.AlterField( - model_name='telemetrypacket', - name='payload', - field=models.JSONField(blank=True, default=dict), - ), - migrations.DeleteModel( - name='UserPrediction', - ), - ] diff --git a/api/migrations/__pycache__/0001_initial.cpython-311.pyc b/api/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..5cce3a3 Binary files /dev/null and b/api/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/__init__.cpython-311.pyc b/api/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..8fc4c03 Binary files /dev/null and b/api/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/models.py b/api/models.py index 5d7b7c3..bb29c77 100644 --- a/api/models.py +++ b/api/models.py @@ -1,87 +1,36 @@ import uuid from django.db import models from django.contrib.auth import get_user_model -from django.contrib.auth.models import AbstractUser, AnonymousUser - +from django.contrib.auth.models import AbstractUser class User(AbstractUser): satellites = models.ManyToManyField("Satellite", related_name="users") class Prediction(models.Model): - user = models.ForeignKey(get_user_model( - ), on_delete=models.CASCADE, default=0, related_name='predictions') - satellite = models.ForeignKey( - 'Satellite', on_delete=models.CASCADE, related_name='predictions', null=True) + satellite = models.ForeignKey('Satellite', on_delete=models.CASCADE, related_name='predictions', null=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) - request = models.JSONField(default=dict) - result = models.JSONField(default=dict) + result = models.JSONField() + deleted_at = models.DateTimeField(null=True, blank=True) +class UserPrediction(models.Model): + user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) + prediction = models.ForeignKey("Prediction", on_delete=models.CASCADE) + created_at = models.DateTimeField() + class Satellite(models.Model): - user = models.ForeignKey( - get_user_model(), on_delete=models.CASCADE, default=0) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=100) - metadata = models.JSONField(blank=True, default=dict) - image = models.ImageField( - upload_to='satellite_images/', blank=True, null=True) - created_at = models.DateTimeField(auto_now_add=True) - class TelemetryPacket(models.Model): - user = models.ForeignKey( - get_user_model(), on_delete=models.CASCADE, default=0) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - satellite = models.ForeignKey( - Satellite, on_delete=models.CASCADE, related_name="telemetry") + satellite = models.ForeignKey(Satellite, on_delete=models.CASCADE, related_name="telemetry") timestamp = models.BigIntegerField() # unix time - lat = models.FloatField(default=0.0) - lon = models.FloatField(default=0.0) - alt = models.FloatField(default=0.0) - payload = models.JSONField(blank=True, default=dict) - raw_data = models.JSONField(blank=True, default=dict) - created_at = models.DateTimeField(auto_now_add=True) - - -class PreditctionTemplate(models.Model): - user = models.ForeignKey( - get_user_model(), on_delete=models.CASCADE, default=0) - name = models.CharField(max_length=100) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - template_data = models.JSONField(blank=True, default=dict) - is_default = models.BooleanField(default=False) - - class Meta: - unique_together = ('user', 'name') - - -class SavedPoint(models.Model): - user = models.ForeignKey( - get_user_model(), on_delete=models.CASCADE, default=0) - name = models.CharField(max_length=100) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - lat = models.FloatField(default=0.0) - lon = models.FloatField(default=0.0) - alt = models.FloatField(default=0.0) - is_default = models.BooleanField(default=False) - - class Meta: - unique_together = ('user', 'name') - - -class SavedRateProfile(models.Model): - user = models.ForeignKey( - get_user_model(), on_delete=models.CASCADE, default=0) - name = models.CharField(max_length=100) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - rate_profile_data = models.JSONField(blank=True, default=dict) - is_default = models.BooleanField(default=False) - - class Meta: - unique_together = ('user', 'name') \ No newline at end of file + lat = models.FloatField() + lon = models.FloatField() + alt = models.FloatField() + payload = models.JSONField(null=True, blank=True) + created_at = models.DateTimeField(auto_now_add=True) \ No newline at end of file diff --git a/api/views.py b/api/views.py index 8c46851..8c1469c 100644 --- a/api/views.py +++ b/api/views.py @@ -2,7 +2,7 @@ from rest_framework import status, generics, permissions from rest_framework.response import Response from rest_framework.views import APIView from django.utils import timezone -from .models import Prediction, User +from .models import Prediction, User, UserPrediction from .serializers import PredictionSerializer, PredictionRequestSerializer, PredictionListSerializer, PredictionDetailSerializer from rest_framework.permissions import IsAuthenticated import requests @@ -57,7 +57,8 @@ class PredictionCreateView(APIView): print("Tawhiri error:", str(e), e.response.text if e.response else "no response") return Response({"error": f"Tawhiri error: {str(e)}"}, status=status.HTTP_502_BAD_GATEWAY) - prediction = Prediction.objects.create(result=prediction_result, user=request.user, request=validated_data) + prediction = Prediction.objects.create(result=prediction_result) + UserPrediction.objects.create(user=request.user, prediction=prediction, created_at=timezone.now()) return Response({ "id": prediction.id, "created_at": prediction.created_at, @@ -79,7 +80,7 @@ class PredictionListView(APIView): return Response({'detail': 'Access to this satellite is forbidden.'}, status=403) filters = { - 'id__in': Prediction.objects.filter(user=user).values_list('prediction_id', flat=True), + 'id__in': UserPrediction.objects.filter(user=user).values_list('prediction_id', flat=True), 'deleted_at__isnull': True } print(filters) @@ -102,7 +103,8 @@ class PredictionHistoryListView(generics.ListAPIView): def get_queryset(self): return Prediction.objects.filter( - user=self.request.user, + id__in=UserPrediction.objects.filter(user=self.request.user).values_list('prediction_id', flat=True), + deleted_at__isnull=True ) @@ -113,7 +115,8 @@ class PredictionHistoryDetailView(generics.RetrieveAPIView): def get_queryset(self): return Prediction.objects.filter( - user=self.request.user, + id__in=UserPrediction.objects.filter(user=self.request.user).values_list('prediction_id', flat=True), + deleted_at__isnull=True ) @@ -123,9 +126,15 @@ class PredictionHistoryDeleteView(generics.DestroyAPIView): def get_queryset(self): return Prediction.objects.filter( - user=self.request.user, + id__in=UserPrediction.objects.filter(user=self.request.user).values_list('prediction_id', flat=True), + deleted_at__isnull=True ) + def perform_destroy(self, instance): + instance.deleted_at = timezone.now() + instance.save() + + class TelemetryListCreateView(generics.ListCreateAPIView): serializer_class = TelemetryPacketSerializer diff --git a/requirements.txt b/requirements.txt index 72cda28..ad39d85 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ psycopg2-binary drf-spectacular requests django-cors-headers -Pillow