Skip to content

Commit

Permalink
Merge pull request #23 from hackathone-prosept-team2/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ratarov authored Dec 5, 2023
2 parents 05e8134 + a8f329a commit 118b97b
Show file tree
Hide file tree
Showing 38 changed files with 1,388 additions and 23,868 deletions.
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=db
POSTGRES_PORT=5432

ADMIN_EMAIL=[email protected]
ADMIN_PASSWORD=Password-123

# Domain for frontend docker container
DOMAIN_URL=http://127.0.0.1
50 changes: 50 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: mafia-app workflow

on:
push:
branches: [develop]

jobs:
build_and_push_to_docker_hub:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Push to Docker Hub
uses: docker/build-push-action@v2
with:
push: true
context: ./
tags: ${{ secrets.DOCKER_USERNAME }}/prosept_back:latest

deploy:
runs-on: ubuntu-latest
needs: build_and_push_to_docker_hub
steps:
- name: executing remote ssh commands to deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
key: ${{ secrets.SSH_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
password: ${{ secrets.PASSPHRASE }}
script: |
cd prosept_app/deploy/
sudo docker-compose down
sudo docker rm prosept_back
sudo docker rm prosept_nginx
sudo docker rmi ${{ secrets.DOCKER_USERNAME }}/prosept_back
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/prosept_back:latest
sudo docker-compose up -d --build
sudo docker exec -i prosept_back python manage.py migrate
sudo docker exec -i prosept_back python manage.py collectstatic --noinput
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ media/*
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
# <django-project-name>/staticfiles/
static/

### Django.Python Stack ###
# Byte-compiled / optimized / DLL files
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RUN pip3 install poetry && curl -sSL 'https://install.python-poetry.org' | pytho
ENV PYTHONPATH="$PYTHONPATH:/app"

RUN poetry config virtualenvs.create false \
&& poetry install $(test "$YOUR_ENV" == production && echo "--without dev") --no-interaction --no-ansi
&& poetry install --without dev --no-interaction --no-ansi

COPY . .

Expand Down
6 changes: 3 additions & 3 deletions apps/api/v1/dealers/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ def get_status(self, queryset, name, value):
"""Поиск по статусу."""
if not value:
return queryset
if value in ["-", "0"]:
return queryset.filter(status=value)
return queryset.exclude(status__in=["-", "0"])
if value == "-":
return queryset.filter(status=101)
return queryset.exclude(status=101)
15 changes: 15 additions & 0 deletions apps/api/v1/dealers/schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from drf_spectacular.utils import extend_schema, OpenApiParameter

from . import serializer as ser


dealer_schema = {
"list": extend_schema(description="Получение списка дилеров."),
Expand Down Expand Up @@ -31,3 +33,16 @@
),
"retrieve": extend_schema(description="Просмотр экземпляра ключа дилера."),
}


matches_schema = {
"post": extend_schema(responses=ser.MatchSerializer(many=True))
}


choose_match_schema = {
"post": extend_schema(
request=ser.ChooseMatchSerializer(),
responses=ser.MatchSerializer(many=True),
)
}
78 changes: 73 additions & 5 deletions apps/api/v1/dealers/serializer.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,60 @@
from rest_framework import serializers

from apps.dealers.models import Dealer, DealerKey
from apps.dealers.models import Dealer, DealerKey, Match
from apps.products.crud import product_exists

from ..products.serializer import ProductShortSerializer


class DealerSerializer(serializers.ModelSerializer):
"""Сериализатор для полей модели Дилер."""
class BaseDealerSerializer(serializers.ModelSerializer):
"""Базовый сериализатор для полей модели Дилер."""

class Meta:
model = Dealer
fields = ("id", "name")


class DealerSerializer(BaseDealerSerializer):
"""Сериализатор полей для списка Дилеров."""

pass


class DealerReportSerializer(BaseDealerSerializer):
"""Сериализатор полей для отчета по Дилерам."""

total_prices = serializers.IntegerField()
total_keys = serializers.IntegerField()
keys_with_product = serializers.IntegerField()
keys_without_product = serializers.SerializerMethodField()
confirmed_matches = serializers.IntegerField()
to_be_checked = serializers.IntegerField()
no_matches = serializers.IntegerField()

class Meta(BaseDealerSerializer.Meta):
fields = BaseDealerSerializer.Meta.fields + (
"total_prices",
"total_keys",
"keys_with_product",
"keys_without_product",
"confirmed_matches",
"to_be_checked",
"no_matches",
)

def get_keys_without_product(self, obj):
return obj.total_keys - obj.keys_with_product


class KeySerializer(serializers.ModelSerializer):
"""Сериализатор для полей Ключей/артикулов Дилера."""

dealer = DealerSerializer()
product = ProductShortSerializer()
name = serializers.CharField()
last_price = serializers.DecimalField(max_digits=7, decimal_places=2)
status = serializers.CharField()
similarity = serializers.SerializerMethodField()
# status = serializers.IntegerField()

class Meta:
model = DealerKey
Expand All @@ -29,7 +63,41 @@ class Meta:
"key",
"name",
"last_price",
"status",
# "status",
"similarity",
"dealer",
"product",
)

def get_similarity(self, obj):
if obj.status == 101:
return "-"
return obj.status


class MatchSerializer(serializers.ModelSerializer):
"""Сериализатор полей списка предлагаемых соответствий Ключ - Продукт."""

product = ProductShortSerializer()

class Meta:
model = Match
fields = ("id", "product", "similarity", "status")

def to_representation(self, instance):
rep = super().to_representation(instance)
rep["status"] = instance.get_status_display()
return rep


class ChooseMatchSerializer(serializers.Serializer):
"""Сериализатор выбора Продукта из предлагаемых соответствий."""

product_id = serializers.IntegerField()

def validate_product_id(self, value):
if not product_exists(product_id=value):
raise serializers.ValidationError(
"Указанный id продукта отсутствует в базе."
)
return value
55 changes: 54 additions & 1 deletion apps/api/v1/dealers/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
from drf_spectacular.utils import extend_schema_view

from rest_framework import views, status
from rest_framework.response import Response
from rest_framework.generics import ListAPIView
from rest_framework.viewsets import ReadOnlyModelViewSet

from apps.dealers.crud import list_dealers, list_keys
from apps.dealers.crud import (
list_dealers,
list_keys,
list_matches,
list_dealers_report_data,
)
from apps.dealers.services import decline_matches, choose_match

from ..pagination import CommonPagePagination
from .filters import DealerKeyFilter
Expand All @@ -17,6 +27,13 @@ class DealerViewset(ReadOnlyModelViewSet):
serializer_class = ser.DealerSerializer


class DealersReport(ListAPIView):
"""Отчет по дилерам Просепт."""

queryset = list_dealers_report_data()
serializer_class = ser.DealerReportSerializer


@extend_schema_view(**schema.key_schema)
class DealerKeyViewset(ReadOnlyModelViewSet):
"""Ключи/артикулы Дилеров компании Просепт."""
Expand All @@ -25,3 +42,39 @@ class DealerKeyViewset(ReadOnlyModelViewSet):
serializer_class = ser.KeySerializer
pagination_class = CommonPagePagination
filterset_class = DealerKeyFilter


@extend_schema_view(**schema.matches_schema)
class MatchView(ListAPIView):
"""Список предлагаемых соответствий Ключ - Продукт."""

serializer_class = ser.MatchSerializer

def get_queryset(self):
key_pk = self.kwargs.get("pk")
return list_matches(key_pk=key_pk)


@extend_schema_view(**schema.matches_schema)
class DeclineMatchesView(views.APIView):
"""Отклонение всех предлагаемых соответствий Ключ - Продукт."""

def post(self, request, pk):
key_pk = self.kwargs.get("pk")
matches = decline_matches(key_pk=key_pk)
serializer = ser.MatchSerializer(instance=matches, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)


@extend_schema_view(**schema.choose_match_schema)
class ChooseMatchView(views.APIView):
"""Выбор 1 предлагаемого соответствия Ключ - Продукт."""

def post(self, request, pk):
key_pk = self.kwargs.get("pk")
serializer = ser.ChooseMatchSerializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
product_id = serializer.validated_data["product_id"]
matches = choose_match(key_pk=key_pk, product_id=product_id)
serializer = ser.MatchSerializer(instance=matches, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
22 changes: 17 additions & 5 deletions apps/api/v1/prices/views.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
from django.shortcuts import get_object_or_404
from rest_framework.generics import ListAPIView
from rest_framework import views, status
from rest_framework.response import Response

from apps.dealers.models import DealerKey
from apps.prices.crud import list_key_prices
from apps.prices.services import delete_prices_and_relations, create_prices

from ..pagination import NestedPagePagination
from . import serializer as ser


class KeyPriceViewset(ListAPIView):
class KeyPriceView(ListAPIView):
"""Цены дилеров компании Просепт по 1 ключу."""

pagination_class = NestedPagePagination
serializer_class = ser.KeyPriceSerializer

def get_queryset(self):
key_pk = self.kwargs.get("pk")
dealer_key = get_object_or_404(DealerKey, pk=key_pk)
return list_key_prices(dealer_key=dealer_key)
return list_key_prices(key_pk=key_pk)


class PricesView(views.APIView):
"""Загрузка и удаление цен дилеров и связанных ключей дилеров."""

def post(self, request):
create_prices()
return Response(status=status.HTTP_201_CREATED)

def delete(self, request):
delete_prices_and_relations()
return Response(status=status.HTTP_204_NO_CONTENT)
32 changes: 26 additions & 6 deletions apps/api/v1/urls.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
from django.urls import include, path
from rest_framework import routers

from .dealers.views import DealerViewset, DealerKeyViewset
from .prices.views import KeyPriceViewset
from .dealers.views import (
ChooseMatchView,
DealerViewset,
DealerKeyViewset,
MatchView,
DeclineMatchesView,
DealersReport,
)
from .prices.views import PricesView, KeyPriceView
from .products.views import ProductViewset
from .users.views import UserViewset

app_name = "api"

router = routers.DefaultRouter()
router.register("products", ProductViewset, "products")
router.register("dealers", DealerViewset, "dealers")
router.register("keys", DealerKeyViewset, "keys")
# router.register("keys/<int:pk>/prices", KeyPriceViewset, "prices")
router.register("auth/users", UserViewset, "users")

urlpatterns = [
path("keys/<int:pk>/prices", KeyPriceViewset.as_view(), name="key_prices"),
path("dealers/report/", DealersReport.as_view(), name="dealers_report"),
path("keys/<int:pk>/prices/", KeyPriceView.as_view(), name="key_prices"),
path("keys/<int:pk>/matches/", MatchView.as_view(), name="get_matches"),
path(
"keys/<int:pk>/choose_match/",
ChooseMatchView.as_view(),
name="choose_match",
),
path(
"keys/<int:pk>/decline_matches/",
DeclineMatchesView.as_view(),
name="decline_all_matches",
),
path("prices/", PricesView.as_view(), name="add_and_delete_prices"),
path("", include(router.urls)),
path('auth/', include('djoser.urls')),
path('auth/', include('djoser.urls.authtoken')),
path("auth/", include("djoser.urls.authtoken")),
]
Loading

0 comments on commit 118b97b

Please sign in to comment.