from rest_framework import viewsets from rest_framework.response import Response from rest_framework.views import APIView, View from rest_framework.request import Request from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponseBadRequest, HttpResponse, JsonResponse, HttpRequest from django.db.models.query import QuerySet from django.core.validators import validate_email from django.core.exceptions import ValidationError from .models import Apartament, User, AuthToken from .serializer import (ApartamentListSerializer, ApartamentDetailSerializer, PsychTestAddResultSerializer, PublicUserSerializer, UserSerializer, TokenSerializer) from .authlib import * import json, math, random, re, requests, base64, uuid, time, ipware as iplib ipware = iplib.IpWare(); class ApartamentViewSet(viewsets.ReadOnlyModelViewSet): """Вывод списка квартир или отдельной квартиры""" def get_queryset(self): apartaments = Apartament.objects.all() return apartaments def get_serializer_class(self): if self.action == 'list': return ApartamentListSerializer elif self.action == "retrieve": return ApartamentDetailSerializer class ApartamentGetManyViewSet(viewsets.ReadOnlyModelViewSet): """Вывод отдельных квартир для сравнения""" def get_queryset(self): # получение id квартир для избранного или сравнения pk = self.request.query_params.get("pk", None) # получение id пользователя if self.action == "retrieve": # если для страницы сравнения apartaments_id = User.objects.get(pk=pk).apartaments_for_comparison.split(',') # получение id квартир elif self.action == "list": # если для страницы избранного apartaments_id = User.objects.get(pk=pk).favorites_apartaments.split(',') # получение id квартир queryset = [] for i in apartaments_id: queryset.append(Apartament.objects.get(pk=i)) return queryset def retrieve(self, request, *args, **kwargs): queryset = self.get_queryset() apartaments = [] for i in queryset: apartaments.append(ApartamentDetailSerializer(i).data) return Response({'results': apartaments}) def list(self, request, *args, **kwargs): queryset = self.get_queryset() apartaments = [] for i in queryset: apartaments.append(ApartamentListSerializer(i).data) return Response({'results': apartaments}) class ApartmentFilter(viewsets.ViewSet): """Вывод списка квартир или отдельной квартиры""" def list(self, req: Request): filters = dict(req.data); unfiltered = Apartament.objects.all(); filtered = []; # TODO: Some better converting practice? filters['price_range']['from'] = int('0' if filters['price_range']['from'] == '' else filters['price_range']['from']); filters['price_range']['to'] = int('100000000' if filters['price_range']['to'] == '' else filters['price_range']['to']); filters['area_range']['from'] = int('0' if filters['area_range']['from'] == '' else filters['area_range']['from']); filters['area_range']['to'] = int('100000000' if filters['area_range']['to'] == '' else filters['price_range']['to']); filters['rooms'] = int(filters['rooms']) for entry in unfiltered: if (filters['price_range']['from'] >= entry.price and (filters['price_range']['to'] != -1 and filters['price_range']['to'] <= entry.price)): continue; if (filters['area_range']['from'] >= entry.perimetrs and (filters['area_range']['to'] != -1 and filters['area_range']['to'] <= entry.perimetrs)): continue; if (filters['rooms'] != -1 and entry.rooms != filters['rooms']): continue; filtered.append(entry); return Response(ApartamentListSerializer(filtered, many=True).data); class PsychTestAddResultViewSet(viewsets.ViewSet): def get_object(self, pk): return User.objects.get(pk=pk) def update(self, request, pk): user = self.get_object(pk) results = request.data user.update(test_results=results) return Response({'successfully': 'results post'}) class CompatibleUsersView(viewsets.ViewSet): @rest_auth_required def list(self, req: Request): user_data = dict(req.data); token = AuthToken.objects.get(key=req.headers['authorization']); this_user = User.objects.get(pk=token.user); answers_this_user = None; try: answers_this_user = PsychTestReultsSerializer(PsychTestAnswers.objects.get(user=this_user.id)).dict; except PsychTestAnswers.DoesNotExist: return Response({'error': 'answers not found'}, 404); # users_answers_query = PsychTestReultsSerializer(PsychTestAnswers.objects.all(), many=True).dict # users = []; # for user_answers in users_answers_query: # score = 0 # for i in range(1, 12): # if answers_this_user[i] == user_answers[i]: # score += 1 # if score / 12 * 100 > 30: # users.append(UserSerializer(User.objects.get(pk=user_answers[0])).data) return Response(users); class UserLogin(APIView): # TODO: Remove csrf exempt when index.html is loaded through django @csrf_exempt def post(self, req: HttpRequest): # for debug purposes # return HttpResponse("""{"user_data": {"id": 1, "name": "\u041d\u0438\u043a\u0438\u0442\u0430 \u041f\u0443\u0441\u0442\u043e\u0432\u0430\u043b\u043e\u0432", "date_of_birth": null, "about_me": "", "gender": "?", "phone": "+00000", "email": null, "telegram": null, "discord": null, "city": null, "role": "s", "photo_provider": "VVSU", "openid_addr": "blek__@vvsu.ru", "openid_id": "096C78CD-4943-4D57-BC6D-5CDE12F686E3"}, "new_user": false, "token": {"id": 2, "user": 1, "key": "e1c24581-523a-4f60-973f-02ba873b3edc", "expires": 1684423572, "ip": "127.0.0.1"}}"""); if (req.session.has_key('auth_data')): # TODO: Return user object instead of error return JsonResponse({'error': 'already authenticated'}) if (req.content_type != 'application/json'): res = HttpResponse({'error': 'bad content type'}); res.status_code = 400; return res; data = json.loads(req.body.decode('utf8')); if not ('code' in data and 'code_verifier' in data): res = JsonResponse({'error': 'no code'}); res.status_code = 400; return res; auth_data = get_oauth_token('https://vvsu.ru/connect', { 'grant_type': 'authorization_code', 'redirect_uri': 'https://tochka.vvsu.ru/sign-in/', 'code': data['code'], 'code_verifier': data['code_verifier'], 'client_id': 'it-hub-client', 'client_secret': 'U8y@uPVee6Q^*729esHTo4Vd' }); if ('error' in auth_data): return JsonResponse(auth_data); user = None; new_user = False; vvsu_data = get_oauth_data('https://vvsu.ru/connect', auth_data['access_token']); if ('error' in vvsu_data): res = JsonResponse(vvsu_data); res.status_code = 500; return res; if ('error' in vvsu_data): res = JsonResponse(vvsu_data); res.status_code = 500; return res vvsu_data['vvsu_login'] += '@vvsu.ru'; try: user = User.objects.get(openid_addr=vvsu_data['vvsu_login']); except User.DoesNotExist: user = register(vvsu_data['vvsu_login'], vvsu_data['id'], f"{vvsu_data['given_name']} {vvsu_data['family_name']}"); new_user = True; return JsonResponse({ 'user_data': PublicUserSerializer(user).data, 'new_user': new_user, 'token': TokenSerializer(create_auth_token(user.id, ipware.get_client_ip(req.META)[0].exploded)).data }); class UserGet(APIView): def get(self, req: HttpRequest): if not ('id' in req.GET.keys() or 'login' in req.GET.keys()): res = JsonResponse({'error': 'no id or login'}); res.status_code = 400; return res; id_type = 'id' if 'id' in req.GET.keys() else 'login'; id = req.GET.get(id_type); if (id_type == 'login'): if not id.endswith('@vvsu.ru'): id += '@vvsu.ru'; id_type = 'openid_addr'; user = None; try: user = User.objects.get(**{id_type: id}); except User.DoesNotExist: res = JsonResponse({'error': 'not found'}); res.status_code = 404; return res; return JsonResponse(PublicUserSerializer(user).data); def VVSUAuthProxy(req: HttpRequest): proxy = 'https://vvsu.ru/connect' + req.path[len('/api/auth/vvsu'):]; preq = requests.request(req.method, proxy, headers={ 'User-Agent': 'OIDC Client / Pairent', 'Origin': 'https://tochka.vvsu.ru', 'Referer': 'https://tochka.vvsu.ru' }); resp = HttpResponse(preq.content); resp.headers['Content-Type'] = preq.headers['Content-Type']; return resp;