From 2aef4d47565745a9ebe480754dd55403da866cdf Mon Sep 17 00:00:00 2001 From: "afanasyev.aa" Date: Sat, 5 Apr 2025 03:05:30 +0900 Subject: [PATCH] added validation, tawhiri request creation --- api/__pycache__/serializers.cpython-313.pyc | Bin 793 -> 4306 bytes api/__pycache__/urls.cpython-313.pyc | Bin 734 -> 730 bytes api/__pycache__/validators.cpython-313.pyc | Bin 0 -> 2163 bytes api/__pycache__/views.cpython-313.pyc | Bin 4563 -> 5150 bytes api/serializers.py | 66 ++++++++++++++++++ .../__pycache__/tawhiri.cpython-313.pyc | Bin 0 -> 3553 bytes api/services/tawhiri.py | 52 ++++++++++++++ api/validators.py | 31 ++++++++ api/views.py | 43 +++++++----- db.sqlite3 | Bin 176128 -> 176128 bytes testapi/__pycache__/settings.cpython-313.pyc | Bin 2851 -> 2874 bytes testapi/settings.py | 10 ++- 12 files changed, 184 insertions(+), 18 deletions(-) create mode 100644 api/__pycache__/validators.cpython-313.pyc create mode 100644 api/services/__pycache__/tawhiri.cpython-313.pyc create mode 100644 api/services/tawhiri.py create mode 100644 api/validators.py diff --git a/api/__pycache__/serializers.cpython-313.pyc b/api/__pycache__/serializers.cpython-313.pyc index 70e2ce548fb8d3b7ba41c48260ca1c8496396fcd..72dde887d22514067699c6452874b5490012f6be 100644 GIT binary patch literal 4306 zcmbtXOKcm-5uM@xPl`WT(n_XjTM;dbT7B2@cV&^%ijpOVLwTJw*Ml)RlqR7_ZO_n2 zltTz42m}NHvIvazAqSrV<&yA_LykK7$RQ1oXxP98K?3+@Kwj+8sh;78lq}g!G60+1 zT~)8DtE;Q4_nl4~1>ax$UakMzNm2hK1MM@mI{SZv&LfJU7PS=@NRR zhd#v^mJA64GAQ%LC1b*bObIhGCoIU4up(=SIz@#k#?(tO<}{u3YYN)`Q+lrY+=~~x5=|Cwz2GHFlzu;zeK$ z0P8;dC>)-J9?~cbACVs6QiTRckKic{*?|`N_d1>N`fCarm67mZ4_H{p zawyAgp<+(R^Vpcn7r~Ea#6N^MXgOJ!Cx*!^~J_Xk-IA@!OFPtgtdRpgVxxdxQwX zFhveBV+SieCn2P}6a?=(EO0PRK=8en!~YHrvWmca=s}<#>nBF_LO0Nl_kv14^&WZ; z&?k@c65yK|7p$?5araW_BgTXJ*SjKK+}A#~N&c%6giS|MAmJCKxrFTa3ZM2D@L zLV<;BR)Xxc$^A_2B9bbE4M>CYB=I4D5g-*}!;eKJ6`Herj)TJu^5)D&QONKj8Uc~@ zU-|Z--zhYFpN<|QKI$Q zFNF62kA6+pmb`qIqPVLR+(T>h70|-LmfX|QEtNDKQ3^u{Q{z<29-dyK83Q?QYx>KV zKTz7#mR|iA*kaLiD7LJCEoRl0ETjp*H~*LTmNq_PZ6QHc0VJz}L^C$>|H1a!+jy(L z1A7k=h+^-rz+Oj7iw}GUm4NzzJ_pgGNt3IKeAy52uv3%bX~uN|y6b;NcXyz-_Pyon z|6?y157-Ioi`8l=tSwQS*d9AXKL8~c;9jS*UY1ik(@$lPjok9h#0}drOK`a@e5}$q33A{W>pU&+X*u{Ni$)Wm2;% zvDst{ktBxQchr&)ip4lWMTDIi-~96GYzn)y;oKUNTD^tLAcRO#fI7+`^7$M#z=}BZ zF#)r+oiCC!6@m|u;sRT=$`hY^N1l&rTqFyNe}FtzrkdX1H$z_!J)U_sI9>OCvSV%r zdcL{)_1)^gXr-$jnAov>Yxh124%Y31P50?1Qr$iLJb0!N9IFM#s^i&ukgt09rrTHb zpOf9^cYEvZi4OWkJt$N?!Ye)HnS5oUT!BA2>(28U(5_USjLD<%r@i%2=548_d*Dg7 z?!K^_t=y2Kb9+*C`Ad1>em#1>gO{%db5&0cG>o#es=`%wg01~eQgwIa+1UJ^^mIjD zxYrm<%VX&d$;EmwQS~G=Eziamo*JIA@@HQ*#_!AHojMZr;8NAI^nqrB5sse6vAR9< zJUqM`tMtnkZ`8w|?!BA^mTjKYg!82SJvc3J8kB^9J*_~=7Ypm^j57wYnt}(1B7sP`hQ>(bSm!o4 zq{5gWEo?%aX`fRrZ*|hktlhr7noPxGY%5e5L^7Qkk-_EJRGdk%vDwrt6Hl>A@gIG@ znv7vH30jet&?Uk;Lz;2YOpt~YE@+xGpFo2hH;ctQ&lOaCcA)@AdaJ0M?3;w?xMF&c z5J*ER7tsun45c~=%Zs((#frH1Kn^aJSDW48M)ydqd*tu*9wT=zRtwGo(X*KbM?7CN8Q0C6oTxY8nZ_2K@ z@&fF)Z=m5Fs(FVh=l3RM?`P$uCd~LEHD9DMwHK3pi{<5JAk+v9*8;1o|Q1^~2&`8@yt delta 314 zcmcblIFpUsfjEc-QdI=jBne`%!w422qnHOsv@v{VVq&%X!T=;73PEas2H)Z-#0%cH77W=C^Io9vnsU+Vl1jvw>WHa^HWN5QtgW5 sfEpQrxL6iQd|+l|WW39uc9%i!3kx%&-3;sN(q&Au`KIba6>0AQLyxBvhE diff --git a/api/__pycache__/urls.cpython-313.pyc b/api/__pycache__/urls.cpython-313.pyc index a73920cb56c44c42dd3526242c7f1809a15f87ca..516fdbd026e4180fa69bdcfc3238b34cf1c0e5eb 100644 GIT binary patch delta 49 zcmcb|dW)6!GcPX}0}vRkdY}G&BkvYQMz+nz7+D#GB`yf7TxL=Iz{$$b)W}^V0#pM4 DcPb50 delta 53 zcmcb`dXJU&GcPX}0}z-leV_h$BkvYQR<6W?O#RJ=7+D#GWiE(oTxQYyz{$$b)W}^V H0#pY8z8wzG diff --git a/api/__pycache__/validators.cpython-313.pyc b/api/__pycache__/validators.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57e4db68a555fdefaae28d3af218e3fecba02139 GIT binary patch literal 2163 zcma)7O>7%Q6rS1jPhu-EwQFb#Z71okY2rG~UkPp6C~8%x$RSHmi(5smcWoKjUTfB_ zLL^X{99n2aIS?suphc>LkT_WB4gDL4Hw|j6IFeIa^cPFu0v1`j5Kd& zXWpBg`QG=wt+%uU5VQ^Re`Mnxgnr{MZj+or{U8ixk%AO_5>fk!DTa6Hr1ZK(C4v-r z3!<{(0qaq`V7-bDtS^gW{>OZqkr=j`)Kpn3=L%XHJ3I4-54sG!9tSgvl8v<_pA~Hk zzTE4aMv>gnP85?X6>wmmvzz7=tFn7+!Mw;8*gTAHo705dVoU74Ib&Whr(yc8d70fN z>>Kc_g5Pc7f0dXQ*dkkk4VG*_vX?tR+!T+2jix$CBHl%Q{on?f5Vk9kh-E+fl(%n> zWbHGaJ{prOxsWS@Nln0QJrr(h@Y@ipZFt}e)k^vqm?@`9xih?0PUt zyN{>yxe{%L7>D!k`3;fbFdbKZfpa?v571P+a3nnuJ8J?^NY@^Ts>85AFKtBFwYUnnY{)ieq}+m zMHtMYZT|x%7l!rWa#xEu$rC2pC_nyx8UT)6-<_xpB}LJ3CqGI>5GqQ^7B@tZ#-vu% zExG<0R^*~IBxP_09hSGF432p!G4N)e0EL0M!14u1%#5J?xs;*x^>k{*w61C@NmuB3 zZPHsQXF3l~KL1)#aL%43b`}Q6NX&2f>^Q6WTwjl>@mR~}JU#CideQRc^^|H@&BrFv zTB)3anZR2-WydJhX-u~K&KE7e9j01XGdR|S5IdnE`x88!;#Bk{Smo(7-UKs+o_IXo z{*~~i<#7AMaQpTCT6o`b_<$KcP=(>Em;5WC$koXYC+GImLhY=n{m+%)#yY|f(z=Pg z*i~(-M%d=wT5BI`>iheN3=7Xh{Y(!WM)v|kTjU4+)}g5UAnJwj8diYp*{rw%1Hp=h z1dSm#3y|SeIl@UEBbqBlhw)x#CKZNDqom(?1?k!X*^i)JXTsf4@SwpJ-~sGU&~}uS z8hMs0??Di|CdzA`E0KAXXSsuz7eUdMoJ86(CDIRUxC5`ZxB!CQ&6poK^$GM?ggTw! zL|ISZpsw!&jV|yyCVX!pkc+W3Nb&mVhF;Hu*#W1W1tE!`6E6dU@v3l-;bcQ}*1@M$ z;M0(w)yh!NzzKxTqggLOZ*=fFCn$^iWnjGYnD00OL<{7MToJUOnAR*$K4+9IIjg*E3nXYSFI(6mlMj5@^?c&_}HlOeekD*0_%SnoDS0mdhqd>SJ0Xgn4oQ7 zEIF0W(-&X_NAwEfTfUN>E0&ElM~$v~J_^X9&Crb@Fm{bZS2mFA(b|SRmwYRs&2zhN z?5u_MEQi#uht2(}c{W|!uhu$L)}*=>68$-}krzbtnGu3rrn~#loxqSRKaeokn4bb+ z5#|3Hq0-{_BXrij3O~YENQkLj$W4a|x?0I=gA{UvFmz)F82ALnk5J1a6#NBked?3& V?xz6>AH`1tKHOgq`*2ij@(-;TJ&OPU literal 0 HcmV?d00001 diff --git a/api/__pycache__/views.cpython-313.pyc b/api/__pycache__/views.cpython-313.pyc index f1db0f683f9d77e5fd340401b83e176d919fcc6c..edba6dd3e0bca25eeabf6dd1c374c4130359a44a 100644 GIT binary patch delta 2559 zcma)8U2GFa5Z?8j{~e#>I6t;SVnPZrAt4Drfha)S;6m*xz&RGGj@G#LIUI8Au;&0p zNa;gGd8kx{Yt^Vy`%F~SLa78&`#^sXF9^jz<>(4(RrR4#RS8N!6_u*)oPD_np{gf) zX7<~;o&EM^=I+j#PrBTX>gpVbUh}ISO!T{E-7WaH*>wkJVjST@D1j2TxF=Rm>NVRQ z_YyC~9Px&jkN7mq8E=d=ktWS{QQv0LOl@vFZAOU(3j0>Tt0wH>#@Q#i^(NJ~pNLs0Q<92>gh-@xUOFWbHE5u` zcx+mfONxZsM#5NiW@M5}i6_O$sS+J}CdJZ`Vm6f(Gewdv6$!;`k$k>*B2svh+I8dU z6GtQ>jpik>P`dmMwqyKMnKi|+Pq}Xr%&Y0%Ib{bkjYG;GoZm+ISrQDfDz}*6h88-R zF#)~WWuqDhKYBvZ50HTMi6mAoVV@&`x8s5-Y2wYwEF0L?Rh!OsAS76qeN8;9^UNh^ zPYyudrL1NfW=z{noro^we#Vgw3rrglJUY&Mb<5BlD9LQ8?XJKIG=BBsJ9W#@{5r$d ztt2~>uu?7-LFa(}_pO*;uP}+nEp&_88}7;rk3n-AY>c z0o^uql1Ne3Nb&+KSSX^lZ(7U&j)R5Y+9YSwGLDnQzrmL+j_1 zrYk?|aj5FXw;ArbwGSs)y@n|3Wzw|jEYAz>Mw?81cm=_bPEa-buNF=04hE6#P#SjtYsbWDERkH>XI4gR) zh2qosQkYTMX_?ljV`{l_XH-Xqi0P7;O{KxXBxOkty^BC5goC6GY)CWJCdsMew8*o> z3`2_+LDsgU`u2{G?@w*+>r1^D*`4B}2a?gmxa!v2wY6dY1U9a^C&W@}MSKFKs(Na@ zB6>0-PC-Xe%~M1wlvGA85zw1aj6b^Shc=JAZ68h zW8P_(7ndKixXG!m-6Mt(X)<4&R^j=%3Mc< z>nwAf_Zot8u}W)CxwYrZTxIKlGW|913oia=|C)+_pzI$w>wdtp_6dA1)Kdu!-wq95 zef>`8l?B(TC5Q5nb^XlX=fm^E*J5{tOhuTuElk`Iqy^gxW!uqTx#mT0>xVtFJ&S?P zN?>C-uyL_z-9szucP!aZgTLYpm%ZVKcGlDV0I~M&zm_=UX{m5sWv=THGC@dJ{epMx z1?GI@Q_Hpf8$&mSF5)YWOO7kt7u-VP@LgB>UIQPTJ9wV^nz=#9Z&ebZ~u>naX)I7Pcu- z+txrmbymGoBAJwAndU?)lTXXCD3geC+7=ufrPBoZBME_k{-_B^D4C<;3|b6y%mo(M zrpK($++FqURBpM3&e?sq|8k@K9JZ@gD2bGmRW3N%@tAVck#|BH(UOX6Q%0R#J0btW z7BUR*4iIA?_JP<>h3YiYLY6HQ(enU2{K~vDhzFGG&d;=NPGH|-bh+Iy8wK$ah&>>* z$S;HS47)gBAo}TFhPTie^w{Jy$8nWboYLBlcU^9;3**gUI(^DMRxE{b#pyy;dY>jC zfi@Sm*Jx3@8Vk~v3{jz+c6YTI3=adYB{oYf;6t8QGR!y6aI^X2)90u!)q`B zVi)}{bFi96Y8+rH+@`$kdCx@Z6i5nl4Nfdyh-v3AuOqn?de{j|u`$ zTWzknOqZnmN*4m}TcRbChd%1#Qbv?}OVy7HttXMy;GpG?cFfv7fnk%8UaD<)vY4ID zi#y3N+l;&C2A2?3O9L(($8*g~2=r2` O4Ugct!N&-+w)($^79xEB delta 1822 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 literal 0 HcmV?d00001 diff --git a/api/services/tawhiri.py b/api/services/tawhiri.py new file mode 100644 index 0000000..dbaf7e8 --- /dev/null +++ b/api/services/tawhiri.py @@ -0,0 +1,52 @@ +import requests +from urllib.parse import urlencode +from datetime import datetime +from typing import Any +from zoneinfo import ZoneInfo +from collections import OrderedDict + +class TawhiriClient: + BASE_URL = "https://fly.stratonautica.ru/api/v2/" + TIMEOUT = 15 + + @staticmethod + def _convert_value(value: Any) -> Any: + if isinstance(value, datetime): + return value.isoformat().replace("+00:00", "Z") + return value + + @classmethod + def get_prediction(cls, params: dict) -> dict: + url = cls.build_url(params) + print("🔍 URL:", url) + response = requests.get(url, timeout=cls.TIMEOUT) + response.raise_for_status() + return response.json() + + @classmethod + def build_url(cls, params: dict) -> str: + query = OrderedDict() + + query["profile"] = params.get("profile") + query["launch_datetime"] = cls._convert_value(params.get("launch_datetime")) + query["launch_latitude"] = params.get("launch_latitude") + query["launch_longitude"] = params.get("launch_longitude") + query["launch_altitude"] = params.get("launch_altitude", 0) + query["ascent_rate"] = params.get("ascent_rate") + query["burst_altitude"] = params.get("burst_altitude") + query["descent_rate"] = params.get("descent_rate") + query["interpolate"] = str(params.get("interpolate", False)).lower() + query["dataset"] = cls._convert_value(params.get("dataset")) + query["format"] = params.get("format", "json") + query["pred_type"] = "single" # <-- в конце + + filtered = {k: v for k, v in query.items() if v is not None} + return f"{cls.BASE_URL}?{urlencode(filtered)}" + + + @classmethod + def get_prediction(cls, params: dict) -> dict: + url = cls.build_url(params) + response = requests.get(url, timeout=cls.TIMEOUT) + response.raise_for_status() + return response.json() diff --git a/api/validators.py b/api/validators.py new file mode 100644 index 0000000..222c170 --- /dev/null +++ b/api/validators.py @@ -0,0 +1,31 @@ +import base64 +import json +from datetime import datetime + + +def rate_clip(rate): + """Ограничивает допустимые значения скорости (например, 0.1 ≤ x ≤ 100)""" + return min(max(rate, 0.1), 100.0) + + +def _rfc3339_to_timestamp(value): + """Парсинг RFC 3339 строки в datetime""" + return datetime.fromisoformat(value.replace("Z", "+00:00")) + + +def base64_to_curve(encoded): + """Декодирует base64-encoded curve""" + try: + decoded = base64.b64decode(encoded).decode('utf-8') + return json.loads(decoded) + except Exception as e: + raise ValueError(f"Invalid curve format: {e}") + + +def validate_custom_curve(curve): + """Проверяет, что curve имеет ожидаемую структуру (например, список точек)""" + try: + points = base64_to_curve(curve) + return isinstance(points, list) and all(isinstance(p, list) and len(p) == 2 for p in points) + except Exception: + return False diff --git a/api/views.py b/api/views.py index 803abe6..5255069 100644 --- a/api/views.py +++ b/api/views.py @@ -3,9 +3,14 @@ from rest_framework.response import Response from rest_framework.views import APIView from django.utils import timezone from .models import Prediction, User, UserPrediction -from .serializers import PredictionSerializer +from .serializers import PredictionSerializer, PredictionRequestSerializer from rest_framework.permissions import IsAuthenticated import requests +from django.views.decorators.csrf import csrf_exempt +from django.utils.decorators import method_decorator +from rest_framework.permissions import AllowAny +from .services.tawhiri import TawhiriClient + def get_prediction_from_tawhiri(params): base_url = "https://fly.stratonautica.ru/api/v2" @@ -15,25 +20,31 @@ def get_prediction_from_tawhiri(params): return response.json() # получаем результат предсказания else: raise Exception(f"Tawhiri error: {response.status_code} {response.text}") - - + class PredictionCreateView(APIView): - def post(self, request): - user_id = request.data.get('user_id') - user = User.objects.get(id=user_id) + permission_classes = [AllowAny] + + def post(self, request): + serializer = PredictionRequestSerializer(data=request.data) + if not serializer.is_valid(): + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + validated_data = serializer.validated_data - # Передаём остальные параметры (кроме user_id) в Tawhiri - tawhiri_params = {k: v for k, v in request.data.items() if k != 'user_id'} - try: - prediction_result = get_prediction_from_tawhiri(tawhiri_params) - except Exception as e: - return Response({"error": str(e)}, status=500) + prediction_result = TawhiriClient.get_prediction(validated_data) + except requests.RequestException as e: + print("❌ Tawhiri error:", str(e), e.response.text if e.response else "no response") + return Response({"error": f"Tawhiri error: {str(e)}"}, status=status.HTTP_502_BAD_GATEWAY) prediction = Prediction.objects.create(result=prediction_result) - UserPrediction.objects.create(user=user, prediction=prediction) + UserPrediction.objects.create(user=request.user, prediction=prediction, created_at=timezone.now()) - return Response(PredictionSerializer(prediction).data) + return Response({ + "id": prediction.id, + "created_at": prediction.created_at, + "result": prediction_result + }, status=status.HTTP_201_CREATED) class PredictionListView(APIView): def get(self, request): @@ -59,5 +70,5 @@ class PredictionDeleteView(APIView): except Prediction.DoesNotExist: return Response({"error": "Not found"}, status=404) -class PredictionCreateView(APIView): - permission_classes = [IsAuthenticated] \ No newline at end of file +#class PredictionCreateView(APIView): + #permission_classes = [IsAuthenticated] \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index a39dc9f3abc4a71954b5fbc7318f15502339b92d..6e40345d6fc75e7199cab29743a6eacb12498479 100644 GIT binary patch delta 404 zcmZp8z}4`8Yl1YR?nD`9M%|4GcKVE*o9FAN8n7|)Cou3QY!*xi;j^w~EA+{NU{JN|$o8Vp9uG6@5Sb zsANlzDB~d0lJbBG{}R(EUytmdDhm%^vrOX(m)sQ7^i0nXN1wz{+r*UI%)G?3#Jt4f z%+xZy#LD8-JcsmL-Neisz2y8{BLgE-T>}#!QZO{IGBU6-Hq$et$~RJ=%XDB{5ycs>-dA*7+GQ+Ig?V1OpOf9l8sG_ z%q%R8lTuQXEKE#IEX~tQ&63kn64NY94UCdZ4ACq$wlXl&Gcz(aGO&PHe1(Dk3eenB d{ASwBu|%5+(ffyi{|`{_dwzDHADEdrIRTdPZ2$lO delta 56 zcmV-80LTA;;0l1?3XmHCE0G*S0V}a!J}&_Xv!5?zFtY@Z2M_@Vvk`#r50Ov>qL2`R OkhYKk1n{#2;QTKabreJZ diff --git a/testapi/__pycache__/settings.cpython-313.pyc b/testapi/__pycache__/settings.cpython-313.pyc index 4edb2ac65f0bb47a9cb3500356c288d3ab7e8275..9f7596d7ff0cd5f41372816b8e582e7538ca05a1 100644 GIT binary patch delta 339 zcmZ21wo8ofGcPX}0}yPL_>e9xIFV0+@!v%CHg=XGo?!MO-iaH;CHaDRiui+hgZX0E zg86m185n{E^q347iv%Vh1=WcFge$T|nzqynxlTk&vD7CmGKCLJ*H?=&!C|j=}wJ0~UxHvOEuUOA9 zCnvw$F|Ts64M!NG delta 362 zcmdlbwpfhsGcPX}0}!aMe4p+wFp*D!@y|r{wtDs=o?s4rhG3RpP9Vt@$Y{VA%&o_w z&sfA8%u~b{%p1%X!xqf1%gw+LETG3^z*xi|EEp^VR3#WJ3?@auq^JR-K1-26uvn2` zuy~PBFiVjz5Q_v$6p02)7KsH*1xxEQ2Fn1ktR8cbc)FaXe4-8`!)86k21Z7%$?KUe zu`wqWWNNZ+-p%};iIH#fYPL+qIK!gU;*$8ZqQu