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 e3d4052..4e59175 100644 --- a/frontend/assets/css/tailwind.css +++ b/frontend/assets/css/tailwind.css @@ -120,14 +120,60 @@ --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: translateX(50%); } } + + @keyframes slideDown { + from { + height: 0; + } + to { + height: var(--reka-accordion-content-height); + } + } + + @keyframes slideUp { + from { + height: var(--reka-accordion-content-height); + } + to { + height: 0; + } + } + + @keyframes overlayShow { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + @keyframes contentShow { + from { + opacity: 0; + transform: translate(-50%, -48%) scale(0.96); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } + } } /* CONTAINER */ diff --git a/frontend/components/global/ServiceHighlights.vue b/frontend/components/global/ServiceHighlights.vue new file mode 100644 index 0000000..7ea8f5b --- /dev/null +++ b/frontend/components/global/ServiceHighlights.vue @@ -0,0 +1,61 @@ + + + + + + + + + + + + {{ highlight.title }} + + + {{ highlight.description }} + + + + + + + + + + diff --git a/frontend/components/global/product-detail/ProductsSlider.vue b/frontend/components/global/product-detail/ProductsSlider.vue index 3ad0d83..5f9870f 100644 --- a/frontend/components/global/product-detail/ProductsSlider.vue +++ b/frontend/components/global/product-detail/ProductsSlider.vue @@ -27,7 +27,7 @@ const onSwiper = (swiper: SwiperClass) => { - + {{ title }} @@ -90,7 +90,7 @@ const onSwiper = (swiper: SwiperClass) => { - + diff --git a/frontend/components/global/product/Accordion.vue b/frontend/components/global/product/Accordion.vue new file mode 100644 index 0000000..3736ce4 --- /dev/null +++ b/frontend/components/global/product/Accordion.vue @@ -0,0 +1,132 @@ + + + + + + مشخصات + + + + + + + + صفحه نمایش + + + روشنایی :3000mn + + + روشنایی :3000mn + + + + + + + + + مشخصات + + + + + + + + صفحه نمایش + + + روشنایی :3000mn + + + روشنایی :3000mn + + + + + + + + + مشخصات + + + + + + + + صفحه نمایش + + + روشنایی :3000mn + + + روشنایی :3000mn + + + + + + + + + + + + + diff --git a/frontend/components/product/Comments.vue b/frontend/components/product/ProductComments.vue similarity index 100% rename from frontend/components/product/Comments.vue rename to frontend/components/product/ProductComments.vue diff --git a/frontend/components/product/ProductDetails.vue b/frontend/components/product/ProductDetails.vue new file mode 100644 index 0000000..6ba8b56 --- /dev/null +++ b/frontend/components/product/ProductDetails.vue @@ -0,0 +1,38 @@ + + + + جزيات محصول + + + + + + + + داخل جعبه چیه؟ + + + + + + Headphones + + + + + + + + + + + diff --git a/frontend/components/product/Video.vue b/frontend/components/product/ProductVideo.vue similarity index 83% rename from frontend/components/product/Video.vue rename to frontend/components/product/ProductVideo.vue index 82f77c4..dc7479e 100644 --- a/frontend/components/product/Video.vue +++ b/frontend/components/product/ProductVideo.vue @@ -1,7 +1,7 @@ - + - + diff --git a/frontend/components/products/FilterButton.vue b/frontend/components/products/FilterButton.vue new file mode 100644 index 0000000..097aa0f --- /dev/null +++ b/frontend/components/products/FilterButton.vue @@ -0,0 +1,78 @@ + + + + + + + فیلتر محصولات + + + + + + + Edit profile + + + Make changes to your profile here. Click save when you're + done. + + + + Name + + + + + + Username + + + + + + + Save changes + + + + + + + + + + + + diff --git a/frontend/dockerfile b/frontend/dockerfile new file mode 100644 index 0000000..52d9096 --- /dev/null +++ b/frontend/dockerfile @@ -0,0 +1,13 @@ +FROM node:20-alpine as build-stage +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +FROM node:20-alpine as production-stage +WORKDIR /app +COPY --from=build-stage /app /app +EXPOSE 3000 +ENV NODE_ENV=production +CMD ["npm", "run", "start"] \ No newline at end of file diff --git a/frontend/layouts/Default.vue b/frontend/layouts/Default.vue index 8a409fe..1e0fa55 100644 --- a/frontend/layouts/Default.vue +++ b/frontend/layouts/Default.vue @@ -11,11 +11,17 @@ - + - + + + + diff --git a/frontend/pages/product/[id].vue b/frontend/pages/product/[id].vue index d50937b..056cfac 100644 --- a/frontend/pages/product/[id].vue +++ b/frontend/pages/product/[id].vue @@ -1,8 +1,11 @@ - - - - + + + + + + + diff --git a/frontend/pages/products.vue b/frontend/pages/products.vue new file mode 100644 index 0000000..e8e68c0 --- /dev/null +++ b/frontend/pages/products.vue @@ -0,0 +1,35 @@ + + + + + + + + خانه + / + محصولات + / + همه + + همه محصولات + + + + + + + + + + + + +
+ {{ highlight.description }} +