Merge remote-tracking branch 'origin/main'

This commit is contained in:
marzban-dev
2025-03-21 14:20:26 +03:30
11 changed files with 170 additions and 22 deletions
+22 -5
View File
@@ -8,10 +8,11 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Copy files to server
uses: appleboy/scp-action@v0.1.6
@@ -21,8 +22,19 @@ jobs:
password: ${{ secrets.SSH_PASSWORD }}
source: "."
target: "/root/hshop/"
rm: true
- name: SSH command to build and start Docker
- name: Deploy environment file
uses: appleboy/ssh-action@v0.1.6
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SSH_USER }}
password: ${{ secrets.SSH_PASSWORD }}
script: |
mkdir -p /root/hshop/backend/
printf "%s" "${{ secrets.ENV_FILE_CONTENT }}" > /root/hshop/backend/.env.local
- name: Build and start Docker containers
uses: appleboy/ssh-action@v0.1.6
with:
host: ${{ secrets.SERVER_HOST }}
@@ -30,6 +42,11 @@ jobs:
password: ${{ secrets.SSH_PASSWORD }}
script: |
cd /root/hshop/
docker compose down
docker compose build
docker compose up -d
docker compose down --remove-orphans --timeout 60
docker compose up --build --detach --remove-orphans
docker image prune -af
docker compose ps
+7
View File
@@ -242,3 +242,10 @@ class SecurityBreachAttemptModel(models.Model):
class Meta:
verbose_name = "تلاش نفوذ"
verbose_name_plural = "تلاش‌های نفوذ"
# class NotifModel(models.Model):
# subject = models.CharField(max_length=100)
# description = models.TextField()
# def __str__(self):
# return f'{self.subject[:30]}'
+3
View File
@@ -2,6 +2,8 @@ from django.urls import path
from . import views
from djoser.urls.jwt import views as djoser_jwt_views
urlpatterns = [
path('profile', views.ProfileView.as_view()),
path('verify', djoser_jwt_views.TokenVerifyView.as_view(), name='jwt-verify'),
@@ -13,6 +15,7 @@ urlpatterns = [
path('address/list', views.GetUserAddressesView.as_view(), name='list-addresses'),
path('address/<int:pk>', views.GetIDUserAddressView.as_view(), name='get-ID-address'),
path('subscribe', views.SubscribeView.as_view(), name='subscibe'),
path('unsubscribe', views.UnsubscribeView.as_view(), name='unsubscibe'),
path('attack/view/<int:pk>', views.ChangeViewAttack.as_view(), name='attack-view'),
path('logout', views.LogoutView.as_view(), name='logout'),
]
+27 -9
View File
@@ -11,12 +11,11 @@ from django.shortcuts import get_object_or_404, redirect
from rest_framework_simplejwt.tokens import RefreshToken
import ghasedak_sms
from django.views import View
# this works only need to be used
# class APIView(APIView):
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# if AllowAny in self.permission_classes or not self.permission_classes:
# self.authentication_classes = []
from rest_framework import serializers
from rest_framework_simplejwt.tokens import RefreshToken
class SendOTPView(APIView):
permission_classes = [AllowAny]
@extend_schema(
@@ -143,7 +142,9 @@ class CreateAddressView(generics.CreateAPIView):
permission_classes = [permissions.IsAuthenticated]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
user = self.request.user
is_first_address = not UserAddressModel.objects.filter(user=user).exists()
serializer.save(user=user, is_main=is_first_address)
class EditAddressView(generics.UpdateAPIView):
queryset = UserAddressModel.objects.all()
@@ -190,6 +191,25 @@ class SubscribeView(APIView):
return Response(status=status.HTTP_400_BAD_REQUEST)
class UnsubscribeSerializer(serializers.Serializer):
end_point = serializers.CharField()
class UnsubscribeView(APIView):
permission_classes = [IsAuthenticated]
serializer_class = UnsubscribeSerializer
def post(self, request):
endpoint = request.data.get("end_point")
if not endpoint:
return Response({"detail": "اند پوینت لازم است"}, status=status.HTTP_400_BAD_REQUEST)
deleted, _ = PushSubscription.objects.filter(user=request.user, endpoint=endpoint).delete()
if deleted:
return Response({"detail": "با موفقیت اشتراک پاک شد"}, status=status.HTTP_200_OK)
return Response({"detail": "اند پوینت پیدا نشد"}, status=status.HTTP_404_NOT_FOUND)
class ChangeViewAttack(View):
def get(self, request, pk):
attack = get_object_or_404(SecurityBreachAttemptModel, pk=pk)
@@ -198,8 +218,6 @@ class ChangeViewAttack(View):
return redirect('admin:account_securitybreachattemptmodel_changelist')
from rest_framework import serializers
from rest_framework_simplejwt.tokens import RefreshToken
class LogoutSerializer(serializers.Serializer):
refresh_token = serializers.CharField(help_text="Refresh token to be blacklisted")
@@ -0,0 +1,20 @@
# Generated by Django 5.1.2 on 2025-03-19 17:58
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('azbankgateways', '0006_bank_order'),
('order', '0023_remove_ordermodel_bank_records'),
]
operations = [
migrations.AlterField(
model_name='bank',
name='order',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bank_records', to='order.ordermodel'),
),
]
+1 -1
View File
@@ -143,7 +143,7 @@ USE_TZ = True
# Static Files Configuration
# ==============================================================================
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "custom_static"),
# os.path.join(BASE_DIR, "custom_static"),
BASE_DIR / "core" / "static",
]
+3
View File
@@ -5,3 +5,6 @@ class OrderConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'order'
verbose_name = 'سفارش'
def ready(self):
import order.signals
+15 -1
View File
@@ -20,7 +20,21 @@ class GetOrderPermission(BasePermission):
def has_object_permission(self, request, view, obj):
if obj.user != request.user:
return False
if obj.status != 'CART':
if obj.status == 'CART':
self.message = "سفارش در وضعیت سبد خرید است"
return False
return True
from rest_framework.permissions import BasePermission
class SetAddressPermissions(BasePermission):
message = "این ادرس متعلق به شما نیست."
def has_object_permission(self, request, view, obj):
if obj.user != request.user:
self.message = "این ادرس متعلق به شما نیست."
return False
return True
+24
View File
@@ -0,0 +1,24 @@
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import OrderModel
@receiver(pre_save, sender=OrderModel)
def order_status_changed(sender, instance, **kwargs):
if instance.pk:
previous = OrderModel.objects.get(pk=instance.pk)
if previous.status != instance.status:
send_change_status_notif(instance)
def send_change_status_notif(order):
pass
def update_cart_price_fields(order):
pass
def update_sell_data(order):
pass
def update_quantity(order):
pass
+3 -2
View File
@@ -1,16 +1,17 @@
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from .views import CartItemViews, CartView, OrderlistView, CartItemClear, ApplyDiscountView, OrderGetView
from .views import CartItemViews, CartView, OrderlistView, CartItemClear, ApplyDiscountView, OrderGetView, SetAddressForCartView
from .views import PaymentView, callback_view
urlpatterns = [
path('all', OrderlistView.as_view(), name='order-list'),
path('cart', CartView.as_view()),
path('cart/set-address', SetAddressForCartView.as_view()),
path('cart/discount', ApplyDiscountView.as_view()),
path('cart/all', CartItemClear.as_view()),
path('cart/item/<int:pk>', CartItemViews.as_view(), name='change-item-cart'),
path('payment', PaymentView.as_view(), name='payment'),
path('cart/payment', PaymentView.as_view(), name='payment'),
path('callback', callback_view, name='callback-gateway'),
path('<int:pk>', OrderGetView.as_view(), name='order-get'),
]
+42 -1
View File
@@ -7,13 +7,16 @@ from .serializers import *
# from cart.models import
from rest_framework import status
from .models import OrderItemModel, OrderModel, DiscountCode
from .permissons import CanDeleteCartItemPermissions, GetOrderPermission
from .permissons import CanDeleteCartItemPermissions, GetOrderPermission, SetAddressPermissions
from azbankgateways import bankfactories, models as bank_models
from azbankgateways.exceptions import AZBankGatewaysException
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
from utils.pagination import StructurePagination
from order.models import OrderModel
from django.urls import reverse
from account.models import UserAddressModel
# try:
# pass
# except DiscountNotAvailableError:
@@ -176,9 +179,22 @@ class OrderGetView(APIView):
order_ser = self.serializer_class(order_object, context={'request': request})
return Response(order_ser.data, status=status.HTTP_200_OK)
from rest_framework import serializers
class BankTypeSerializer(serializers.Serializer):
gateway_type = serializers.ChoiceField(choices=['BMI', 'SEP', 'ZARINPAL', 'IDPAY', 'ZIBAL', 'BAHAMTA', 'MELLAT', 'PAYV1'])
class PaymentView(APIView):
permission_classes = [IsAuthenticated]
serializer_class = BankTypeSerializer
@extend_schema(
description="choices=['BMI', 'SEP', 'ZARINPAL', 'IDPAY', 'ZIBAL', 'BAHAMTA', 'MELLAT', 'PAYV1']"
)
def post(self, request):
print(request.data.get('gateway_type'))
cart_order = get_object_or_404(OrderModel, user=request.user, status='CART')
amount = 5000
user_mobile_number = request.user.phone
@@ -237,3 +253,28 @@ def callback_view(request):
return HttpResponse(
"پرداخت با شکست مواجه شده است. اگر پول کم شده است ظرف مدت ۴۸ ساعت پول به حساب شما بازخواهد گشت."
)
class SetAddressSerilizer(serializers.Serializer):
address_id = serializers.IntegerField()
class SetAddressForCartView(APIView):
serializer_class = SetAddressSerilizer
permission_classes = [IsAuthenticated, SetAddressPermissions]
def post(self, request):
address_id = request.data.get('address_id', None)
if not address_id:
return Response({'detail': 'address_id را ارسال کنید'}, status=status.HTTP_400_BAD_REQUEST)
address_object = get_object_or_404(UserAddressModel, pk=address_id)
permission = SetAddressPermissions()
if not permission.has_object_permission(request, self, address_object):
return Response({"detail": permission.message}, status=status.HTTP_403_FORBIDDEN)
cart_order, created = OrderModel.objects.get_or_create(
user=request.user,
status='CART'
)
cart_order.address = address_object
cart_order.save()
return Response({'detail': 'ادرس با موفقیت انتخاب شد'})