UPDATE
This commit is contained in:
@@ -3,11 +3,16 @@ Account API module.
|
||||
CRUD endpoints for user account profile.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
|
||||
from auth.serializers import AuthUserSerializer
|
||||
from config.swagger import code_response
|
||||
from .serializers import UpdateProfileSerializer
|
||||
|
||||
|
||||
@@ -25,6 +30,13 @@ def _auth_user_to_data(user):
|
||||
}
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
patch=extend_schema(
|
||||
tags=["Account"],
|
||||
request=UpdateProfileSerializer,
|
||||
responses={200: code_response("ProfileUpdateResponse", data=AuthUserSerializer())},
|
||||
),
|
||||
)
|
||||
class ProfileView(APIView):
|
||||
"""
|
||||
PATCH /api/account/profile/
|
||||
@@ -63,6 +75,26 @@ class ProfileView(APIView):
|
||||
)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
get=extend_schema(
|
||||
tags=["Account"],
|
||||
responses={200: code_response("AccountGetResponse", data=serializers.JSONField())},
|
||||
),
|
||||
post=extend_schema(
|
||||
tags=["Account"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: code_response("AccountCreateResponse")},
|
||||
),
|
||||
patch=extend_schema(
|
||||
tags=["Account"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: code_response("AccountUpdateResponse")},
|
||||
),
|
||||
delete=extend_schema(
|
||||
tags=["Account"],
|
||||
responses={200: code_response("AccountDeleteResponse")},
|
||||
),
|
||||
)
|
||||
class AccountView(APIView):
|
||||
"""
|
||||
Account CRUD endpoints. Dispatch by HTTP method and path (uuid for detail/update/delete).
|
||||
|
||||
@@ -5,13 +5,17 @@ from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.core.signing import BadSignature, SignatureExpired, TimestampSigner
|
||||
from django.db import IntegrityError
|
||||
from rest_framework import serializers
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from account.models import User
|
||||
from config.swagger import code_response
|
||||
from .serializers import (
|
||||
AuthUserSerializer,
|
||||
LoginSerializer,
|
||||
RegisterSerializer,
|
||||
RequestOTPSerializer,
|
||||
@@ -38,6 +42,16 @@ def _auth_user_to_data(user):
|
||||
}
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
post=extend_schema(
|
||||
tags=["Authentication"],
|
||||
request=RegisterSerializer,
|
||||
responses={
|
||||
201: code_response("RegisterResponse", data=AuthUserSerializer(), token=True),
|
||||
400: code_response("RegisterErrorResponse"),
|
||||
},
|
||||
),
|
||||
)
|
||||
class RegisterView(APIView):
|
||||
"""
|
||||
POST /api/auth/register/
|
||||
@@ -92,6 +106,16 @@ class RegisterView(APIView):
|
||||
)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
post=extend_schema(
|
||||
tags=["Authentication"],
|
||||
request=LoginSerializer,
|
||||
responses={
|
||||
200: code_response("LoginResponse", data=AuthUserSerializer(), token=True),
|
||||
401: code_response("LoginErrorResponse"),
|
||||
},
|
||||
),
|
||||
)
|
||||
class LoginView(APIView):
|
||||
"""
|
||||
POST /api/auth/login/
|
||||
@@ -131,6 +155,23 @@ class LoginView(APIView):
|
||||
)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
post=extend_schema(
|
||||
tags=["Authentication"],
|
||||
request=RequestOTPSerializer,
|
||||
responses={
|
||||
200: code_response(
|
||||
"RequestOtpResponse",
|
||||
extra_fields={
|
||||
"token": serializers.CharField(),
|
||||
"sms_warning": serializers.CharField(required=False),
|
||||
"debug_otp": serializers.CharField(required=False),
|
||||
},
|
||||
),
|
||||
400: code_response("RequestOtpErrorResponse"),
|
||||
},
|
||||
),
|
||||
)
|
||||
class AuthenticationView(APIView):
|
||||
"""
|
||||
Single view for auth flows: request-otp and verify-otp.
|
||||
|
||||
@@ -35,6 +35,8 @@ INSTALLED_APPS = [
|
||||
"fertilization_recommendation",
|
||||
"farm_ai_assistant",
|
||||
"rest_framework",
|
||||
"drf_spectacular",
|
||||
"drf_spectacular_sidecar",
|
||||
"corsheaders",
|
||||
]
|
||||
|
||||
@@ -113,6 +115,18 @@ REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
],
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
}
|
||||
|
||||
SPECTACULAR_SETTINGS = {
|
||||
"TITLE": "CropLogic API",
|
||||
"DESCRIPTION": "Swagger/OpenAPI documentation for all CropLogic API endpoints.",
|
||||
"VERSION": "1.0.0",
|
||||
"SERVE_INCLUDE_SCHEMA": False,
|
||||
"SWAGGER_UI_DIST": "SIDECAR",
|
||||
"SWAGGER_UI_FAVICON_HREF": "SIDECAR",
|
||||
"REDOC_DIST": "SIDECAR",
|
||||
"SCHEMA_PATH_PREFIX": r"/api/",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from drf_spectacular.utils import inline_serializer
|
||||
|
||||
|
||||
class TokenPairSerializer(serializers.Serializer):
|
||||
access = serializers.CharField()
|
||||
refresh = serializers.CharField()
|
||||
|
||||
|
||||
def code_response(name, data=None, token=False, extra_fields=None):
|
||||
fields = {
|
||||
"code": serializers.IntegerField(),
|
||||
"msg": serializers.CharField(),
|
||||
}
|
||||
if data is not None:
|
||||
fields["data"] = data
|
||||
if token:
|
||||
fields["token"] = TokenPairSerializer()
|
||||
if extra_fields:
|
||||
fields.update(extra_fields)
|
||||
return inline_serializer(name=name, fields=fields)
|
||||
|
||||
|
||||
def status_response(name, data=None):
|
||||
fields = {
|
||||
"status": serializers.CharField(default="success"),
|
||||
}
|
||||
if data is not None:
|
||||
fields["data"] = data
|
||||
return inline_serializer(name=name, fields=fields)
|
||||
@@ -1,8 +1,12 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
|
||||
path("api/docs/swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"),
|
||||
path("api/docs/redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"),
|
||||
path("api/auth/", include("auth.urls")),
|
||||
path("api/account/", include("account.urls")),
|
||||
path("api/sensor-hub/", include("sensor_hub.urls")),
|
||||
|
||||
+60
-31
@@ -1,16 +1,17 @@
|
||||
"""
|
||||
Crop Zoning API views.
|
||||
Plain Django only; no DRF. No database. All responses are static mock data.
|
||||
No database. All responses are static mock data.
|
||||
Response format: {"status": "success", "data": <payload>}. HTTP 200 only.
|
||||
No processing, validation, or use of input parameters in responses.
|
||||
CSRF exempt on POST so frontend can call without token.
|
||||
"""
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from config.swagger import status_response
|
||||
from .mock_data import (
|
||||
AREA_RESPONSE_DATA,
|
||||
PRODUCTS_RESPONSE_DATA,
|
||||
@@ -22,7 +23,7 @@ from .mock_data import (
|
||||
)
|
||||
|
||||
|
||||
class AreaView(View):
|
||||
class AreaView(APIView):
|
||||
"""
|
||||
GET endpoint for fixed land area (GeoJSON polygon).
|
||||
|
||||
@@ -40,14 +41,18 @@ class AreaView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
responses={200: status_response("CropZoningAreaResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": AREA_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class ProductsView(View):
|
||||
class ProductsView(APIView):
|
||||
"""
|
||||
GET endpoint for list of crop products and colors.
|
||||
|
||||
@@ -67,15 +72,18 @@ class ProductsView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
responses={200: status_response("CropZoningProductsResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": PRODUCTS_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ZonesInitialView(View):
|
||||
class ZonesInitialView(APIView):
|
||||
"""
|
||||
POST endpoint for initial zone data (map + hover/tooltip).
|
||||
|
||||
@@ -99,15 +107,19 @@ class ZonesInitialView(View):
|
||||
not used in the response.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("CropZoningZonesInitialResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": ZONES_INITIAL_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ZonesWaterNeedView(View):
|
||||
class ZonesWaterNeedView(APIView):
|
||||
"""
|
||||
POST endpoint for water need per zone (water need layer).
|
||||
|
||||
@@ -126,15 +138,19 @@ class ZonesWaterNeedView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("CropZoningZonesWaterNeedResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": ZONES_WATER_NEED_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ZonesSoilQualityView(View):
|
||||
class ZonesSoilQualityView(APIView):
|
||||
"""
|
||||
POST endpoint for soil quality per zone (soil quality layer).
|
||||
|
||||
@@ -153,15 +169,19 @@ class ZonesSoilQualityView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("CropZoningZonesSoilQualityResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": ZONES_SOIL_QUALITY_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ZonesCultivationRiskView(View):
|
||||
class ZonesCultivationRiskView(APIView):
|
||||
"""
|
||||
POST endpoint for cultivation risk per zone (cultivation risk layer).
|
||||
|
||||
@@ -180,14 +200,19 @@ class ZonesCultivationRiskView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("CropZoningZonesCultivationRiskResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": ZONES_CULTIVATION_RISK_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class ZoneDetailsView(View):
|
||||
class ZoneDetailsView(APIView):
|
||||
"""
|
||||
GET endpoint for zone detail data (detail panel after click).
|
||||
|
||||
@@ -208,9 +233,13 @@ class ZoneDetailsView(View):
|
||||
not used in the response.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Crop Zoning"],
|
||||
responses={200: status_response("CropZoningZoneDetailsResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request, zone_id):
|
||||
data = ZONE_DETAILS_BY_ID.get(zone_id, ZONE_DETAILS_BY_ID["zone-0"])
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": data},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@@ -4,12 +4,27 @@ No database connection. All responses use static mock data from mock_data.py.
|
||||
"""
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework import serializers
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
|
||||
from config.swagger import code_response
|
||||
from .mock_data import ALL_CARDS, CONFIG
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
get=extend_schema(
|
||||
tags=["Farm Dashboard"],
|
||||
responses={200: code_response("FarmDashboardConfigGetResponse", data=serializers.JSONField())},
|
||||
),
|
||||
patch=extend_schema(
|
||||
tags=["Farm Dashboard"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: code_response("FarmDashboardConfigPatchResponse", data=serializers.JSONField())},
|
||||
),
|
||||
)
|
||||
class FarmDashboardConfigView(APIView):
|
||||
"""
|
||||
Farm dashboard config endpoints: GET and PATCH.
|
||||
@@ -27,6 +42,12 @@ class FarmDashboardConfigView(APIView):
|
||||
return Response({"code": 200, "msg": "OK", "data": CONFIG}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
get=extend_schema(
|
||||
tags=["Farm Dashboard"],
|
||||
responses={200: code_response("FarmDashboardCardsResponse", data=serializers.JSONField())},
|
||||
),
|
||||
)
|
||||
class FarmDashboardCardsView(APIView):
|
||||
"""
|
||||
Farm dashboard cards endpoint: GET.
|
||||
|
||||
+24
-15
@@ -1,20 +1,21 @@
|
||||
"""
|
||||
Farm AI Assistant API views.
|
||||
Plain Django only; no DRF. No database. All responses are static mock data.
|
||||
No database. All responses are static mock data.
|
||||
Response format: {"status": "success", "data": <payload>}. HTTP 200 only.
|
||||
No processing, validation, or use of input parameters in responses.
|
||||
CSRF exempt on POST so frontend can call without token.
|
||||
"""
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from config.swagger import status_response
|
||||
from .mock_data import CHAT_RESPONSE_DATA, CONTEXT_RESPONSE_DATA
|
||||
|
||||
|
||||
class ContextView(View):
|
||||
class ContextView(APIView):
|
||||
"""
|
||||
GET endpoint for farm context (Farm AI Assistant bar).
|
||||
|
||||
@@ -34,15 +35,18 @@ class ContextView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Farm AI Assistant"],
|
||||
responses={200: status_response("FarmAiAssistantContextResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": CONTEXT_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ChatView(View):
|
||||
class ChatView(APIView):
|
||||
"""
|
||||
POST endpoint for Farm AI Assistant chat (send message, get structured reply).
|
||||
|
||||
@@ -70,8 +74,13 @@ class ChatView(View):
|
||||
not used in the response.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
{"status": "success", "data": CHAT_RESPONSE_DATA},
|
||||
status=200,
|
||||
@extend_schema(
|
||||
tags=["Farm AI Assistant"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("FarmAiAssistantChatResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return Response(
|
||||
{"status": "success", "data": CHAT_RESPONSE_DATA},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
"""
|
||||
Fertilization Recommendation API views.
|
||||
Plain Django only; no DRF. No database. All responses are static mock data.
|
||||
No database. All responses are static mock data.
|
||||
Response format: {"status": "success", "data": <payload>}. HTTP 200 only.
|
||||
No processing, validation, or use of input parameters in responses.
|
||||
CSRF exempt on POST so frontend can call without token.
|
||||
"""
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from config.swagger import status_response
|
||||
from .mock_data import CONFIG_RESPONSE_DATA, RECOMMEND_RESPONSE_DATA
|
||||
|
||||
|
||||
class ConfigView(View):
|
||||
class ConfigView(APIView):
|
||||
"""
|
||||
GET endpoint for fertilization config (farm data, growth stages, crop options).
|
||||
|
||||
@@ -34,15 +35,18 @@ class ConfigView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Fertilization Recommendation"],
|
||||
responses={200: status_response("FertilizationConfigResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": CONFIG_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class RecommendView(View):
|
||||
class RecommendView(APIView):
|
||||
"""
|
||||
POST endpoint for fertilization recommendation.
|
||||
|
||||
@@ -64,8 +68,13 @@ class RecommendView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
{"status": "success", "data": RECOMMEND_RESPONSE_DATA},
|
||||
status=200,
|
||||
@extend_schema(
|
||||
tags=["Fertilization Recommendation"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("FertilizationRecommendResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return Response(
|
||||
{"status": "success", "data": RECOMMEND_RESPONSE_DATA},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
"""
|
||||
Irrigation Recommendation API views.
|
||||
Plain Django only; no DRF. No database. All responses are static mock data.
|
||||
No database. All responses are static mock data.
|
||||
Response format: {"status": "success", "data": <payload>}. HTTP 200 only.
|
||||
No processing, validation, or use of input parameters in responses.
|
||||
CSRF exempt on POST so frontend can call without token.
|
||||
"""
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from config.swagger import status_response
|
||||
from .mock_data import CONFIG_RESPONSE_DATA, RECOMMEND_RESPONSE_DATA
|
||||
|
||||
|
||||
class ConfigView(View):
|
||||
class ConfigView(APIView):
|
||||
"""
|
||||
GET endpoint for irrigation config (farm info and crop options).
|
||||
|
||||
@@ -34,15 +35,18 @@ class ConfigView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation Recommendation"],
|
||||
responses={200: status_response("IrrigationConfigResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(
|
||||
return Response(
|
||||
{"status": "success", "data": CONFIG_RESPONSE_DATA},
|
||||
status=200,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class RecommendView(View):
|
||||
class RecommendView(APIView):
|
||||
"""
|
||||
POST endpoint for irrigation recommendation.
|
||||
|
||||
@@ -64,8 +68,13 @@ class RecommendView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
{"status": "success", "data": RECOMMEND_RESPONSE_DATA},
|
||||
status=200,
|
||||
@extend_schema(
|
||||
tags=["Irrigation Recommendation"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("IrrigationRecommendResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return Response(
|
||||
{"status": "success", "data": RECOMMEND_RESPONSE_DATA},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "dashboard task queued",
|
||||
"data": {
|
||||
"task_id": "dashboard-task-123",
|
||||
"status_url": "/api/dashboard-data/dashboard-task-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "پارامتر sensor_id الزامی است.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "dashboard-task-123",
|
||||
"status": "FAILURE",
|
||||
"error": "خطا در ساخت کارتهای داشبورد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "dashboard-task-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "dashboard-task-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"current": 5,
|
||||
"total": 15,
|
||||
"card": "sensorValuesList",
|
||||
"message": "processing sensorValuesList"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "dashboard-task-123",
|
||||
"status": "SUCCESS",
|
||||
"result": {
|
||||
"sensor_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"all_cards": {
|
||||
"farmOverviewKpis": {
|
||||
"healthScore": 82,
|
||||
"activeAlerts": 2,
|
||||
"waterNeedMm": 18.4
|
||||
},
|
||||
"sensorValuesList": {
|
||||
"items": [
|
||||
{
|
||||
"label": "رطوبت خاک",
|
||||
"value": 45.2,
|
||||
"unit": "%"
|
||||
},
|
||||
{
|
||||
"label": "دما خاک",
|
||||
"value": 22.5,
|
||||
"unit": "°C"
|
||||
}
|
||||
]
|
||||
},
|
||||
"recommendationsList": {
|
||||
"items": [
|
||||
{
|
||||
"recommendation_title": "تنظیم نوبت آبیاری",
|
||||
"suggested_action": "آبیاری بعدی را صبح فردا انجام دهید.",
|
||||
"urgency_level": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "تسک توصیه کودهی در صف قرار گرفت.",
|
||||
"data": {
|
||||
"task_id": "fert-task-123",
|
||||
"status_url": "/api/fertilization/recommend/fert-task-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"sensor_uuid": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "fert-task-123",
|
||||
"status": "FAILURE",
|
||||
"error": "خطا در دریافت توصیه کودهی."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "fert-task-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "fert-task-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"message": "در حال پردازش توصیه کودهی..."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "fert-task-123",
|
||||
"status": "SUCCESS",
|
||||
"result": {
|
||||
"plan": {
|
||||
"npkRatio": "20-20-20",
|
||||
"amountPerHectare": "150 kg/ha",
|
||||
"applicationMethod": "کودآبیاری در دو نوبت",
|
||||
"applicationInterval": "هر ۱۰ روز",
|
||||
"reasoning": "نیتروژن و پتاسیم خاک در محدوده متوسط است و گیاه در فاز رویشی نیاز تغذیهای بالاتری دارد."
|
||||
},
|
||||
"raw_response": "{\"plan\":{\"npkRatio\":\"20-20-20\"}}",
|
||||
"status": "completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,604 @@
|
||||
[
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/dashboard-data/generate/",
|
||||
"status_code": 202,
|
||||
"description": "Dashboard data task queued",
|
||||
"file": "json/mock_data/dashboard-data/generate/post_202.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/dashboard-data/generate/",
|
||||
"status_code": 400,
|
||||
"description": "Missing sensor_id",
|
||||
"file": "json/mock_data/dashboard-data/generate/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/dashboard-data/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Pending dashboard task",
|
||||
"file": "json/mock_data/dashboard-data/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/dashboard-data/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Dashboard task in progress",
|
||||
"file": "json/mock_data/dashboard-data/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/dashboard-data/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Successful dashboard task",
|
||||
"file": "json/mock_data/dashboard-data/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/dashboard-data/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Failed dashboard task",
|
||||
"file": "json/mock_data/dashboard-data/status/get_200_failure.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/fertilization/recommend/",
|
||||
"status_code": 202,
|
||||
"description": "Fertilization task queued",
|
||||
"file": "json/mock_data/fertilization/recommend/post_202.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/fertilization/recommend/",
|
||||
"status_code": 400,
|
||||
"description": "Validation error",
|
||||
"file": "json/mock_data/fertilization/recommend/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Fertilization status pending",
|
||||
"file": "json/mock_data/fertilization/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Fertilization status progress",
|
||||
"file": "json/mock_data/fertilization/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Fertilization status success",
|
||||
"file": "json/mock_data/fertilization/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Fertilization status failure",
|
||||
"file": "json/mock_data/fertilization/status/get_200_failure.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/",
|
||||
"status_code": 200,
|
||||
"description": "List irrigation methods",
|
||||
"file": "json/mock_data/irrigation/methods/get_200.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/irrigation/",
|
||||
"status_code": 201,
|
||||
"description": "Create irrigation method",
|
||||
"file": "json/mock_data/irrigation/methods/post_201.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/irrigation/",
|
||||
"status_code": 400,
|
||||
"description": "Irrigation create validation error",
|
||||
"file": "json/mock_data/irrigation/methods/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/irrigation/recommend/",
|
||||
"status_code": 202,
|
||||
"description": "Irrigation recommendation task queued",
|
||||
"file": "json/mock_data/irrigation/recommend/post_202.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/irrigation/recommend/",
|
||||
"status_code": 400,
|
||||
"description": "Irrigation recommendation validation error",
|
||||
"file": "json/mock_data/irrigation/recommend/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation recommendation status pending",
|
||||
"file": "json/mock_data/irrigation/recommend/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation recommendation status progress",
|
||||
"file": "json/mock_data/irrigation/recommend/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation recommendation status success",
|
||||
"file": "json/mock_data/irrigation/recommend/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation recommendation status failure",
|
||||
"file": "json/mock_data/irrigation/recommend/status/get_200_failure.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation method get success",
|
||||
"file": "json/mock_data/irrigation/method-detail/get_200.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Irrigation method get not found",
|
||||
"file": "json/mock_data/irrigation/method-detail/get_404.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation method put success",
|
||||
"file": "json/mock_data/irrigation/method-detail/put_200.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 400,
|
||||
"description": "Irrigation method put validation error",
|
||||
"file": "json/mock_data/irrigation/method-detail/put_400.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Irrigation method put not found",
|
||||
"file": "json/mock_data/irrigation/method-detail/put_404.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Irrigation method patch success",
|
||||
"file": "json/mock_data/irrigation/method-detail/patch_200.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 400,
|
||||
"description": "Irrigation method patch validation error",
|
||||
"file": "json/mock_data/irrigation/method-detail/patch_400.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Irrigation method patch not found",
|
||||
"file": "json/mock_data/irrigation/method-detail/patch_404.json"
|
||||
},
|
||||
{
|
||||
"method": "DELETE",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Delete irrigation method",
|
||||
"file": "json/mock_data/irrigation/method-detail/delete_200.json"
|
||||
},
|
||||
{
|
||||
"method": "DELETE",
|
||||
"path": "/api/irrigation/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Delete irrigation method not found",
|
||||
"file": "json/mock_data/irrigation/method-detail/delete_404.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/",
|
||||
"status_code": 200,
|
||||
"description": "Soil data served from database",
|
||||
"file": "json/mock_data/soil-data/get_200_database.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/",
|
||||
"status_code": 202,
|
||||
"description": "Soil data fetch task queued",
|
||||
"file": "json/mock_data/soil-data/get_202_queued.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/",
|
||||
"status_code": 400,
|
||||
"description": "Soil data validation error",
|
||||
"file": "json/mock_data/soil-data/get_400.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/soil-data/",
|
||||
"status_code": 200,
|
||||
"description": "Soil data POST served from database",
|
||||
"file": "json/mock_data/soil-data/post_200_database.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/soil-data/",
|
||||
"status_code": 202,
|
||||
"description": "Soil data POST task queued",
|
||||
"file": "json/mock_data/soil-data/post_202_queued.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/soil-data/",
|
||||
"status_code": 400,
|
||||
"description": "Soil data POST validation error",
|
||||
"file": "json/mock_data/soil-data/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Soil task status pending",
|
||||
"file": "json/mock_data/soil-data/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Soil task status progress",
|
||||
"file": "json/mock_data/soil-data/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Soil task status success",
|
||||
"file": "json/mock_data/soil-data/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Soil task status failure",
|
||||
"file": "json/mock_data/soil-data/status/get_200_failure.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/plants/",
|
||||
"status_code": 200,
|
||||
"description": "List plants",
|
||||
"file": "json/mock_data/plant/list-get_200.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/plants/",
|
||||
"status_code": 201,
|
||||
"description": "Create plant",
|
||||
"file": "json/mock_data/plant/create-post_201.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/plants/",
|
||||
"status_code": 400,
|
||||
"description": "Plant create validation error",
|
||||
"file": "json/mock_data/plant/create-post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Plant detail get success",
|
||||
"file": "json/mock_data/plant/detail-get_200.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Plant detail get not found",
|
||||
"file": "json/mock_data/plant/detail-get_404.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Plant detail put success",
|
||||
"file": "json/mock_data/plant/detail-put_200.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 400,
|
||||
"description": "Plant detail put validation error",
|
||||
"file": "json/mock_data/plant/detail-put_400.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Plant detail put not found",
|
||||
"file": "json/mock_data/plant/detail-put_404.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Plant detail patch success",
|
||||
"file": "json/mock_data/plant/detail-patch_200.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 400,
|
||||
"description": "Plant detail patch validation error",
|
||||
"file": "json/mock_data/plant/detail-patch_400.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Plant detail patch not found",
|
||||
"file": "json/mock_data/plant/detail-patch_404.json"
|
||||
},
|
||||
{
|
||||
"method": "DELETE",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 200,
|
||||
"description": "Delete plant success",
|
||||
"file": "json/mock_data/plant/detail-delete_200.json"
|
||||
},
|
||||
{
|
||||
"method": "DELETE",
|
||||
"path": "/api/plants/{pk}/",
|
||||
"status_code": 404,
|
||||
"description": "Delete plant not found",
|
||||
"file": "json/mock_data/plant/detail-delete_404.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/plants/fetch-info/",
|
||||
"status_code": 200,
|
||||
"description": "Fetch plant info success",
|
||||
"file": "json/mock_data/plant/fetch-info-post_200.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/plants/fetch-info/",
|
||||
"status_code": 400,
|
||||
"description": "Fetch plant info missing name",
|
||||
"file": "json/mock_data/plant/fetch-info-post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/plants/fetch-info/",
|
||||
"status_code": 503,
|
||||
"description": "Fetch plant info service unavailable",
|
||||
"file": "json/mock_data/plant/fetch-info-post_503.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/chat/",
|
||||
"status_code": 200,
|
||||
"description": "RAG chat streaming response",
|
||||
"file": "json/mock_data/rag/chat-post_200_stream.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/chat/",
|
||||
"status_code": 400,
|
||||
"description": "Missing query",
|
||||
"file": "json/mock_data/rag/chat-post_400_missing_query.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/chat/",
|
||||
"status_code": 400,
|
||||
"description": "Invalid service id",
|
||||
"file": "json/mock_data/rag/chat-post_400_invalid_service.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/chat/",
|
||||
"status_code": 400,
|
||||
"description": "Missing user_id for service",
|
||||
"file": "json/mock_data/rag/chat-post_400_missing_user.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/recommend/irrigation/",
|
||||
"status_code": 202,
|
||||
"description": "RAG irrigation task queued",
|
||||
"file": "json/mock_data/rag/irrigation/post_202.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/recommend/irrigation/",
|
||||
"status_code": 400,
|
||||
"description": "RAG irrigation validation error",
|
||||
"file": "json/mock_data/rag/irrigation/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG irrigation status pending",
|
||||
"file": "json/mock_data/rag/irrigation/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG irrigation status progress",
|
||||
"file": "json/mock_data/rag/irrigation/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG irrigation status success",
|
||||
"file": "json/mock_data/rag/irrigation/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG irrigation status failure",
|
||||
"file": "json/mock_data/rag/irrigation/status/get_200_failure.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/recommend/fertilization/",
|
||||
"status_code": 202,
|
||||
"description": "RAG fertilization task queued",
|
||||
"file": "json/mock_data/rag/fertilization/post_202.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/rag/recommend/fertilization/",
|
||||
"status_code": 400,
|
||||
"description": "RAG fertilization validation error",
|
||||
"file": "json/mock_data/rag/fertilization/post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG fertilization status pending",
|
||||
"file": "json/mock_data/rag/fertilization/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG fertilization status progress",
|
||||
"file": "json/mock_data/rag/fertilization/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG fertilization status success",
|
||||
"file": "json/mock_data/rag/fertilization/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "RAG fertilization status failure",
|
||||
"file": "json/mock_data/rag/fertilization/status/get_200_failure.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/sensor-data/{uuid_sensor}/",
|
||||
"status_code": 200,
|
||||
"description": "Sensor update put success",
|
||||
"file": "json/mock_data/sensor-data/update-put_200.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/sensor-data/{uuid_sensor}/",
|
||||
"status_code": 400,
|
||||
"description": "Sensor update put validation error",
|
||||
"file": "json/mock_data/sensor-data/update-put_400.json"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/sensor-data/{uuid_sensor}/",
|
||||
"status_code": 404,
|
||||
"description": "Sensor update put location not found",
|
||||
"file": "json/mock_data/sensor-data/update-put_404.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/sensor-data/{uuid_sensor}/",
|
||||
"status_code": 200,
|
||||
"description": "Sensor update patch success",
|
||||
"file": "json/mock_data/sensor-data/update-patch_200.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/sensor-data/{uuid_sensor}/",
|
||||
"status_code": 400,
|
||||
"description": "Sensor update patch validation error",
|
||||
"file": "json/mock_data/sensor-data/update-patch_400.json"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/sensor-data/{uuid_sensor}/",
|
||||
"status_code": 404,
|
||||
"description": "Sensor update patch location not found",
|
||||
"file": "json/mock_data/sensor-data/update-patch_404.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/sensor-data/parameters/",
|
||||
"status_code": 201,
|
||||
"description": "Create sensor parameter",
|
||||
"file": "json/mock_data/sensor-data/parameters-post_201.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/sensor-data/parameters/",
|
||||
"status_code": 400,
|
||||
"description": "Sensor parameter validation error",
|
||||
"file": "json/mock_data/sensor-data/parameters-post_400.json"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/api/tasks/",
|
||||
"status_code": 200,
|
||||
"description": "Task trigger success",
|
||||
"file": "json/mock_data/tasks/post_200.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Task status pending",
|
||||
"file": "json/mock_data/tasks/status/get_200_pending.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Task status progress",
|
||||
"file": "json/mock_data/tasks/status/get_200_progress.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Task status success",
|
||||
"file": "json/mock_data/tasks/status/get_200_success.json"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/tasks/{task_id}/status/",
|
||||
"status_code": 200,
|
||||
"description": "Task status failure",
|
||||
"file": "json/mock_data/tasks/status/get_200_failure.json"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "روش آبیاری با موفقیت حذف شد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "روش آبیاری یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "اکثر خاکها",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "روش آبیاری یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "اکثر خاکها",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"name": [
|
||||
"This field may not be blank."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "روش آبیاری یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "اکثر خاکها",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"name": [
|
||||
"This field may not be blank."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "روش آبیاری یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "اکثر خاکها",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 201,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "اکثر خاکها",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"name": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "تسک توصیه آبیاری در صف قرار گرفت.",
|
||||
"data": {
|
||||
"task_id": "irr-task-123",
|
||||
"status_url": "/api/irrigation/recommend/irr-task-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"sensor_uuid": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "irr-task-123",
|
||||
"status": "FAILURE",
|
||||
"error": "خطا در دریافت توصیه آبیاری."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "irr-task-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "irr-task-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"message": "در حال پردازش توصیه آبیاری..."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "irr-task-123",
|
||||
"status": "SUCCESS",
|
||||
"result": {
|
||||
"plan": {
|
||||
"frequencyPerWeek": 3,
|
||||
"durationMinutes": 42,
|
||||
"bestTimeOfDay": "صبح زود",
|
||||
"moistureLevel": 68,
|
||||
"warning": "در صورت بارش موثر، نوبت سوم این هفته را حذف کنید."
|
||||
},
|
||||
"raw_response": "{\"plan\":{\"frequencyPerWeek\":3,\"durationMinutes\":42}}",
|
||||
"water_balance": {
|
||||
"daily": [
|
||||
{
|
||||
"forecast_date": "2025-03-25",
|
||||
"et0_mm": 4.7,
|
||||
"etc_mm": 5.6,
|
||||
"effective_rainfall_mm": 0.0,
|
||||
"gross_irrigation_mm": 6.2,
|
||||
"irrigation_timing": "06:00-08:00"
|
||||
}
|
||||
],
|
||||
"crop_profile": {
|
||||
"kc_initial": 0.6,
|
||||
"kc_mid": 1.15,
|
||||
"kc_end": 0.8
|
||||
},
|
||||
"active_kc": 1.15
|
||||
},
|
||||
"status": "completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 201,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "گوجهفرنگی",
|
||||
"light": "آفتاب کامل",
|
||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
||||
"soil": "لومی، غنی از مواد آلی",
|
||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
||||
"planting_season": "بهار",
|
||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
||||
"fertilizer": "کود NPK متعادل",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"name": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "گیاه با موفقیت حذف شد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "گیاه یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "گوجهفرنگی",
|
||||
"light": "آفتاب کامل",
|
||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
||||
"soil": "لومی، غنی از مواد آلی",
|
||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
||||
"planting_season": "بهار",
|
||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
||||
"fertilizer": "کود NPK متعادل",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "گیاه یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "گوجهفرنگی",
|
||||
"light": "آفتاب کامل",
|
||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
||||
"soil": "لومی، غنی از مواد آلی",
|
||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
||||
"planting_season": "بهار",
|
||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
||||
"fertilizer": "کود NPK متعادل",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"name": [
|
||||
"This field may not be blank."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "گیاه یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "گوجهفرنگی",
|
||||
"light": "آفتاب کامل",
|
||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
||||
"soil": "لومی، غنی از مواد آلی",
|
||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
||||
"planting_season": "بهار",
|
||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
||||
"fertilizer": "کود NPK متعادل",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"name": [
|
||||
"This field may not be blank."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "گیاه یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "گوجهفرنگی",
|
||||
"light": "آفتاب کامل",
|
||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
||||
"soil": "لومی، غنی از مواد آلی",
|
||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
||||
"planting_season": "بهار",
|
||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
||||
"fertilizer": "کود NPK متعادل",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "نام گیاه الزامی است.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 503,
|
||||
"msg": "سرویس API هنوز پیادهسازی نشده است.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "گوجهفرنگی",
|
||||
"light": "آفتاب کامل",
|
||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
||||
"soil": "لومی، غنی از مواد آلی",
|
||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
||||
"planting_season": "بهار",
|
||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
||||
"fertilizer": "کود NPK متعادل",
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"content_type": "text/plain; charset=utf-8",
|
||||
"body": "سلام، برای بازیابی رطوبت خاک بهتر است آبیاری صبحگاهی را تنظیم کنید."
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "service_id نامعتبر است: unknown_service"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "پارامتر query الزامی است."
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "برای این service_id، پارامتر user_id الزامی است."
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "تسک توصیه کودهی در صف قرار گرفت.",
|
||||
"data": {
|
||||
"task_id": "rag-fert-123",
|
||||
"status_url": "/api/rag/recommend/fertilization/rag-fert-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "پارامتر sensor_uuid الزامی است.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-fert-123",
|
||||
"status": "FAILURE",
|
||||
"error": "خطا در دریافت توصیه کودهی."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-fert-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-fert-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"message": "در حال پردازش توصیه کودهی..."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-fert-123",
|
||||
"status": "SUCCESS",
|
||||
"result": {
|
||||
"plan": {
|
||||
"npkRatio": "20-20-20",
|
||||
"amountPerHectare": "150 kg/ha",
|
||||
"applicationMethod": "کودآبیاری در دو نوبت",
|
||||
"applicationInterval": "هر ۱۰ روز",
|
||||
"reasoning": "نیتروژن و پتاسیم خاک در محدوده متوسط است و گیاه در فاز رویشی نیاز تغذیهای بالاتری دارد."
|
||||
},
|
||||
"raw_response": "{\"plan\":{\"npkRatio\":\"20-20-20\"}}",
|
||||
"status": "completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "تسک توصیه آبیاری در صف قرار گرفت.",
|
||||
"data": {
|
||||
"task_id": "rag-irr-123",
|
||||
"status_url": "/api/rag/recommend/irrigation/rag-irr-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "پارامتر sensor_uuid الزامی است.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-irr-123",
|
||||
"status": "FAILURE",
|
||||
"error": "خطا در دریافت توصیه آبیاری."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-irr-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-irr-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"message": "در حال پردازش توصیه آبیاری..."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "rag-irr-123",
|
||||
"status": "SUCCESS",
|
||||
"result": {
|
||||
"plan": {
|
||||
"frequencyPerWeek": 3,
|
||||
"durationMinutes": 42,
|
||||
"bestTimeOfDay": "صبح زود",
|
||||
"moistureLevel": 68,
|
||||
"warning": "در صورت بارش موثر، نوبت سوم این هفته را حذف کنید."
|
||||
},
|
||||
"raw_response": "{\"plan\":{\"frequencyPerWeek\":3,\"durationMinutes\":42}}",
|
||||
"water_balance": {
|
||||
"daily": [
|
||||
{
|
||||
"forecast_date": "2025-03-25",
|
||||
"et0_mm": 4.7,
|
||||
"etc_mm": 5.6,
|
||||
"effective_rainfall_mm": 0.0,
|
||||
"gross_irrigation_mm": 6.2,
|
||||
"irrigation_timing": "06:00-08:00"
|
||||
}
|
||||
],
|
||||
"crop_profile": {
|
||||
"kc_initial": 0.6,
|
||||
"kc_mid": 1.15,
|
||||
"kc_end": 0.8
|
||||
},
|
||||
"active_kc": 1.15
|
||||
},
|
||||
"status": "completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"code": 201,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 3,
|
||||
"code": "soil_moisture",
|
||||
"name_fa": "رطوبت خاک",
|
||||
"unit": "%",
|
||||
"created_at": "2025-03-24T10:00:00Z",
|
||||
"action": "added"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"code": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"uuid_sensor": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"location_id": 12,
|
||||
"soil_moisture": 45.2,
|
||||
"soil_temperature": 22.5,
|
||||
"soil_ph": 6.8,
|
||||
"electrical_conductivity": 1.2,
|
||||
"nitrogen": 30.0,
|
||||
"phosphorus": 15.0,
|
||||
"potassium": 20.0,
|
||||
"plant_ids": [
|
||||
1
|
||||
],
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"location_id": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "location_id یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"uuid_sensor": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"location_id": 12,
|
||||
"soil_moisture": 45.2,
|
||||
"soil_temperature": 22.5,
|
||||
"soil_ph": 6.8,
|
||||
"electrical_conductivity": 1.2,
|
||||
"nitrogen": 30.0,
|
||||
"phosphorus": 15.0,
|
||||
"potassium": 20.0,
|
||||
"plant_ids": [
|
||||
1
|
||||
],
|
||||
"created_at": "2025-03-20T10:00:00Z",
|
||||
"updated_at": "2025-03-24T10:00:00Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"location_id": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"code": 404,
|
||||
"msg": "location_id یافت نشد.",
|
||||
"data": null
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"source": "database",
|
||||
"id": 12,
|
||||
"lon": "51.389000",
|
||||
"lat": "35.689200",
|
||||
"depths": [
|
||||
{
|
||||
"depth_label": "0-5cm",
|
||||
"bdod": 1.31,
|
||||
"cec": 18.4,
|
||||
"cfvo": 2.0,
|
||||
"clay": 24.0,
|
||||
"nitrogen": 0.18,
|
||||
"ocd": 32.0,
|
||||
"ocs": 4.1,
|
||||
"phh2o": 7.2,
|
||||
"sand": 34.0,
|
||||
"silt": 42.0,
|
||||
"soc": 1.6,
|
||||
"wv0010": 0.31,
|
||||
"wv0033": 0.22,
|
||||
"wv1500": 0.11
|
||||
},
|
||||
{
|
||||
"depth_label": "5-15cm",
|
||||
"bdod": 1.35,
|
||||
"cec": 17.2,
|
||||
"cfvo": 2.3,
|
||||
"clay": 26.0,
|
||||
"nitrogen": 0.16,
|
||||
"ocd": 28.0,
|
||||
"ocs": 3.7,
|
||||
"phh2o": 7.1,
|
||||
"sand": 36.0,
|
||||
"silt": 38.0,
|
||||
"soc": 1.4,
|
||||
"wv0010": 0.29,
|
||||
"wv0033": 0.2,
|
||||
"wv1500": 0.1
|
||||
},
|
||||
{
|
||||
"depth_label": "15-30cm",
|
||||
"bdod": 1.39,
|
||||
"cec": 15.8,
|
||||
"cfvo": 2.8,
|
||||
"clay": 28.0,
|
||||
"nitrogen": 0.13,
|
||||
"ocd": 22.0,
|
||||
"ocs": 3.2,
|
||||
"phh2o": 7.0,
|
||||
"sand": 38.0,
|
||||
"silt": 34.0,
|
||||
"soc": 1.1,
|
||||
"wv0010": 0.26,
|
||||
"wv0033": 0.18,
|
||||
"wv1500": 0.09
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "تسک در صف. وضعیت را با task_id بررسی کنید.",
|
||||
"data": {
|
||||
"source": "task",
|
||||
"task_id": "soil-task-123",
|
||||
"lon": 51.389,
|
||||
"lat": 35.6892,
|
||||
"status_url": "/api/soil-data/tasks/soil-task-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"lat": [
|
||||
"This field is required."
|
||||
],
|
||||
"lon": [
|
||||
"This field is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"source": "database",
|
||||
"id": 12,
|
||||
"lon": "51.389000",
|
||||
"lat": "35.689200",
|
||||
"depths": [
|
||||
{
|
||||
"depth_label": "0-5cm",
|
||||
"bdod": 1.31,
|
||||
"cec": 18.4,
|
||||
"cfvo": 2.0,
|
||||
"clay": 24.0,
|
||||
"nitrogen": 0.18,
|
||||
"ocd": 32.0,
|
||||
"ocs": 4.1,
|
||||
"phh2o": 7.2,
|
||||
"sand": 34.0,
|
||||
"silt": 42.0,
|
||||
"soc": 1.6,
|
||||
"wv0010": 0.31,
|
||||
"wv0033": 0.22,
|
||||
"wv1500": 0.11
|
||||
},
|
||||
{
|
||||
"depth_label": "5-15cm",
|
||||
"bdod": 1.35,
|
||||
"cec": 17.2,
|
||||
"cfvo": 2.3,
|
||||
"clay": 26.0,
|
||||
"nitrogen": 0.16,
|
||||
"ocd": 28.0,
|
||||
"ocs": 3.7,
|
||||
"phh2o": 7.1,
|
||||
"sand": 36.0,
|
||||
"silt": 38.0,
|
||||
"soc": 1.4,
|
||||
"wv0010": 0.29,
|
||||
"wv0033": 0.2,
|
||||
"wv1500": 0.1
|
||||
},
|
||||
{
|
||||
"depth_label": "15-30cm",
|
||||
"bdod": 1.39,
|
||||
"cec": 15.8,
|
||||
"cfvo": 2.8,
|
||||
"clay": 28.0,
|
||||
"nitrogen": 0.13,
|
||||
"ocd": 22.0,
|
||||
"ocs": 3.2,
|
||||
"phh2o": 7.0,
|
||||
"sand": 38.0,
|
||||
"silt": 34.0,
|
||||
"soc": 1.1,
|
||||
"wv0010": 0.26,
|
||||
"wv0033": 0.18,
|
||||
"wv1500": 0.09
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 202,
|
||||
"msg": "تسک در صف. وضعیت را با task_id بررسی کنید.",
|
||||
"data": {
|
||||
"source": "task",
|
||||
"task_id": "soil-task-123",
|
||||
"lon": 51.389,
|
||||
"lat": 35.6892,
|
||||
"status_url": "/api/soil-data/tasks/soil-task-123/status/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "داده نامعتبر.",
|
||||
"data": {
|
||||
"lat": [
|
||||
"A valid number is required."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "soil-task-123",
|
||||
"status": "FAILURE",
|
||||
"error": "خطا در واکشی داده خاک."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "soil-task-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "soil-task-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"step": "fetch",
|
||||
"percent": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "soil-task-123",
|
||||
"status": "SUCCESS",
|
||||
"result": {
|
||||
"source": "database",
|
||||
"id": 12,
|
||||
"lon": "51.389000",
|
||||
"lat": "35.689200",
|
||||
"depths": [
|
||||
{
|
||||
"depth_label": "0-5cm",
|
||||
"bdod": 1.31,
|
||||
"cec": 18.4,
|
||||
"cfvo": 2.0,
|
||||
"clay": 24.0,
|
||||
"nitrogen": 0.18,
|
||||
"ocd": 32.0,
|
||||
"ocs": 4.1,
|
||||
"phh2o": 7.2,
|
||||
"sand": 34.0,
|
||||
"silt": 42.0,
|
||||
"soc": 1.6,
|
||||
"wv0010": 0.31,
|
||||
"wv0033": 0.22,
|
||||
"wv1500": 0.11
|
||||
},
|
||||
{
|
||||
"depth_label": "5-15cm",
|
||||
"bdod": 1.35,
|
||||
"cec": 17.2,
|
||||
"cfvo": 2.3,
|
||||
"clay": 26.0,
|
||||
"nitrogen": 0.16,
|
||||
"ocd": 28.0,
|
||||
"ocs": 3.7,
|
||||
"phh2o": 7.1,
|
||||
"sand": 36.0,
|
||||
"silt": 38.0,
|
||||
"soc": 1.4,
|
||||
"wv0010": 0.29,
|
||||
"wv0033": 0.2,
|
||||
"wv1500": 0.1
|
||||
},
|
||||
{
|
||||
"depth_label": "15-30cm",
|
||||
"bdod": 1.39,
|
||||
"cec": 15.8,
|
||||
"cfvo": 2.8,
|
||||
"clay": 28.0,
|
||||
"nitrogen": 0.13,
|
||||
"ocd": 22.0,
|
||||
"ocs": 3.2,
|
||||
"phh2o": 7.0,
|
||||
"sand": 38.0,
|
||||
"silt": 34.0,
|
||||
"soc": 1.1,
|
||||
"wv0010": 0.26,
|
||||
"wv0033": 0.18,
|
||||
"wv1500": 0.09
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "sample-task-123"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "sample-task-123",
|
||||
"status": "FAILURE",
|
||||
"error": "Sample task failed."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "sample-task-123",
|
||||
"status": "PENDING",
|
||||
"message": "تسک در صف یا یافت نشد."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "sample-task-123",
|
||||
"status": "PROGRESS",
|
||||
"progress": {
|
||||
"current": 1,
|
||||
"total": 3,
|
||||
"message": "در حال پردازش..."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"task_id": "sample-task-123",
|
||||
"status": "SUCCESS",
|
||||
"result": "done"
|
||||
}
|
||||
}
|
||||
+17
-12
@@ -1,21 +1,21 @@
|
||||
"""
|
||||
Pest Detection API views.
|
||||
Plain Django only; no DRF. No database. All responses are static mock data.
|
||||
No database. All responses are static mock data.
|
||||
Response format: {"status": "success", "data": <payload>}. HTTP 200 only.
|
||||
No processing, validation, or use of input parameters in responses.
|
||||
CSRF exempt so frontend can call POST without token.
|
||||
"""
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from config.swagger import status_response
|
||||
from .mock_data import ANALYZE_RESPONSE_DATA
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class AnalyzeView(View):
|
||||
class AnalyzeView(APIView):
|
||||
"""
|
||||
POST endpoint for pest detection analysis.
|
||||
|
||||
@@ -36,8 +36,13 @@ class AnalyzeView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
return JsonResponse(
|
||||
{"status": "success", "data": ANALYZE_RESPONSE_DATA},
|
||||
status=200,
|
||||
@extend_schema(
|
||||
tags=["Pest Detection"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("PestDetectionAnalyzeResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return Response(
|
||||
{"status": "success", "data": ANALYZE_RESPONSE_DATA},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
+47
-24
@@ -1,22 +1,22 @@
|
||||
"""
|
||||
Plant Simulator API views.
|
||||
Plain Django only; no DRF. No database. All responses are static mock data.
|
||||
No database. All responses are static mock data.
|
||||
Response format: {"status": "success"} or {"status": "success", "data": <payload>}. HTTP 200 only.
|
||||
No processing, validation, or use of input parameters in responses.
|
||||
CSRF exempt so frontend (e.g. localhost:3000) can call POST/PATCH without token.
|
||||
"""
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from config.swagger import status_response
|
||||
from .mock_data import CONFIG_SLIDERS_ONLY, START_RESPONSE_DATA, STATE_RESPONSE_DATA
|
||||
from .serializers import success_response, success_with_data
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ConfigView(View):
|
||||
class ConfigView(APIView):
|
||||
"""
|
||||
GET endpoint for simulator configuration (ورود).
|
||||
|
||||
@@ -34,12 +34,15 @@ class ConfigView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Plant Simulator"],
|
||||
responses={200: status_response("PlantSimulatorConfigResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(success_with_data(CONFIG_SLIDERS_ONLY), status=200)
|
||||
return Response(success_with_data(CONFIG_SLIDERS_ONLY), status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class StateView(View):
|
||||
class StateView(APIView):
|
||||
"""
|
||||
GET endpoint for plant state, progress, and chart history.
|
||||
|
||||
@@ -62,12 +65,15 @@ class StateView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Plant Simulator"],
|
||||
responses={200: status_response("PlantSimulatorStateResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def get(self, request):
|
||||
return JsonResponse(success_with_data(STATE_RESPONSE_DATA), status=200)
|
||||
return Response(success_with_data(STATE_RESPONSE_DATA), status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class StartView(View):
|
||||
class StartView(APIView):
|
||||
"""
|
||||
POST endpoint to start simulation.
|
||||
|
||||
@@ -86,12 +92,16 @@ class StartView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Plant Simulator"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("PlantSimulatorStartResponse", data=serializers.JSONField())},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(success_with_data(START_RESPONSE_DATA), status=200)
|
||||
return Response(success_with_data(START_RESPONSE_DATA), status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class StopView(View):
|
||||
class StopView(APIView):
|
||||
"""
|
||||
POST endpoint to stop simulation.
|
||||
|
||||
@@ -109,12 +119,16 @@ class StopView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Plant Simulator"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("PlantSimulatorStopResponse")},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(success_response(), status=200)
|
||||
return Response(success_response(), status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class ResetView(View):
|
||||
class ResetView(APIView):
|
||||
"""
|
||||
POST endpoint to reset simulation.
|
||||
|
||||
@@ -132,12 +146,16 @@ class ResetView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Plant Simulator"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("PlantSimulatorResetResponse")},
|
||||
)
|
||||
def post(self, request):
|
||||
return JsonResponse(success_response(), status=200)
|
||||
return Response(success_response(), status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class EnvironmentView(View):
|
||||
class EnvironmentView(APIView):
|
||||
"""
|
||||
PATCH endpoint to update environment (slider values).
|
||||
|
||||
@@ -157,5 +175,10 @@ class EnvironmentView(View):
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Plant Simulator"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={200: status_response("PlantSimulatorEnvironmentResponse")},
|
||||
)
|
||||
def patch(self, request):
|
||||
return JsonResponse(success_response(), status=200)
|
||||
return Response(success_response(), status=status.HTTP_200_OK)
|
||||
|
||||
@@ -1,12 +1,50 @@
|
||||
from rest_framework import status
|
||||
from rest_framework import serializers
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
|
||||
from config.swagger import code_response
|
||||
from .models import Sensor
|
||||
from .serializers import SensorCreateSerializer, SensorSerializer
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
get=extend_schema(
|
||||
tags=["Sensor Hub"],
|
||||
responses={
|
||||
200: code_response("SensorHubGetResponse", data=serializers.JSONField()),
|
||||
404: code_response("SensorHubNotFoundResponse"),
|
||||
},
|
||||
),
|
||||
post=extend_schema(
|
||||
tags=["Sensor Hub"],
|
||||
request=OpenApiTypes.OBJECT,
|
||||
responses={
|
||||
201: code_response("SensorCreateResponse", data=serializers.JSONField()),
|
||||
200: code_response("SensorToggleResponse"),
|
||||
400: code_response("SensorToggleValidationResponse"),
|
||||
404: code_response("SensorToggleNotFoundResponse"),
|
||||
},
|
||||
),
|
||||
patch=extend_schema(
|
||||
tags=["Sensor Hub"],
|
||||
request=SensorCreateSerializer,
|
||||
responses={
|
||||
200: code_response("SensorUpdateResponse", data=SensorSerializer()),
|
||||
404: code_response("SensorUpdateNotFoundResponse"),
|
||||
},
|
||||
),
|
||||
delete=extend_schema(
|
||||
tags=["Sensor Hub"],
|
||||
responses={
|
||||
200: code_response("SensorDeleteResponse"),
|
||||
404: code_response("SensorDeleteNotFoundResponse"),
|
||||
},
|
||||
),
|
||||
)
|
||||
class SensorHubView(APIView):
|
||||
"""
|
||||
Sensor-hub CRUD endpoints connected to the database.
|
||||
|
||||
Reference in New Issue
Block a user