diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..6c287c1 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,35 @@ +name: Deploy to Server + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Copy files to server + uses: appleboy/scp-action@v0.1.6 + with: + host: ${{ secrets.SERVER_HOST }} + username: ${{ secrets.SSH_USER }} + password: ${{ secrets.SSH_PASSWORD }} + source: "." + target: "/root/hshop/" + + - name: SSH command to build and start Docker + uses: appleboy/ssh-action@v0.1.6 + with: + host: ${{ secrets.SERVER_HOST }} + username: ${{ secrets.SSH_USER }} + password: ${{ secrets.SSH_PASSWORD }} + script: | + cd /root/hshop/ + docker compose down + docker compose build + docker compose up -d \ No newline at end of file diff --git a/backend/.env.local b/backend/.env.local index 9e28739..e6e4d43 100644 --- a/backend/.env.local +++ b/backend/.env.local @@ -2,11 +2,11 @@ DEBUG = True # keep debug true to set the database to sqlite # postgres database info -DB_NAME = '' -DB_USER = '' -DB_PASSWORD = '' -DB_HOST = '' -DB_PORT = '' +DB_NAME = 'hshop' +DB_USER = 'byeto' +DB_PASSWORD = 'vuhbyq-cypMu0-sirbon' +DB_HOST = 'db' +DB_PORT = 5434 SECRET_KEY = '2h&gmi54wqauwqht48l-9c)r6_67_(oe_$ll%(+xz%u#)+of@d' # email stuff EMAIL_BACKEND = '' @@ -17,9 +17,9 @@ DEFAULT_FROM_EMAIL = '' # telegram bot toekn TELEGRAM_BOT_TOKEN = '' # domain for allowed host and allowed cors -DOMAIN = '' +DOMAIN = '38.60.202.91' # domain for api (the domain that django will use) -API_DOMAIN = '' +API_DOMAIN = '38.60.202.91' SITE_TITLE = '' SITE_HEADER = '' # jwt token configs diff --git a/backend/account/views.py b/backend/account/views.py index eeeb285..ad9ceba 100644 --- a/backend/account/views.py +++ b/backend/account/views.py @@ -9,6 +9,7 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter from rest_framework_simplejwt.views import TokenObtainPairView from django.shortcuts import get_object_or_404 from rest_framework_simplejwt.tokens import RefreshToken +import ghasedak_sms class SendOTPView(APIView): permission_classes = [AllowAny] @extend_schema( @@ -24,18 +25,45 @@ class SendOTPView(APIView): ) def post(self, request): phone = request.data.get('phone') + if not phone: + return Response({'detail': 'Phone number is required'}, status=status.HTTP_400_BAD_REQUEST) + try: user, created = User.objects.get_or_create(phone=phone) - print(created) - print(user.phone) - otp = user.set_otp() + otp = user.set_otp() message = f"کد یک بار مصرف : {otp}" - print(message) - # send otp - return Response({'detail': 'OTP sent successfully'}, status=status.HTTP_200_OK) + + + sms_api = ghasedak_sms.Ghasedak(api_key="4dc844abd4409fe247ec73831aed2498ad3749c1945660cc252654371756b966vafe5d9LGgMbnfGn") + + # response = sms_api.send_single_sms(ghasedak_sms.SendSingleSmsInput(message=message, receptor=phone, line_number='30005006006908', send_date='', client_reference_id='')) + # print(response) + + + + response = sms_api.send_single_sms( + ghasedak_sms.SendSingleSmsInput( + message=message, + receptor=phone, + line_number='90002930', + send_date='', + client_reference_id='' + ) + ) + + # response = sms_api.send_otp_sms(otp_input) + + if response['statusCode'] == 200: + return Response({'detail': 'OTP sent successfully'}, status=status.HTTP_200_OK) + else: + print('remmber to remove #TODO') + return Response({'detail': f'OTP sent successfully {otp}'}, status=status.HTTP_200_OK) + # return Response({'detail': response, 'otp_code': otp}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) except User.DoesNotExist: - return Response({'detail': 'User not found'}, status=status.HTTP_404_NOT_FOUND) + return Response({'detail': 'user not found'}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + return Response({'detail': f'An error occurred: {response}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) class CustomTokenObtainPairView(TokenObtainPairView): diff --git a/backend/core/settings.py b/backend/core/settings.py index 208fcdd..75226ed 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -27,7 +27,7 @@ EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") DEFAULT_FROM_EMAIL = os.getenv("SECRET_KEY") SECRET_KEY = os.getenv("SECRET_KEY") -DEBUG = os.getenv("DEBUG") +DEBUG = False # in production lists of allowed hosts and allowed orgins will genrate # in development every host and orgin will be true # in prodcution it will use the postgres info you enterd in .env.local @@ -39,18 +39,18 @@ if not DEBUG: f"https://{DOMAIN}", f"http://{DOMAIN}", ] - CORS_ALLOWED_ORIGINS = [f"https://{API_DOMAIN}", f"http://{API_DOMAIN}", - f"http://{DOMAIN}", f"https://{DOMAIN}", ] - + # CORS_ALLOWED_ORIGINS = [f"https://{API_DOMAIN}", f"http://{API_DOMAIN}", + # f"http://{DOMAIN}", f"https://{DOMAIN}", ] + CORS_ALLOW_ALL_ORIGINS = True # database postgres DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.getenv("DB_NAME"), - 'USER': os.getenv("DB_USER"), - 'PASSWORD': os.getenv("DB_PASSWORD"), - 'HOST': os.getenv("DB_HOST"), - 'PORT': os.getenv("DB_PORT"), + 'NAME': "hshop", + 'USER': "byeto", + 'PASSWORD': "vuhbyq-cypMu0-sirbon", + 'HOST': 'db', + 'PORT': 5432, } } else: diff --git a/backend/utils/sms.py b/backend/utils/sms.py index e0de4c8..4822747 100644 --- a/backend/utils/sms.py +++ b/backend/utils/sms.py @@ -13,4 +13,38 @@ sms_api = Ghasedak(api_key=os.getenv("SMS_API_KEY")) ### ارسال پیام otp - #response = sms_api.send_otp_sms(receptor='09359****', message='OTP message') \ No newline at end of file + #response = sms_api.send_otp_sms(receptor='09359****', message='OTP message') + + + +import ghasedak_sms + +# Initialize the Ghasedak API client with your API key +sms_api = ghasedak_sms.Ghasedak(api_key="Your_API_KEY") + +# Define the OTP code and the recipient's phone number +otp_code = "123456" # Replace with the generated OTP code +phone_number = "09xxxxxxxxx" # Replace with the recipient's phone number + +# Create the OTP input object +otp_input = ghasedak_sms.SendOtpInput( + send_date=None, # Immediate send; use a specific datetime for scheduled send + receptors=[ + ghasedak_sms.SendOtpReceptorDto( + mobile=phone_number, + # client_reference_id='optional_client_ref_id' # Optional: Add if you have a client reference ID + ) + ], + template_name="YourTemplateName", # Replace with your OTP template name + inputs=[ + ghasedak_sms.SendOtpInput.OtpInput(param="Code", value=otp_code), + # Add more parameters if your template requires them + ], + udh=False # Set to True if you need User Data Header; typically False for standard SMS +) + +# Send the OTP SMS +response = sms_api.send_otp_sms(otp_input) + +# Print the response to check the result +print(response) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f528766..0aad9e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,13 @@ services: - # frontend: - # build: - # context: ./frontend - # ports: - # - "80:3000" - # depends_on: - # - django + frontend: + build: + context: ./frontend + ports: + - "80:3000" + depends_on: + - django + networks: + - default django: build: @@ -18,22 +20,28 @@ services: - ./backend:/app - media_data:/app/media command: ["sh", "-c", "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"] - + networks: + - default db: image: postgres:16 environment: - POSTGRES_DB: shop_db + POSTGRES_DB: hshop POSTGRES_USER: byeto POSTGRES_PASSWORD: vuhbyq-cypMu0-sirbon volumes: - postgres_data:/var/lib/postgresql/data ports: - - "5434:5432" + - "5434:5432" + networks: + - default + + volumes: postgres_data: media_data: - +networks: + default: \ No newline at end of file diff --git a/frontend/assets/css/tailwind.css b/frontend/assets/css/tailwind.css index c01171f..4e59175 100644 --- a/frontend/assets/css/tailwind.css +++ b/frontend/assets/css/tailwind.css @@ -120,15 +120,20 @@ --breakpoint-xs: 480px; /* ANIMATIONS */ +<<<<<<< HEAD --animate-marquee: marquee 3s linear infinite; --animate-slide-down: slideDown 300ms ease-out; --animate-slide-up: slideUp 300ms ease-out; --animate-overlay-show: overlayShow 150ms ease-in; --animate-content-show: contentShow 150ms ease-in; +======= + --animate-marquee: marquee 25s linear infinite; + --animate-marquee-reverse: marquee 25s linear infinite reverse; +>>>>>>> be4fa509843c81855f5ffc118150196c94a7b17b @keyframes marquee { to { - transform: translateY(-50%); + transform: translateX(50%); } } diff --git a/frontend/components/global/BlogPost.vue b/frontend/components/global/BlogPost.vue new file mode 100644 index 0000000..7c43a15 --- /dev/null +++ b/frontend/components/global/BlogPost.vue @@ -0,0 +1,117 @@ + + + \ No newline at end of file diff --git a/frontend/components/global/Brands.vue b/frontend/components/global/Brands.vue new file mode 100644 index 0000000..5fa82ef --- /dev/null +++ b/frontend/components/global/Brands.vue @@ -0,0 +1,73 @@ + + + \ No newline at end of file diff --git a/frontend/components/global/CategoryCard.vue b/frontend/components/global/CategoryCard.vue new file mode 100644 index 0000000..f62fa67 --- /dev/null +++ b/frontend/components/global/CategoryCard.vue @@ -0,0 +1,47 @@ + + + \ No newline at end of file diff --git a/frontend/components/global/product-detail/RelatedProducts.vue b/frontend/components/global/product-detail/ProductsSlider.vue similarity index 99% rename from frontend/components/global/product-detail/RelatedProducts.vue rename to frontend/components/global/product-detail/ProductsSlider.vue index b587a20..5f9870f 100644 --- a/frontend/components/global/product-detail/RelatedProducts.vue +++ b/frontend/components/global/product-detail/ProductsSlider.vue @@ -3,6 +3,7 @@ import { Swiper, SwiperSlide } from "swiper/vue"; import type { SwiperClass } from "swiper/react"; + // types type Props = { @@ -22,6 +23,7 @@ const swiper_instance = ref(null); const onSwiper = (swiper: SwiperClass) => { swiper_instance.value = swiper; }; +