unfinished logging
This commit is contained in:
parent
94501bf986
commit
43ccf7fb34
10 changed files with 117 additions and 50 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,9 +1,12 @@
|
||||||
# Generated by Django 4.2.20 on 2025-04-05 15:24
|
# Generated by Django 5.1.7 on 2025-04-05 16:49
|
||||||
|
|
||||||
|
import django.contrib.auth.models
|
||||||
|
import django.contrib.auth.validators
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import uuid
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
@ -11,20 +14,10 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
('auth', '0012_alter_user_first_name_max_length'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
|
||||||
name='Prediction',
|
|
||||||
fields=[
|
|
||||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('result', models.JSONField()),
|
|
||||||
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Satellite',
|
name='Satellite',
|
||||||
fields=[
|
fields=[
|
||||||
|
|
@ -33,18 +26,41 @@ class Migration(migrations.Migration):
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='User',
|
name='Prediction',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('result', models.JSONField()),
|
||||||
|
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
||||||
|
('satellite', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='predictions', to='api.satellite')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='UserPrediction',
|
name='User',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('created_at', models.DateTimeField()),
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
('prediction', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.prediction')),
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||||
|
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||||
|
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||||
|
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||||
|
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||||
|
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||||
|
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||||
|
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||||
|
('satellites', models.ManyToManyField(related_name='users', to='api.satellite')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'user',
|
||||||
|
'verbose_name_plural': 'users',
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
managers=[
|
||||||
|
('objects', django.contrib.auth.models.UserManager()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
|
|
@ -60,4 +76,13 @@ class Migration(migrations.Migration):
|
||||||
('satellite', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='telemetry', to='api.satellite')),
|
('satellite', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='telemetry', to='api.satellite')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserPrediction',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField()),
|
||||||
|
('prediction', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.prediction')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
import uuid
|
import uuid
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
class User(models.Model):
|
from django.contrib.auth.models import AbstractUser
|
||||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
||||||
|
class User(AbstractUser):
|
||||||
|
satellites = models.ManyToManyField("Satellite", related_name="users")
|
||||||
|
|
||||||
|
|
||||||
class Prediction(models.Model):
|
class Prediction(models.Model):
|
||||||
|
satellite = models.ForeignKey('Satellite', on_delete=models.CASCADE, related_name='predictions', null=True)
|
||||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
@ -12,7 +16,6 @@ class Prediction(models.Model):
|
||||||
deleted_at = models.DateTimeField(null=True, blank=True)
|
deleted_at = models.DateTimeField(null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserPrediction(models.Model):
|
class UserPrediction(models.Model):
|
||||||
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||||
prediction = models.ForeignKey("Prediction", on_delete=models.CASCADE)
|
prediction = models.ForeignKey("Prediction", on_delete=models.CASCADE)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from rest_framework.authtoken.views import obtain_auth_token
|
||||||
from .views import TelemetryListCreateView
|
from .views import TelemetryListCreateView
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('predictions', PredictionCreateView.as_view(), name='create_prediction'),
|
path('predictions', PredictionCreateView.as_view(), name='create_prediction'),
|
||||||
path('predictions', PredictionListView.as_view(), name='get_predictions'),
|
path('predictions/list/', PredictionListView.as_view(), name='get_predictions'),
|
||||||
path('token', obtain_auth_token, name = 'get_token'),
|
path('token', obtain_auth_token, name = 'get_token'),
|
||||||
path("history", PredictionHistoryListView.as_view(), name='view_history_list'),
|
path("history", PredictionHistoryListView.as_view(), name='view_history_list'),
|
||||||
path("history/<uuid:pk>/", PredictionHistoryDetailView.as_view(), name='view_history_detail'),
|
path("history/<uuid:pk>/", PredictionHistoryDetailView.as_view(), name='view_history_detail'),
|
||||||
|
|
|
||||||
46
api/views.py
46
api/views.py
|
|
@ -20,6 +20,9 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentica
|
||||||
from django.contrib.auth import authenticate, login, logout
|
from django.contrib.auth import authenticate, login, logout
|
||||||
import json
|
import json
|
||||||
from django.middleware.csrf import get_token
|
from django.middleware.csrf import get_token
|
||||||
|
from rest_framework.decorators import api_view, permission_classes, authentication_classes
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
from django.utils.dateparse import parse_datetime
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
@ -50,7 +53,6 @@ class PredictionCreateView(APIView):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
prediction_result = TawhiriClient.get_prediction(validated_data)
|
prediction_result = TawhiriClient.get_prediction(validated_data)
|
||||||
print(prediction_result)
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
print("Tawhiri error:", str(e), e.response.text if e.response else "no response")
|
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)
|
return Response({"error": f"Tawhiri error: {str(e)}"}, status=status.HTTP_502_BAD_GATEWAY)
|
||||||
|
|
@ -65,20 +67,36 @@ class PredictionCreateView(APIView):
|
||||||
|
|
||||||
|
|
||||||
class PredictionListView(APIView):
|
class PredictionListView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
user_id = request.query_params.get('user_id')
|
user = request.user
|
||||||
|
satellite_id = request.query_params.get('satellite_id')
|
||||||
created_from = request.query_params.get('created_from')
|
created_from = request.query_params.get('created_from')
|
||||||
created_till = request.query_params.get('created_till')
|
created_till = request.query_params.get('created_till')
|
||||||
|
|
||||||
predictions = Prediction.objects.filter(
|
# Проверка доступа к спутнику
|
||||||
id__in=UserPrediction.objects.filter(user_id=user_id).values_list('prediction_id'),
|
if satellite_id and not user.satellites.filter(id=satellite_id).exists():
|
||||||
created_at__gte=created_from,
|
return Response({'detail': 'Access to this satellite is forbidden.'}, status=403)
|
||||||
created_at__lte=created_till,
|
|
||||||
deleted_at__isnull=True
|
filters = {
|
||||||
)
|
'id__in': UserPrediction.objects.filter(user=user).values_list('prediction_id', flat=True),
|
||||||
|
'deleted_at__isnull': True
|
||||||
|
}
|
||||||
|
print(filters)
|
||||||
|
print(Prediction.objects.filter(**filters))
|
||||||
|
if created_from:
|
||||||
|
filters['created_at__gte'] = parse_datetime(created_from)
|
||||||
|
if created_till:
|
||||||
|
filters['created_at__lte'] = parse_datetime(created_till)
|
||||||
|
if satellite_id:
|
||||||
|
filters['satellite_id'] = satellite_id
|
||||||
|
|
||||||
|
predictions = Prediction.objects.filter(**filters)
|
||||||
return Response(PredictionSerializer(predictions, many=True).data)
|
return Response(PredictionSerializer(predictions, many=True).data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PredictionHistoryListView(generics.ListAPIView):
|
class PredictionHistoryListView(generics.ListAPIView):
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
serializer_class = PredictionListSerializer
|
serializer_class = PredictionListSerializer
|
||||||
|
|
@ -172,12 +190,20 @@ class WhoAmIView(APIView):
|
||||||
return JsonResponse({'username': request.user.username})
|
return JsonResponse({'username': request.user.username})
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(methods=["GET"], description="Get CSRF token")
|
||||||
|
@api_view(["GET"])
|
||||||
|
@permission_classes([AllowAny])
|
||||||
def get_csrf(request):
|
def get_csrf(request):
|
||||||
response = JsonResponse({'detail': 'CSRF cookie set'})
|
response = JsonResponse({'detail': 'CSRF cookie set'})
|
||||||
response['X-CSRFToken'] = get_token(request)
|
response['X-CSRFToken'] = get_token(request)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(methods=["POST"], description="Login user")
|
||||||
|
@csrf_exempt
|
||||||
|
@api_view(["POST"])
|
||||||
|
@authentication_classes([])
|
||||||
|
@permission_classes([AllowAny])
|
||||||
def login_view(request):
|
def login_view(request):
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
username = data.get('username')
|
username = data.get('username')
|
||||||
|
|
@ -187,7 +213,6 @@ def login_view(request):
|
||||||
return JsonResponse({'detail': 'Please provide username and password.'}, status=400)
|
return JsonResponse({'detail': 'Please provide username and password.'}, status=400)
|
||||||
|
|
||||||
user = authenticate(username=username, password=password)
|
user = authenticate(username=username, password=password)
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
return JsonResponse({'detail': 'Invalid credentials.'}, status=400)
|
return JsonResponse({'detail': 'Invalid credentials.'}, status=400)
|
||||||
|
|
||||||
|
|
@ -195,6 +220,9 @@ def login_view(request):
|
||||||
return JsonResponse({'detail': 'Successfully logged in.'})
|
return JsonResponse({'detail': 'Successfully logged in.'})
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(methods=["POST"], description="Logout user")
|
||||||
|
@api_view(["POST"])
|
||||||
|
@permission_classes([AllowAny])
|
||||||
def logout_view(request):
|
def logout_view(request):
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
return JsonResponse({'detail': 'You\'re not logged in.'}, status=400)
|
return JsonResponse({'detail': 'You\'re not logged in.'}, status=400)
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -89,14 +89,22 @@ WSGI_APPLICATION = 'testapi.wsgi.application'
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
'NAME': os.environ.get("DB_NAME", "drfapi"),
|
'NAME': 'drfapi', # Your database name
|
||||||
'USER': os.environ.get("DB_USER", "postgres"),
|
'USER': 'postgres', # Your PostgreSQL username
|
||||||
'PASSWORD': os.environ.get("DB_PASSWORD", "1235"),
|
'PASSWORD': '1235', # Your PostgreSQL password
|
||||||
'HOST': os.environ.get("DB_HOST", "localhost"),
|
'HOST': 'localhost', # Or your DB server's IP
|
||||||
'PORT': os.environ.get("DB_PORT", "5432"),
|
'PORT': '5432', # Default PostgreSQL port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,27 +148,30 @@ STATIC_URL = 'static/'
|
||||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
AUTH_USER_MODEL = 'api.User'
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
# ВАШИ НАСТРОЙКИ
|
|
||||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||||
'PAGE_SIZE': 100,
|
'PAGE_SIZE': 100,
|
||||||
|
|
||||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||||
|
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||||
'rest_framework.authentication.TokenAuthentication',
|
'rest_framework.authentication.TokenAuthentication',
|
||||||
|
'rest_framework.authentication.SessionAuthentication',
|
||||||
],
|
],
|
||||||
|
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
'rest_framework.permissions.IsAuthenticated',
|
'rest_framework.permissions.IsAuthenticated',
|
||||||
# 'rest_framework.permissions.AllowAny',
|
# 'rest_framework.permissions.AllowAny',
|
||||||
],
|
],
|
||||||
|
|
||||||
'DEFAULT_RENDERER_CLASSES': [
|
'DEFAULT_RENDERER_CLASSES': [
|
||||||
'rest_framework.renderers.JSONRenderer',
|
'rest_framework.renderers.JSONRenderer',
|
||||||
],
|
],
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
|
||||||
'rest_framework.authentication.SessionAuthentication',
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CSRF_COOKIE_SAMESITE = 'Lax'
|
CSRF_COOKIE_SAMESITE = 'Lax'
|
||||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||||
CSRF_COOKIE_HTTPONLY = True
|
CSRF_COOKIE_HTTPONLY = True
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue