diff --git a/apps/location/urls/web.py b/apps/location/urls/web.py index cac89037..e86a3992 100644 --- a/apps/location/urls/web.py +++ b/apps/location/urls/web.py @@ -1,7 +1,6 @@ """Location app web urlconf.""" from location.urls.common import urlpatterns as common_urlpatterns - urlpatterns = [] -urlpatterns.extend(common_urlpatterns) \ No newline at end of file +urlpatterns.extend(common_urlpatterns) diff --git a/apps/main/migrations/0017_feature_route.py b/apps/main/migrations/0017_feature_route.py new file mode 100644 index 00000000..0b0f46bb --- /dev/null +++ b/apps/main/migrations/0017_feature_route.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-10-07 14:39 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0016_merge_20190919_0954'), + ] + + operations = [ + migrations.AddField( + model_name='feature', + name='route', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='main.Page'), + ), + ] diff --git a/apps/main/migrations/0018_feature_source.py b/apps/main/migrations/0018_feature_source.py new file mode 100644 index 00000000..cf94cad2 --- /dev/null +++ b/apps/main/migrations/0018_feature_source.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-10-07 14:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0017_feature_route'), + ] + + operations = [ + migrations.AddField( + model_name='feature', + name='source', + field=models.PositiveSmallIntegerField(choices=[(0, 'Mobile'), (1, 'Web'), (2, 'All')], default=0, verbose_name='Source'), + ), + ] diff --git a/apps/main/models.py b/apps/main/models.py index fa6cf7d1..46598257 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -1,19 +1,23 @@ """Main app models.""" +from typing import Iterable + from django.conf import settings from django.contrib.contenttypes import fields as generic +from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.fields import JSONField from django.db import models +from django.db.models import Q from django.utils.translation import gettext_lazy as _ -from django.contrib.contenttypes.models import ContentType from advertisement.models import Advertisement +from configuration.models import TranslationSettings from location.models import Country from main import methods from review.models import Review from utils.models import (ProjectBaseMixin, TJSONField, - TranslatedFieldsMixin, ImageMixin) + TranslatedFieldsMixin, ImageMixin, PlatformMixin) from utils.querysets import ContentTypeQuerySetMixin -from configuration.models import TranslationSettings + # # @@ -109,7 +113,6 @@ class SiteSettingsQuerySet(models.QuerySet): class SiteSettings(ProjectBaseMixin): - subdomain = models.CharField(max_length=255, db_index=True, unique=True, verbose_name=_('Subdomain')) country = models.OneToOneField(Country, on_delete=models.PROTECT, @@ -150,7 +153,8 @@ class SiteSettings(ProjectBaseMixin): @property def published_sitefeatures(self): - return self.sitefeature_set.filter(published=True) + return self.sitefeature_set\ + .filter(Q(published=True) and Q(feature__source__in=[PlatformMixin.WEB, PlatformMixin.ALL])) @property def site_url(self): @@ -159,11 +163,27 @@ class SiteSettings(ProjectBaseMixin): domain=settings.SITE_DOMAIN_URI) -class Feature(ProjectBaseMixin): +class Page(models.Model): + """Page model.""" + + page_name = models.CharField(max_length=255, unique=True) + advertisements = models.ManyToManyField(Advertisement) + + class Meta: + """Meta class.""" + verbose_name = _('Page') + verbose_name_plural = _('Pages') + + def __str__(self): + return f'{self.page_name}' + + +class Feature(ProjectBaseMixin, PlatformMixin): """Feature model.""" slug = models.CharField(max_length=255, unique=True) priority = models.IntegerField(unique=True, null=True, default=None) + route = models.ForeignKey(Page, on_delete=models.PROTECT, null=True, default=None) site_settings = models.ManyToManyField(SiteSettings, through='SiteFeature') class Meta: @@ -181,6 +201,12 @@ class SiteFeatureQuerySet(models.QuerySet): def published(self, switcher=True): return self.filter(published=switcher) + def by_country_code(self, country_code: str): + return self.filter(site_settings__country__code=country_code) + + def by_sources(self, sources: Iterable[int]): + return self.filter(feature__source__in=sources) + class SiteFeature(ProjectBaseMixin): """SiteFeature model.""" @@ -351,19 +377,3 @@ class Carousel(models.Model): def model_name(self): if hasattr(self.content_object, 'establishment_type'): return self.content_object.establishment_type.name_translated - - - -class Page(models.Model): - """Page model.""" - - page_name = models.CharField(max_length=255, unique=True) - advertisements = models.ManyToManyField(Advertisement) - - class Meta: - """Meta class.""" - verbose_name = _('Page') - verbose_name_plural = _('Pages') - - def __str__(self): - return f'{self.page_name}' diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 03ea73e6..d425016d 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -25,6 +25,8 @@ class SiteFeatureSerializer(serializers.ModelSerializer): id = serializers.IntegerField(source='feature.id') slug = serializers.CharField(source='feature.slug') priority = serializers.IntegerField(source='feature.priority') + route = serializers.CharField(source='feature.route.page_name') + source = serializers.IntegerField(source='feature.source') class Meta: """Meta class.""" @@ -32,7 +34,9 @@ class SiteFeatureSerializer(serializers.ModelSerializer): fields = ('main', 'id', 'slug', - 'priority' + 'priority', + 'route', + 'source' ) diff --git a/apps/main/urls.py b/apps/main/urls.py deleted file mode 100644 index 12a98c84..00000000 --- a/apps/main/urls.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Main app urls.""" -from django.urls import path -from main import views - -app = 'main' - -urlpatterns = [ - path('determine-site/', views.DetermineSiteView.as_view(), name='determine-site'), - path('determine-location/', views.DetermineLocation.as_view(), name='determine-location'), - path('sites/', views.SiteListView.as_view(), name='site-list'), - path('site-settings//', views.SiteSettingsView.as_view(), name='site-settings'), - path('awards/', views.AwardView.as_view(), name='awards_list'), - path('awards//', views.AwardRetrieveView.as_view(), name='awards_retrieve'), - path('carousel/', views.CarouselListView.as_view(), name='carousel-list'), -] \ No newline at end of file diff --git a/apps/main/urls/__init__.py b/apps/main/urls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/main/urls/common.py b/apps/main/urls/common.py new file mode 100644 index 00000000..bac16add --- /dev/null +++ b/apps/main/urls/common.py @@ -0,0 +1,12 @@ +"""Main app urls.""" +from django.urls import path +from main.views.common import * + +app = 'main' + +common_urlpatterns = [ + path('awards/', AwardView.as_view(), name='awards_list'), + path('awards//', AwardRetrieveView.as_view(), name='awards_retrieve'), + path('carousel/', CarouselListView.as_view(), name='carousel-list'), +path('determine-location/', DetermineLocation.as_view(), name='determine-location') +] diff --git a/apps/main/urls/mobile.py b/apps/main/urls/mobile.py new file mode 100644 index 00000000..b0383d4e --- /dev/null +++ b/apps/main/urls/mobile.py @@ -0,0 +1,11 @@ +from main.urls.common import common_urlpatterns + +from django.urls import path + +from main.views.mobile import FeaturesView + +urlpatterns = [ + path('features/', FeaturesView.as_view(), name='features'), +] + +urlpatterns.extend(common_urlpatterns) diff --git a/apps/main/urls/web.py b/apps/main/urls/web.py new file mode 100644 index 00000000..2126b0c0 --- /dev/null +++ b/apps/main/urls/web.py @@ -0,0 +1,11 @@ +from main.urls.common import common_urlpatterns +from django.urls import path + +from main.views.web import DetermineSiteView, SiteListView, SiteSettingsView + +urlpatterns = [ + path('determine-site/', DetermineSiteView.as_view(), name='determine-site'), + path('sites/', SiteListView.as_view(), name='site-list'), + path('site-settings//', SiteSettingsView.as_view(), name='site-settings'), ] + +urlpatterns.extend(common_urlpatterns) diff --git a/apps/main/views/__init__.py b/apps/main/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/main/views.py b/apps/main/views/common.py similarity index 72% rename from apps/main/views.py rename to apps/main/views/common.py index ee06160e..e6fd3444 100644 --- a/apps/main/views.py +++ b/apps/main/views/common.py @@ -1,56 +1,9 @@ """Main app views.""" +from django.http import Http404 from rest_framework import generics, permissions from rest_framework.response import Response + from main import methods, models, serializers -from utils.serializers import EmptySerializer -from django.http import Http404 - - -class DetermineSiteView(generics.GenericAPIView): - """Determine user's site.""" - - permission_classes = (permissions.AllowAny,) - serializer_class = EmptySerializer - - def get(self, request, *args, **kwargs): - user_ip = methods.get_user_ip(request) - country_code = methods.determine_country_code(user_ip) - url = methods.determine_user_site_url(country_code) - return Response(data={'url': url}) - - -class DetermineLocation(generics.GenericAPIView): - """Determine user's location.""" - - permission_classes = (permissions.AllowAny,) - serializer_class = EmptySerializer - - def get(self, request, *args, **kwargs): - user_ip = methods.get_user_ip(request) - longitude, latitude = methods.determine_coordinates(user_ip) - city = methods.determine_user_city(user_ip) - if longitude and latitude and city: - return Response(data={'latitude': latitude, 'longitude': longitude, 'city': city}) - else: - raise Http404 - - -class SiteSettingsView(generics.RetrieveAPIView): - """Site settings View.""" - - lookup_field = 'subdomain' - permission_classes = (permissions.AllowAny,) - queryset = models.SiteSettings.objects.all() - serializer_class = serializers.SiteSettingsSerializer - - -class SiteListView(generics.ListAPIView): - """Site settings View.""" - - pagination_class = None - permission_classes = (permissions.AllowAny,) - queryset = models.SiteSettings.objects.with_country() - serializer_class = serializers.SiteSerializer # @@ -89,6 +42,7 @@ class SiteListView(generics.ListAPIView): # class SiteFeaturesRUDView(SiteFeaturesViewMixin, # generics.RetrieveUpdateDestroyAPIView): # """Site features RUD.""" +from utils.serializers import EmptySerializer class AwardView(generics.ListAPIView): @@ -111,3 +65,20 @@ class CarouselListView(generics.ListAPIView): serializer_class = serializers.CarouselListSerializer permission_classes = (permissions.AllowAny,) pagination_class = None + + +class DetermineLocation(generics.GenericAPIView): + """Determine user's location.""" + + permission_classes = (permissions.AllowAny,) + serializer_class = EmptySerializer + + def get(self, request, *args, **kwargs): + user_ip = methods.get_user_ip(request) + longitude, latitude = methods.determine_coordinates(user_ip) + city = methods.determine_user_city(user_ip) + if longitude and latitude and city: + return Response(data={'latitude': latitude, 'longitude': longitude, 'city': city}) + else: + raise Http404 + diff --git a/apps/main/views/mobile.py b/apps/main/views/mobile.py new file mode 100644 index 00000000..b992dbb8 --- /dev/null +++ b/apps/main/views/mobile.py @@ -0,0 +1,16 @@ +from rest_framework import generics, permissions + +from main import models, serializers +from utils.models import PlatformMixin + + +class FeaturesView(generics.ListAPIView): + pagination_class = None + permission_classes = (permissions.AllowAny,) + serializer_class = serializers.SiteFeatureSerializer + + def get_queryset(self): + return models.SiteFeature.objects\ + .prefetch_related('feature', 'feature__route') \ + .by_country_code(self.request.country_code) \ + .by_sources([PlatformMixin.ALL, PlatformMixin.MOBILE]) diff --git a/apps/main/views/web.py b/apps/main/views/web.py new file mode 100644 index 00000000..e1dc32ef --- /dev/null +++ b/apps/main/views/web.py @@ -0,0 +1,38 @@ +from typing import Iterable + +from rest_framework import generics, permissions + +from utils.serializers import EmptySerializer +from rest_framework.response import Response +from main import methods, models, serializers + + +class DetermineSiteView(generics.GenericAPIView): + """Determine user's site.""" + + permission_classes = (permissions.AllowAny,) + serializer_class = EmptySerializer + + def get(self, request, *args, **kwargs): + user_ip = methods.get_user_ip(request) + country_code = methods.determine_country_code(user_ip) + url = methods.determine_user_site_url(country_code) + return Response(data={'url': url}) + + +class SiteSettingsView(generics.RetrieveAPIView): + """Site settings View.""" + + lookup_field = 'subdomain' + permission_classes = (permissions.AllowAny,) + queryset = models.SiteSettings.objects.all() + serializer_class = serializers.SiteSettingsSerializer + + +class SiteListView(generics.ListAPIView): + """Site settings View.""" + + pagination_class = None + permission_classes = (permissions.AllowAny,) + queryset = models.SiteSettings.objects.with_country() + serializer_class = serializers.SiteSerializer diff --git a/project/urls/mobile.py b/project/urls/mobile.py index 0bcbd31c..0bea5305 100644 --- a/project/urls/mobile.py +++ b/project/urls/mobile.py @@ -4,6 +4,7 @@ app_name = 'mobile' urlpatterns = [ path('establishments/', include('establishment.urls.mobile')), + path('main/', include('main.urls.mobile')) # path('account/', include('account.urls.web')), # path('advertisement/', include('advertisement.urls.web')), # path('collection/', include('collection.urls.web')), diff --git a/project/urls/web.py b/project/urls/web.py index 59c08a6f..9c05e1a6 100644 --- a/project/urls/web.py +++ b/project/urls/web.py @@ -27,7 +27,7 @@ urlpatterns = [ path('notifications/', include(('notification.urls.web', "notification"), namespace='notification')), path('partner/', include('partner.urls.web')), path('location/', include('location.urls.web')), - path('main/', include('main.urls')), + path('main/', include('main.urls.web')), path('recipes/', include('recipe.urls.web')), path('translation/', include('translation.urls')), path('comments/', include('comment.urls.web')),