mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-24 01:03:47 +03:00
added api endpoints, updated location
This commit is contained in:
parent
9c2beb8cd7
commit
3bf8042ec2
|
@ -1,11 +1,18 @@
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from passfinder.recomendations.api.views import TinderView, PersonalRecommendation
|
||||
from passfinder.users.api.views import UserViewSet
|
||||
|
||||
|
||||
router = DefaultRouter()
|
||||
|
||||
router.register('tinder', TinderView)
|
||||
router.register("recommendations", PersonalRecommendation)
|
||||
router.register("user", UserViewSet)
|
||||
|
||||
app_name = "api"
|
||||
urlpatterns = router.urls
|
||||
urlpatterns = [
|
||||
path("", include("passfinder.events.api.urls")),
|
||||
path("auth/", include("passfinder.users.api.urls")),
|
||||
]
|
||||
urlpatterns += router.urls
|
||||
|
|
|
@ -39,7 +39,11 @@
|
|||
# DATABASES
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
||||
DATABASES = {"default": env.db("DATABASE_URL", "postgres://postgres:Ilvas2006@localhost:5432/passfinder")}
|
||||
DATABASES = {
|
||||
"default": env.db(
|
||||
"DATABASE_URL", "postgres://postgres:Ilvas2006@localhost:5432/passfinder"
|
||||
)
|
||||
}
|
||||
DATABASES["default"]["ATOMIC_REQUESTS"] = True
|
||||
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-DEFAULT_AUTO_FIELD
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
@ -74,11 +78,7 @@
|
|||
"polymorphic",
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
"passfinder.users",
|
||||
"passfinder.events",
|
||||
"passfinder.recomendations"
|
||||
]
|
||||
LOCAL_APPS = ["passfinder.users", "passfinder.events", "passfinder.recomendations"]
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||
|
||||
|
@ -285,9 +285,9 @@
|
|||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-timezone
|
||||
CELERY_TIMEZONE = TIME_ZONE
|
||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-broker_url
|
||||
#CELERY_BROKER_URL = env("CELERY_BROKER_URL")
|
||||
# CELERY_BROKER_URL = env("CELERY_BROKER_URL")
|
||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-result_backend
|
||||
#CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
||||
# CELERY_RESULT_BACKEND = CELERY_BROKER_URL
|
||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended
|
||||
CELERY_RESULT_EXTENDED = True
|
||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-always-retry
|
||||
|
@ -316,8 +316,7 @@
|
|||
# django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
"rest_framework.authentication.TokenAuthentication",
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
),
|
||||
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
|
@ -334,8 +333,8 @@
|
|||
"VERSION": "1.0.0",
|
||||
"SERVE_PERMISSIONS": [],
|
||||
"SERVERS": [
|
||||
{"url": "https://dev2.akarpov.ru", "description": "Production server"},
|
||||
{"url": "http://127.0.0.1:8000", "description": "Local Development server"},
|
||||
{"url": "https://akarpov.ru", "description": "Production server"},
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
default="dh0qndI7XExEDZIdMDh2VPHbW9VNq0jsjsI2ImR9EyDQfNMYudHUaJswMggfhotG",
|
||||
)
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1"]
|
||||
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "dev2.akarpov.ru"]
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
# CACHES
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from django.views import defaults as default_views
|
||||
from django.views.generic import TemplateView
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
||||
from rest_framework.authtoken.views import obtain_auth_token
|
||||
|
||||
urlpatterns = [
|
||||
# Django Admin, use {% url 'admin:index' %}
|
||||
|
@ -17,8 +14,6 @@
|
|||
urlpatterns += [
|
||||
# API base url
|
||||
path("api/", include("config.api_router")),
|
||||
# DRF auth token
|
||||
path("api/auth/token/", obtain_auth_token),
|
||||
path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"),
|
||||
path(
|
||||
"api/docs/",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from passfinder.events.models import Hotel, HotelPhone, City, Event
|
||||
from passfinder.events.models import Hotel, HotelPhone, City, Event, BasePoint
|
||||
|
||||
|
||||
class HotelPhoneSerializer(serializers.ModelSerializer):
|
||||
|
@ -34,4 +34,14 @@ class Meta:
|
|||
class EventSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = ('type', 'title', 'description', 'city', 'oid')
|
||||
fields = ("type", "title", "description", "city", "oid")
|
||||
|
||||
|
||||
class PointSerializer(serializers.ModelSerializer):
|
||||
# location = serializers.ListSerializer(
|
||||
# child=serializers.FloatField(), source="bare_location", max_length=2
|
||||
# )
|
||||
|
||||
class Meta:
|
||||
model = BasePoint
|
||||
fields = ["title", "description", "location", "icon"]
|
||||
|
|
9
passfinder/events/api/urls.py
Normal file
9
passfinder/events/api/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.urls import path
|
||||
|
||||
from passfinder.events.api.views import BuildRouteApiView
|
||||
|
||||
app_name = "events"
|
||||
|
||||
urlpatterns = [
|
||||
path("route/build", BuildRouteApiView.as_view(), name="build_route")
|
||||
]
|
20
passfinder/events/api/views.py
Normal file
20
passfinder/events/api/views.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from django_filters import DateFilter
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework.generics import GenericAPIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
from passfinder.events.api.serializers import PointSerializer
|
||||
from passfinder.events.models import BasePoint
|
||||
|
||||
|
||||
class BuildRouteApiView(GenericAPIView):
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = DateFilter
|
||||
serializer_class = PointSerializer
|
||||
|
||||
def get(self, request):
|
||||
return Response(
|
||||
data=PointSerializer(many=True).to_representation(
|
||||
BasePoint.objects.order_by("?")[:10]
|
||||
)
|
||||
)
|
5
passfinder/events/filters.py
Normal file
5
passfinder/events/filters.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django_filters import rest_framework as filters
|
||||
|
||||
|
||||
class DateFilter(filters.FilterSet):
|
||||
date = filters.DateRangeFilter(field_name="date")
|
|
@ -0,0 +1,43 @@
|
|||
# Generated by Django 4.2.1 on 2023-05-21 17:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("events", "0014_remove_excursionroute_excursion_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="basepoint",
|
||||
name="lat",
|
||||
field=models.FloatField(db_index=True, default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="basepoint",
|
||||
name="lon",
|
||||
field=models.FloatField(db_index=True, default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="city",
|
||||
name="lat",
|
||||
field=models.FloatField(db_index=True, default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="city",
|
||||
name="lon",
|
||||
field=models.FloatField(db_index=True, default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="place",
|
||||
name="lat",
|
||||
field=models.FloatField(db_index=True, default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="place",
|
||||
name="lon",
|
||||
field=models.FloatField(db_index=True, default=0),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 4.2.1 on 2023-05-21 17:44
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("events", "0015_basepoint_lat_basepoint_lon_city_lat_city_lon_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="basepoint",
|
||||
name="location",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="city",
|
||||
name="location",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="place",
|
||||
name="location",
|
||||
),
|
||||
]
|
|
@ -1,6 +1,5 @@
|
|||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from location_field.models.plain import PlainLocationField
|
||||
from polymorphic.models import PolymorphicModel
|
||||
from passfinder.utils.choices import count_max_length
|
||||
|
||||
|
@ -38,7 +37,12 @@ class City(OIDModel):
|
|||
region = models.ForeignKey(
|
||||
"Region", related_name="cities", null=True, on_delete=models.SET_NULL
|
||||
)
|
||||
location = PlainLocationField(zoom=6)
|
||||
lon = models.FloatField(default=0, db_index=True)
|
||||
lat = models.FloatField(default=0, db_index=True)
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return [self.lon, self.lat]
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
@ -55,11 +59,16 @@ class Place(OIDModel):
|
|||
)
|
||||
title = models.CharField(max_length=250)
|
||||
description = models.TextField()
|
||||
location = PlainLocationField(zoom=6)
|
||||
lon = models.FloatField(default=0, db_index=True)
|
||||
lat = models.FloatField(default=0, db_index=True)
|
||||
sites = ArrayField(models.CharField(max_length=250), null=True)
|
||||
phones = ArrayField(models.CharField(max_length=250), null=True)
|
||||
working_time = models.JSONField(null=True)
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return [self.lon, self.lat]
|
||||
|
||||
|
||||
class Tag(OIDModel):
|
||||
name = models.CharField(max_length=250)
|
||||
|
@ -82,10 +91,20 @@ class BasePoint(OIDModel, PolymorphicModel):
|
|||
"Place", related_name="points", null=True, on_delete=models.SET_NULL
|
||||
)
|
||||
sort = models.IntegerField(default=0)
|
||||
location = PlainLocationField(zoom=6)
|
||||
lon = models.FloatField(default=0, db_index=True)
|
||||
lat = models.FloatField(default=0, db_index=True)
|
||||
can_buy = models.BooleanField(default=True)
|
||||
priority = models.BooleanField(default=False)
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return [self.lon, self.lat]
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
# TODO: change to icon/first image
|
||||
return "https://akarpov.ru/media/uploads/files/qMO4dDfIXP.webp"
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from passfinder.users.models import User
|
||||
|
||||
admin.site.register(User)
|
|
@ -7,8 +7,25 @@
|
|||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["username", "name", "url"]
|
||||
fields = ["username", "email"]
|
||||
|
||||
|
||||
class UserRegisterSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ("username", "email", "password")
|
||||
extra_kwargs = {
|
||||
"url": {"view_name": "api:user-detail", "lookup_field": "username"}
|
||||
"password": {"write_only": True},
|
||||
"email": {"required": True},
|
||||
}
|
||||
|
||||
def create(self, validated_data):
|
||||
user = User.objects.create(
|
||||
username=validated_data["username"],
|
||||
email=validated_data["email"],
|
||||
)
|
||||
|
||||
user.set_password(validated_data["password"])
|
||||
user.save()
|
||||
|
||||
return user
|
||||
|
|
10
passfinder/users/api/urls.py
Normal file
10
passfinder/users/api/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
||||
|
||||
from .views import RegisterApiView
|
||||
|
||||
urlpatterns = [
|
||||
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
|
||||
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||
path("register/", RegisterApiView.as_view(), name="user_register"),
|
||||
]
|
|
@ -1,11 +1,12 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from rest_framework import status
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import status, generics, permissions
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from .serializers import UserSerializer
|
||||
from .serializers import UserSerializer, UserRegisterSerializer
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
@ -23,3 +24,16 @@ def get_queryset(self, *args, **kwargs):
|
|||
def me(self, request):
|
||||
serializer = UserSerializer(request.user, context={"request": request})
|
||||
return Response(status=status.HTTP_200_OK, data=serializer.data)
|
||||
|
||||
|
||||
class RegisterApiView(generics.CreateAPIView):
|
||||
"""Creates new user and sends verification email"""
|
||||
|
||||
serializer_class = UserRegisterSerializer
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
||||
@extend_schema(
|
||||
operation_id="auth_user_register",
|
||||
)
|
||||
def post(self, request, *args, **kwargs):
|
||||
return self.create(request, *args, **kwargs)
|
||||
|
|
60
poetry.lock
generated
60
poetry.lock
generated
|
@ -848,6 +848,21 @@ files = [
|
|||
[package.dependencies]
|
||||
Django = ">=3.2"
|
||||
|
||||
[[package]]
|
||||
name = "django-filter"
|
||||
version = "23.2"
|
||||
description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "django-filter-23.2.tar.gz", hash = "sha256:2fe15f78108475eda525692813205fa6f9e8c1caf1ae65daa5862d403c6dbf00"},
|
||||
{file = "django_filter-23.2-py3-none-any.whl", hash = "sha256:d12d8e0fc6d3eb26641e553e5d53b191eb8cec611427d4bdce0becb1f7c172b5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
Django = ">=3.2"
|
||||
|
||||
[[package]]
|
||||
name = "django-ipware"
|
||||
version = "5.0.0"
|
||||
|
@ -1013,6 +1028,31 @@ files = [
|
|||
django = ">=3.0"
|
||||
pytz = "*"
|
||||
|
||||
[[package]]
|
||||
name = "djangorestframework-simplejwt"
|
||||
version = "5.2.2"
|
||||
description = "A minimal JSON Web Token authentication plugin for Django REST Framework"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "djangorestframework_simplejwt-5.2.2-py3-none-any.whl", hash = "sha256:4c0d2e2513e12587d93501ac091781684a216c3ee614eb3b5a10586aef5ca845"},
|
||||
{file = "djangorestframework_simplejwt-5.2.2.tar.gz", hash = "sha256:d27d4bcac2c6394f678dea8b4d0d511c6e18a7f2eb8aaeeb8a7de601aeb77c42"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
django = "*"
|
||||
djangorestframework = "*"
|
||||
pyjwt = ">=1.7.1,<3"
|
||||
|
||||
[package.extras]
|
||||
crypto = ["cryptography (>=3.3.1)"]
|
||||
dev = ["Sphinx (>=1.6.5,<2)", "cryptography", "flake8", "ipython", "isort", "pep8", "pytest", "pytest-cov", "pytest-django", "pytest-watch", "pytest-xdist", "python-jose (==3.3.0)", "sphinx-rtd-theme (>=0.1.9)", "tox", "twine", "wheel"]
|
||||
doc = ["Sphinx (>=1.6.5,<2)", "sphinx-rtd-theme (>=0.1.9)"]
|
||||
lint = ["flake8", "isort", "pep8"]
|
||||
python-jose = ["python-jose (==3.3.0)"]
|
||||
test = ["cryptography", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "tox"]
|
||||
|
||||
[[package]]
|
||||
name = "djangorestframework-stubs"
|
||||
version = "1.10.0"
|
||||
|
@ -2010,6 +2050,24 @@ files = [
|
|||
[package.extras]
|
||||
plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.7.0"
|
||||
description = "JSON Web Token implementation in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "PyJWT-2.7.0-py3-none-any.whl", hash = "sha256:ba2b425b15ad5ef12f200dc67dd56af4e26de2331f965c5439994dad075876e1"},
|
||||
{file = "PyJWT-2.7.0.tar.gz", hash = "sha256:bd6ca4a3c4285c1a2d4349e5a035fdf8fb94e04ccd0fcbe6ba289dae9cc3e074"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
crypto = ["cryptography (>=3.4.0)"]
|
||||
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
|
||||
docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
|
||||
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.17.4"
|
||||
|
@ -2930,4 +2988,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "8461316ade8f4a6256022b829102583a19138c47a7d5c20ccb47d7ba50ec1a1f"
|
||||
content-hash = "9abf5a717109289c45bdc20e08a2b6ad6d3e0ef05dc56d194fa3a77450648a57"
|
||||
|
|
|
@ -49,6 +49,8 @@ sentry-sdk = "^1.12.0"
|
|||
django-location-field = "^2.7.0"
|
||||
django-polymorphic = "^3.1.0"
|
||||
annoy = "^1.17.2"
|
||||
django-filter = "^23.2"
|
||||
djangorestframework-simplejwt = "^5.2.2"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
|
Loading…
Reference in New Issue
Block a user