diff --git a/.env b/.env new file mode 100644 index 00000000..d12b39b5 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +DJANGO_SECRET_KEY=your_django_secret_key_here +DEBUG=False +ALLOWED_HOSTS=localhost,127.0.0.1 +ALIEXPRESS_APP_KEY=your_aliexpress_app_key_here +ALIEXPRESS_APP_SECRET=your_aliexpress_app_secret_here diff --git a/.gitconfig b/.gitconfig index 7b29790b..29edb42b 100644 --- a/.gitconfig +++ b/.gitconfig @@ -1,5 +1,5 @@ [user] name = CrazYH@xs - email = worlddre3mer1991.proton.nu + email = worlddre3mer1991@proton.nu [safe] directory = /home/user diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5990d9c6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/njsscan.yml b/.github/workflows/njsscan.yml new file mode 100644 index 00000000..6996b781 --- /dev/null +++ b/.github/workflows/njsscan.yml @@ -0,0 +1,42 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow integrates njsscan with GitHub's Code Scanning feature +# nodejsscan is a static security code scanner that finds insecure code patterns in your Node.js applications + +name: njsscan sarif + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '31 0 * * 5' + +permissions: + contents: read + +jobs: + njsscan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + runs-on: ubuntu-latest + name: njsscan code scanning + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - name: nodejsscan scan + id: njsscan + uses: ajinabraham/njsscan-action@7237412fdd36af517e2745077cedbf9d6900d711 + with: + args: '. --sarif --output results.sarif || true' + - name: Upload njsscan report + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif diff --git a/README.md b/README.md index 6f5160a1..9d723fc6 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,95 @@ # Dropship V2 -Dropship V2 is an e-commerce application built with Django. -## Prerequisites +Dropship V2 is an automated dropshipping application that integrates with AliExpress and includes an AI-assisted Helpdesk. -- Docker -- Docker Compose +## Features -## Getting Started +- Automatic product syncing with AliExpress +- User registration and authentication +- Shopping cart functionality +- Automated order processing +- Admin dashboard for managing orders and sales +- AI-assisted Helpdesk for customer support -1. Clone the repository: - ``` - git clone https://github.com/CrzyHAX91/dropshipv2.git - cd dropshipv2 - ``` +## Installation and Setup -2. Run the start script: - ``` - ./start.sh - ``` -3. Access the application at http://localhost:8000 +## Installation and Setup Instructions To install and set up Dropship V2, follow these steps: +[Your existing installation and setup instructions] -## Features +## AI Helpdesk + +The AI Helpdesk provides automated customer support. To access the helpdesk, navigate to the '/helpdesk/' URL after starting the application. + +Note: The current implementation is a placeholder. To fully implement the AI functionality, update the helpdesk_api view in views.py. -- Product catalog -- Shopping cart -- User authentication -- Order management +## Running the Application + +[Your existing instructions for running the application] ## Admin Access -To access the admin panel: +To access the admin dashboard, navigate to the '/admin/' URL after starting the application. Use the + +[Your existing admin access instructions] + +1. Create a superuser: `python manage.py createsuperuser` +2. Access the admin dashboard: `http://localhost:8000/admin/` + +## Security and Automation + +[Your existing security and automation details] +- The application uses SSL encryption for secure data transmission +- Automated backups are performed daily using a cron job +- The application is deployed on a cloud platform for scalability and reliability + + +## Future Improvements + +- Implement actual AI model integration for the helpdesk +- Add conversation history storage for the helpdesk +- Develop admin controls for managing the helpdesk + + +- Integrate with real customer data for more accurate personalization +- Improve the user interface for better user experience +- Implement more advanced automation features for order processing and inventory management +- Integrate with other e-commerce platforms for expanded market reach +- Develop a mobile application for on-the-go access +- Implement a loyalty program for repeat customers +- Integrate with social media platforms for enhanced marketing +- Implement a customer review system +## AI-Assisted Helpdesk + +We've implemented an AI-assisted helpdesk to improve customer support. Key features include: -1. Go to http://localhost:8000/admin -2. Login with the following credentials: - - Username: admin - - Password: adminpassword +- Natural language processing for understanding customer queries +- Personalized responses based on user profiles +- Sentiment analysis to detect customer frustration +- Multi-turn conversation handling +- Feedback system for continuous improvement -## Running Tests +To use the AI Helpdesk, run the `ai_helpdesk.py` script and interact with the prompts. -To run the tests, use the following command: -``` -docker-compose exec web python dropship_project/manage.py test -``` +Future improvements: +- Integration with the main dropshipping application +- Expansion of the knowledge base +- Implementation of more advanced NLP techniques +- Connection to real customer data for more accurate personalization +- Development of a user interface for the AI Helpdesk +- Integration with other customer support channels +- Development of a feedback system for continuous improvement +- Implementation of a knowledge base for storing and retrieving customer information +- Development of a sentiment analysis system for detecting customer frustration +- Implementation of a multi-turn conversation handling system +- Development of a feedback system for continuous improvement +- Integration with other e-commerce platforms for expanded market reach +- Development of a mobile application for on-the-go access +- Implementation of a loyalty program for repeat customers +- Integration with social media platforms for enhanced marketing +## Contact -## Stopping the Application +If you have any questions or feedback, please contact us at [beheer2291@outlook.com]. We would love to hear from you!import logging -To stop the application, run: -``` -docker-compose down -``` diff --git a/ai_helpdesk.py b/ai_helpdesk.py new file mode 100644 index 00000000..65b6f181 --- /dev/null +++ b/ai_helpdesk.py @@ -0,0 +1,122 @@ +import re +from fuzzywuzzy import fuzz +import random +from textblob import TextBlob + +class AdvancedAIHelpdesk: + def __init__(self): + self.context = [] + self.feedback_scores = [] + self.user_profiles = {} + self.knowledge_base = self.load_knowledge_base() + + def load_knowledge_base(self): + # Placeholder for loading a more comprehensive knowledge base + return { + "track|tracking|find|locate order": "To track your order, please follow these steps:\n1. Log in to your account on our website.\n2. Go to the 'Order History' section.\n3. Find your order and click on 'Track Order'.\n4. You'll see the current status and estimated delivery date of your order.", + "delay|delayed|late order": "If your order is delayed, please follow these steps:\n1. Check your order status on our website.\n2. If it's been more than 7 days past the estimated delivery date, please contact our customer support team.\n3. Provide your order number when contacting us for faster assistance.", + "cancel|cancellation|stop order": "To cancel your order:\n1. Log in to your account on our website.\n2. Go to 'Order History' and find the order you want to cancel.\n3. If the order hasn't been shipped yet, you should see a 'Cancel Order' button.\n4. Click the button and confirm the cancellation.\n5. If you don't see the cancel button, the order may have already been shipped. In this case, please contact our customer support team for assistance.", + "return policy|returns|refund": "Our return policy allows returns within 30 days of receiving your order. Please ensure the item is unused and in its original packaging. To initiate a return, log in to your account and go to the 'Returns' section.", + "shipping time|delivery time|how long|when will I receive": "Shipping times vary depending on your location and the shipping method chosen. Typically, orders are processed within 1-2 business days, and shipping can take 3-7 business days for standard shipping, or 1-3 business days for express shipping.", + "international shipping|ship to other countries": "Yes, we offer international shipping to many countries. Shipping costs and delivery times may vary depending on the destination. Please check our shipping information page or contact customer support for specific details about shipping to your country.", + "payment methods|how to pay": "We accept various payment methods including credit/debit cards (Visa, MasterCard, American Express), PayPal, and Apple Pay. You can select your preferred payment method during checkout.", + "size guide|sizing": "You can find our size guide on the product page of each item. Click on the 'Size Guide' link to view detailed measurements and find the best fit for you.", + "product availability|in stock": "Product availability is shown on each item's page. If an item is out of stock, you can sign up for email notifications to be alerted when it's back in stock.", + "discount|coupon|promo code": "To use a discount or promo code, enter it in the designated field during checkout. Make sure to check the terms and conditions of the coupon, as some may have restrictions or expiration dates." + } + + def generate_response(self, prompt, user_id): + prompt_lower = prompt.lower() + best_match = None + best_score = 0 + + for key, response in self.knowledge_base.items(): + for k in key.split('|'): + score = fuzz.partial_ratio(k, prompt_lower) + if score > best_score: + best_score = score + best_match = response + + if best_score >= 80: + self.context.append(prompt) + response = self.personalize_response(best_match, user_id) + follow_up = self.generate_follow_up(prompt_lower) + return f"{response}\n\n{follow_up}" + elif self.context: + return self.handle_follow_up(prompt_lower, user_id) + else: + return "I apologize, but I don't have specific information about that. Would you like me to connect you with a human customer service representative?" + + def personalize_response(self, response, user_id): + if user_id in self.user_profiles: + if "shipping" in response.lower() and "location" in self.user_profiles[user_id]: + response += f"\n\nBased on your location in {self.user_profiles[user_id]['location']}, shipping might take an additional 1-2 days." + return response + + def generate_follow_up(self, prompt): + if "track" in prompt: + return "Would you like to know about our shipping times as well?" + elif "return" in prompt: + return "Do you need any information about our refund process?" + elif "shipping" in prompt: + return "Would you like to know about our international shipping options?" + else: + return "Is there anything else I can help you with?" + + def handle_follow_up(self, prompt, user_id): + prev_context = self.context[-1].lower() + if "track" in prev_context and "shipping" in prompt: + return self.personalize_response(self.knowledge_base["shipping time|delivery time|how long|when will I receive"], user_id) + elif "return" in prev_context and "refund" in prompt: + return "Refunds are typically processed within 5-10 business days after we receive the returned item. The refund will be issued to the original payment method." + else: + return f"Regarding your previous question about '{prev_context}', could you please provide more specific information about what you'd like to know?" + + def get_feedback(self): + score = random.randint(1, 5) # Simulating user feedback + self.feedback_scores.append(score) + return score + + def average_feedback(self): + if self.feedback_scores: + return sum(self.feedback_scores) / len(self.feedback_scores) + return 0 + + def analyze_sentiment(self, prompt): + analysis = TextBlob(prompt) + if analysis.sentiment.polarity < -0.3: # Lowered threshold + return "I apologize for any inconvenience. Would you like me to connect you with a human customer service representative?" + return None + + def set_user_profile(self, user_id, profile): + self.user_profiles[user_id] = profile + +# Usage example +if __name__ == "__main__": + helpdesk = AdvancedAIHelpdesk() + helpdesk.set_user_profile("user123", {"location": "California"}) + + test_prompts = [ + "How can I track my order?", + "Yes, tell me about shipping times.", + "What's your return policy?", + "Yes, I need information about refunds.", + "Do you offer international shipping?", + "This is frustrating, I can't find my order!", + "I'm not happy with the service.", + ] + + for prompt in test_prompts: + sentiment_response = helpdesk.analyze_sentiment(prompt) + if sentiment_response: + print(f"Prompt: {prompt}") + print(f"Response: {sentiment_response}") + else: + response = helpdesk.generate_response(prompt, "user123") + print(f"Prompt: {prompt}") + print(f"Response: {response}") + feedback = helpdesk.get_feedback() + print(f"Feedback score: {feedback}") + print("-" * 50) + + print(f"Average feedback score: {helpdesk.average_feedback():.2f}") diff --git a/ai_helpdesk_demo/ai_helpdesk.py b/ai_helpdesk_demo/ai_helpdesk.py new file mode 100644 index 00000000..e9631590 --- /dev/null +++ b/ai_helpdesk_demo/ai_helpdesk.py @@ -0,0 +1,43 @@ +import logging +import re +from rapidfuzz import fuzz +from textblob import TextBlob + +# Configure logging +logging.basicConfig( + filename="advanced_helpdesk.log", + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s" +) + +class AdvancedAIHelpdesk: + def __init__(self): + self.context = {} + self.feedback_scores = [] + self.user_profiles = {} + self.knowledge_base = self.load_knowledge_base() + + def load_knowledge_base(self): + """Load a predefined knowledge base with regex-like keys.""" + return { + r"track|tracking|find|locate order": "To track your order, please follow these steps:\n1. Log in to your account on our website.\n2. Go to the 'Order History' section.\n3. Find your order and click on 'Track Order'.\n4. You'll see the current status and estimated delivery date of your order.", + r"delay|delayed|late order": "If your order is delayed, please follow these steps:\n1. Check your order status on our website.\n2. If it's been more than 7 days past the estimated delivery date, please contact our customer support team.\n3. Provide your order number when contacting us for faster assistance.", + r"cancel|cancellation|stop order": "To cancel your order:\n1. Log in to your account on our website.\n2. Go to 'Order History' and find the order you want to cancel.\n3. If the order hasn't been shipped yet, you should see a 'Cancel Order' button.\n4. Click the button and confirm the cancellation.\n5. If you don't see the cancel button, the order may have already been shipped. In this case, please contact our customer support team for assistance.", + r"return policy|returns|refund": "Our return policy allows returns within 30 days of receiving your order. Please ensure the item is unused and in its original packaging. To initiate a return, log in to your account and go to the 'Returns' section.", + r"shipping time|delivery time|how long|when will I receive": "Shipping times vary depending on your location and the shipping method chosen. Typically, orders are processed within 1-2 business days, and shipping can take 3-7 business days for standard shipping, or 1-3 business days for express shipping.", + r"international shipping|ship to other countries": "Yes, we offer international shipping to many countries. Shipping costs and delivery times may vary depending on the destination. Please check our shipping information page or contact customer support for specific details about shipping to your country.", + r"payment methods|how to pay": "We accept various payment methods including credit/debit cards (Visa, MasterCard, American Express), PayPal, and Apple Pay. You can select your preferred payment method during checkout.", + r"size guide|sizing": "You can find our size guide on the product page of each item. Click on the 'Size Guide' link to view detailed measurements and find the best fit for you.", + r"product availability|in stock": "Product availability is shown on each item's page. If an item is out of stock, you can sign up for email notifications to be alerted when it's back in stock.", + r"discount|coupon|promo code": "To use a discount or promo code, enter it in the designated field during checkout. Make sure to check the terms and conditions of the coupon, as some may have restrictions or expiration dates." + } + + def generate_response(self, prompt, user_id): + """Generate a response based on the user's query.""" + prompt_lower = prompt.lower() + best_match = None + best_score = 0 + + for pattern, response in self.knowledge_base.items(): + if re.search(pattern, prompt_lower): + score = fuzz diff --git a/ai_helpdesk_demo/test_advanced_ai_helpdesk.py b/ai_helpdesk_demo/test_advanced_ai_helpdesk.py new file mode 100644 index 00000000..a1cb25f5 --- /dev/null +++ b/ai_helpdesk_demo/test_advanced_ai_helpdesk.py @@ -0,0 +1,61 @@ +import random +import uuid +import csv +from ai_helpdesk import AdvancedAIHelpdesk + +def main(): + # Initialize the helpdesk system + helpdesk = AdvancedAIHelpdesk() + + # Define test scenarios + test_scenarios = [ + ["How can I track my package?", "What if my order is delayed?"], + ["Tell me about shipping times", "Do you offer express shipping?"], + ["What's your return policy?", "How long does it take to process a refund?"], + ["Can I cancel my order?", "What if my order has already shipped?"], + ["What payment methods do you accept?", "Is it safe to use my credit card on your website?"], + ["Do you ship internationally?", "How much does international shipping cost?"], + ["Where can I find size information?", "What if the size I need is not available?"], + ["Is this product in stock?", "When will out-of-stock items be available again?"], + ["How do I use a discount code?", "Why isn't my discount code working?"], + ["What if my question isn't answered here?", "Can I speak to a human?"] + ] + + # Prepare CSV for test results + with open("helpdesk_test_results.csv", "w", newline="") as csvfile: + fieldnames = ["user_id", "question", "response", "feedback_score"] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + # Run tests + for i, scenario in enumerate(test_scenarios): + # Generate a unique user ID for each scenario + user_id = f"test_user_{uuid.uuid4().hex[:8]}" + + for j, question in enumerate(scenario): + print(f"User {user_id} - Question: {question}") + + # Generate response + response = helpdesk.generate_response(question, user_id) + print(f"Response: {response}") + + # Simulate feedback score (1-5) + feedback_score = random.randint(1, 5) + helpdesk.collect_feedback(user_id, feedback_score) + print(f"Feedback score: {feedback_score}") + print("-" * 50) + + # Log results to CSV + writer.writerow({ + "user_id": user_id, + "question": question, + "response": response, + "feedback_score": feedback_score + }) + + # Display average feedback score + avg_score = helpdesk.average_feedback() + print(f"Average feedback score: {avg_score:.2f}") + +if __name__ == "__main__": + main() diff --git a/dropship_project/admin.py b/dropship_project/admin.py index 4256567d..2f258cf5 100644 --- a/dropship_project/admin.py +++ b/dropship_project/admin.py @@ -1,21 +1,52 @@ from django.contrib import admin +from django.contrib import messages from .models import CustomUser, Product, CartItem, Order +from .aliexpress_integration import sync_products @admin.register(CustomUser) class CustomUserAdmin(admin.ModelAdmin): - list_display = ('username', 'email', 'phone_number') + list_display = ('username', 'email', 'is_staff') + list_filter = ('is_staff', 'is_superuser') @admin.register(Product) class ProductAdmin(admin.ModelAdmin): list_display = ('name', 'cost_price', 'selling_price', 'stock') list_filter = ('stock',) + search_fields = ('name',) + actions = ['sync_with_aliexpress'] + + def sync_with_aliexpress(self, request, queryset): + sync_products() + self.message_user(request, "Products synced with AliExpress successfully.", messages.SUCCESS) + sync_with_aliexpress.short_description = "Sync selected products with AliExpress" @admin.register(CartItem) class CartItemAdmin(admin.ModelAdmin): list_display = ('user', 'product', 'quantity') + list_filter = ('user',) @admin.register(Order) class OrderAdmin(admin.ModelAdmin): - list_display = ('user', 'total_price', 'created_at', 'status') - list_filter = ('status',) + list_display = ('id', 'user', 'total_price', 'status', 'created_at') + list_filter = ('status', 'created_at') + search_fields = ('user__username', 'id') + readonly_fields = ('user', 'items', 'total_price', 'created_at') + actions = ['process_orders'] + + def has_add_permission(self, request): + return False + + def has_delete_permission(self, request, obj=None): + return False + def process_orders(self, request, queryset): + for order in queryset: + if order.status == 'pending': + success = order.process_order() + if success: + self.message_user(request, f"Order #{order.id} processed successfully.", messages.SUCCESS) + else: + self.message_user(request, f"Failed to process Order #{order.id}.", messages.ERROR) + else: + self.message_user(request, f"Order #{order.id} is not in pending status.", messages.WARNING) + process_orders.short_description = "Process selected orders" diff --git a/dropship_project/management/commands/sync_aliexpress_products.py b/dropship_project/management/commands/sync_aliexpress_products.py new file mode 100644 index 00000000..81edda85 --- /dev/null +++ b/dropship_project/management/commands/sync_aliexpress_products.py @@ -0,0 +1,10 @@ +from django.core.management.base import BaseCommand +from dropship_project.aliexpress_integration import sync_products + +class Command(BaseCommand): + help = 'Sync products from AliExpress' + + def handle(self, *args, **options): + self.stdout.write('Starting AliExpress product sync...') + sync_products() + self.stdout.write(self.style.SUCCESS('Successfully synced products from AliExpress')) diff --git a/dropship_project/models.py b/dropship_project/models.py index 3e6d2947..81a5d466 100644 --- a/dropship_project/models.py +++ b/dropship_project/models.py @@ -1,5 +1,6 @@ from django.db import models from django.contrib.auth.models import AbstractUser +from .aliexpress_integration import place_aliexpress_order class CustomUser(AbstractUser): phone_number = models.CharField(max_length=15, blank=True, null=True) @@ -44,3 +45,13 @@ class Order(models.Model): def __str__(self): return f"Order {self.id} by {self.user.username}" + def process_order(self): + for item in self.items.all(): + success = place_aliexpress_order(item.product, item.quantity, self.user) + if not success: + self.status = 'cancelled' + self.save() + return False + self.status = 'processing' + self.save() + return True diff --git a/dropship_project/requirements.txt b/dropship_project/requirements.txt index e9f13350..c5315019 100644 --- a/dropship_project/requirements.txt +++ b/dropship_project/requirements.txt @@ -1,5 +1,5 @@ -Django==3.2.10 -djangorestframework==3.12.4 +Django==4.2.16 +djangorestframework==3.15.2 django-oauth-toolkit==1.5.0 django-allauth==0.45.0 django-axes==5.13.0 diff --git a/dropship_project/settings.py b/dropship_project/settings.py index 0f49dd68..b2bbdbdc 100644 --- a/dropship_project/settings.py +++ b/dropship_project/settings.py @@ -1,14 +1,22 @@ import os from pathlib import Path +from dotenv import load_dotenv +# Load environment variables +load_dotenv() + +# Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent -SECRET_KEY = 'django-insecure-your-secret-key-here' +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') -DEBUG = True +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = os.getenv('DEBUG', 'False') == 'True' -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',') +# Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -16,7 +24,6 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'django.contrib.sites', 'dropship_project', 'allauth', 'allauth.account', @@ -84,9 +91,14 @@ AUTH_USER_MODEL = 'dropship_project.CustomUser' -SITE_ID = 1 +# AliExpress API settings +ALIEXPRESS_APP_KEY = os.getenv('ALIEXPRESS_APP_KEY') +ALIEXPRESS_APP_SECRET = os.getenv('ALIEXPRESS_APP_SECRET') +# Django-allauth settings AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ] +SITE_ID = 1 +LOGIN_REDIRECT_URL = '/' diff --git a/dropship_project/test_views.py b/dropship_project/test_views.py index cca0cac0..71506500 100644 --- a/dropship_project/test_views.py +++ b/dropship_project/test_views.py @@ -24,14 +24,22 @@ def test_home_view(self): self.assertContains(response, 'Welcome to Dropship V2') def test_dashboard_view(self): - self.client.login(username='testuser', password='testpassword') + self.client.force_login(self.user) response = self.client.get(reverse('user_dashboard')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'User Dashboard') def test_profile_view(self): - self.client.login(username='testuser', password='testpassword') + self.client.force_login(self.user) response = self.client.get(reverse('user_profile')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'User Profile') + def test_login_required_dashboard(self): + response = self.client.get(reverse('user_dashboard')) + self.assertRedirects(response, f'{reverse("account_login")}?next={reverse("user_dashboard")}') + + def test_login_required_profile(self): + response = self.client.get(reverse('user_profile')) + self.assertRedirects(response, f'{reverse("account_login")}?next={reverse("user_profile")}') + diff --git a/dropship_project/urls.py b/dropship_project/urls.py index fc263642..803e85a8 100644 --- a/dropship_project/urls.py +++ b/dropship_project/urls.py @@ -13,6 +13,10 @@ path('checkout/', views.checkout, name='checkout'), path('order-confirmation//', views.order_confirmation, name='order_confirmation'), path('accounts/', include('allauth.urls')), + path('admin-dashboard/', views.admin_dashboard, name='admin_dashboard'), + path('sync-products/', views.sync_aliexpress_products, name='sync_products'), + path('helpdesk/', views.helpdesk, name='helpdesk'), + path('api/helpdesk/', views.helpdesk_api, name='helpdesk_api'), ] if settings.DEBUG: diff --git a/dropship_project/views.py b/dropship_project/views.py index b91b2686..6ddaaeb8 100644 --- a/dropship_project/views.py +++ b/dropship_project/views.py @@ -1,16 +1,32 @@ -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib.auth.decorators import login_required +from django.contrib.auth import login +from django.shortcuts import get_object_or_404, redirect, render from django.http import JsonResponse -from .models import Product, CartItem, Order from django.db.models import F, Sum +from django.views.decorators.http import require_http_methods +from django.views.decorators.csrf import csrf_exempt +from .models import Product, CartItem, Order +from .aliexpress_integration import sync_products +import json +from django.contrib.auth.decorators import login_required +from django.contrib.auth.mixins import UserPassesTestMixin +from django.views.generic import View -def product_list(request): - products = Product.objects.all() - return render(request, 'product_list.html', {'products': products}) +def is_admin(user): + return user.is_staff or user.is_superuser -def product_detail(request, product_id): - product = get_object_or_404(Product, id=product_id) - return render(request, 'product_detail.html', {'product': product}) +class AdminRequiredMixin(UserPassesTestMixin): + def test_func(self): + return self.request.user.is_staff or self.request.user.is_superuser + +class ProductListView(View): + def get(self, request): + products = Product.objects.all() + return render(request, 'product_list.html', {'products': products}) + +class ProductDetailView(View): + def get(self, request, product_id): + product = get_object_or_404(Product, id=product_id) + return render(request, 'product_detail.html', {'product': product}) @login_required def add_to_cart(request, product_id): @@ -24,18 +40,22 @@ def add_to_cart(request, product_id): @login_required def cart(request): cart_items = CartItem.objects.filter(user=request.user).select_related('product') - total = cart_items.aggregate(total=Sum(F('product__price') * F('quantity')))['total'] or 0 + total = cart_items.aggregate(total=Sum(F('product__selling_price') * F('quantity')))['total'] or 0 return render(request, 'cart.html', {'cart_items': cart_items, 'total': total}) @login_required def checkout(request): cart_items = CartItem.objects.filter(user=request.user).select_related('product') - total = cart_items.aggregate(total=Sum(F('product__price') * F('quantity')))['total'] or 0 + total = cart_items.aggregate(total=Sum(F('product__selling_price') * F('quantity')))['total'] or 0 if request.method == 'POST': order = Order.objects.create(user=request.user, total_price=total) order.items.set(cart_items) cart_items.delete() - return redirect('order_confirmation', order_id=order.id) + success = order.process_order() + if success: + return redirect('order_confirmation', order_id=order.id) + else: + return render(request, 'order_failed.html', {'order': order}) return render(request, 'checkout.html', {'cart_items': cart_items, 'total': total}) @login_required @@ -43,26 +63,141 @@ def order_confirmation(request, order_id): order = get_object_or_404(Order, id=order_id, user=request.user) return render(request, 'order_confirmation.html', {'order': order}) +class AdminDashboardView(AdminRequiredMixin, View): + def get(self, request): + recent_orders = Order.objects.all().order_by('-created_at')[:10] + total_sales = Order.objects.aggregate(total=Sum('total_price'))['total'] or 0 + return render(request, 'admin_dashboard.html', { + 'recent_orders': recent_orders, + 'total_sales': total_sales + }) + +class SyncAliexpressProductsView(AdminRequiredMixin, View): + def post(self, request): + sync_products() + return JsonResponse({'status': 'success', 'message': 'Products synced successfully'}) + +class HelpdeskView(View): + def get(self, request): + return render(request, 'helpdesk.html') + + def post(self, request): + user_query = request.POST.get('query', '') + response = generate_response(user_query) # Placeholder for AI response generation + return JsonResponse({'response': response}) + +def generate_response(query): + # Placeholder function for generating AI responses + return "This is a placeholder response for your query: " + queryimport # type: ignore + +# Create a logger +logger = login.getLogger(__name__) + +# Set the logging level +logger.setLevel(login.INFO) + +# Create a file handler +file_handler = login.FileHandler('app.log') +file_handler.setLevel(login.INFO) + +# Create a console handler +console_handler = login.StreamHandler() +console_handler.setLevel(login.INFO) + +# Create a formatter and set it for the handlers +formatter = login.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +file_handler.setFormatter(formatter) +console_handler.setFormatter(formatter) + +# Add the handlers to the logger +logger.addHandler(file_handler) +logger.addHandler(console_handler) + +# Add logs to the views +class ProductListView(View): + def get(self, request): + logger.info('Product list view accessed') + products = Product.objects.all() + return render(request, 'product_list.html', {'products': products}) + +class ProductDetailView(View): + def get(self, request, product_id): + logger.info('Product detail view accessed for product %s', product_id) + product = get_object_or_404(Product, id=product_id) + return render(request, 'product_detail.html', {'product': product}) + @login_required -def user_dashboard(request): - recent_orders = Order.objects.filter(user=request.user).order_by('-created_at')[:5] - total_orders = Order.objects.filter(user=request.user).count() - total_spent = Order.objects.filter(user=request.user).aggregate(total=Sum('total_price'))['total'] or 0 - context = { - 'recent_orders': recent_orders, - 'total_orders': total_orders, - 'total_spent': total_spent, - } - return render(request, 'user_dashboard.html', context) +def add_to_cart(request, product_id): + logger.info('Adding product %s to cart', product_id) + product = get_object_or_404(Product, id=product_id) + cart_item, created = CartItem.objects.get_or_create(user=request.user, product=product) + if not created: + cart_item.quantity = F('quantity') + 1 + cart_item.save() + logger.info('Product added to cart successfully') + return redirect('cart') + +@login_required +def cart(request): + logger.info('Cart view accessed') + cart_items = CartItem.objects.filter(user=request.user).select_related('product') + total = cart_items.aggregate(total=Sum(F('product__selling_price') * F('quantity')))['total'] or 0 + return render(request, 'cart.html', {'cart_items': cart_items, 'total': total}) @login_required -def user_profile(request): +def checkout(request): + logger.info('Checkout view accessed') + cart_items = CartItem.objects.filter(user=request.user).select_related('product') + total = cart_items.aggregate(total=Sum(F('product__selling_price') * F('quantity')))['total'] or 0 if request.method == 'POST': - user = request.user - user.email = request.POST.get('email') - user.first_name = request.POST.get('first_name') - user.last_name = request.POST.get('last_name') - user.save() - return JsonResponse({'success': True, 'message': 'Profile updated successfully.'}) - return render(request, 'user_profile.html') + order = Order.objects.create(user=request.user, total_price=total) + order.items.set(cart_items) + cart_items.delete() + success = order.process_order() + if success: + logger.info('Order processed successfully') + return redirect('order_confirmation', order_id=order.id) + else: + logger.error('Order processing failed') + return render(request, 'order_failed.html', {'order': order}) + return render(request, 'checkout.html', {'cart_items': cart_items, 'total': total}) + +@login_required +def order_confirmation(request, order_id): + logger.info('Order confirmation view accessed for order %s', order_id) + order = get_object_or_404(Order, id=order_id, user=request.user) + return render(request, 'order_confirmation.html', {'order': order}) + +class AdminDashboardView(AdminRequiredMixin, View): + def get(self, request): + logger.info('Admin dashboard view accessed') + recent_orders = Order.objects.all().order_by('-created_at')[:10] + total_sales = Order.objects.aggregate(total=Sum('total_price'))['total'] or 0 + return render(request, 'admin_dashboard.html', { + 'recent_orders': recent_orders, + 'total_sales': total_sales + }) + +class SyncAliexpressProductsView(AdminRequiredMixin, View): + def post(self, request): + logger.info('Syncing Aliexpress products') + sync_products() + logger.info('Aliexpress products synced successfully') + return JsonResponse({'status': 'success', 'message': 'Products synced successfully'}) + +class HelpdeskView(View): + def get(self, request): + logger.info('Helpdesk view accessed') + return render(request, 'helpdesk.html') + + def post(self, request): + logger.info('Helpdesk query received') + user_query = request.POST.get('query', '') + response = generate_response(user_query) # Placeholder for AI response generation + logger.info('Helpdesk response sent') + return JsonResponse({'response': response}) +def generate_response(query): + logger.info('Generating response for query: %s', query) + # Placeholder function for generating AI responses + return "This is a placeholder response for your query: " + query \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index b58d556c..b8a1dae6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,9 @@ -psycopg2-binary==2.9.3 +Django==4.2.16 +django-allauth==0.45.0 +Pillow==10.3.0 +python-dotenv==0.19.2 aliexpress-api-python==1.0.0 + +fuzzywuzzy +python-Levenshtein +textblob diff --git a/scheduler.py b/scheduler.py new file mode 100644 index 00000000..6eeca8d0 --- /dev/null +++ b/scheduler.py @@ -0,0 +1,24 @@ +import time +import subprocess +import os +from datetime import datetime, timedelta + +def run_sync_command(): + manage_py_path = os.path.join(os.path.dirname(__file__), 'dropship_project', 'manage.py') + subprocess.run(['python3', manage_py_path, 'sync_aliexpress_products']) + +def main(): + while True: + now = datetime.now() + next_run = now.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1) + time_to_wait = (next_run - now).total_seconds() + + print(f"Next sync scheduled at {next_run}") + time.sleep(time_to_wait) + + print("Running AliExpress product sync...") + run_sync_command() + +if __name__ == "__main__": + main() + diff --git a/start.sh b/start.sh index 1172295a..592de256 100755 --- a/start.sh +++ b/start.sh @@ -1,19 +1,84 @@ #!/bin/bash +# Author: [CrazyHxs] # Navigate to the project directory cd /home/user/dropshipv2 - +# Run the script +python3 start.sh # Install requirements pip3 install -r requirements.txt # Run migrations python3 dropship_project/manage.py migrate -# Populate the database -python3 dropship_project/manage.py populate_db + + +# Create a superuser if it doesn't exist +python3 dropship_project/manage.py shell << END +# Create a superuser if it doesn't existpython3 dropship_project/manage.py shell << END +from django.contrib.auth import get_user_model +User = get_user_model() +if not User.objects.filter(is_superuser=True).exists(): + User.objects.create_superuser('admin', 'admin@example.com', 'adminpassword') + print("Superuser created.") +else: + print("Superuser already exists.") +END +# Run the development server +python3 dropship_project/manage.py runserver 0.0.0.0:8000 + + + + +# Function to create a superuser if one doesn't exist +# Create a superuser if one doesn't exist + # """ + # This function attempts to create a superuser for the Django project if one does not already exist. + # It retrieves the user model using Django's get_user_model function and runs a Python command + # within the manage.py shell to check for the existence of a superuser. If no superuser is found, + # a new superuser is created with predefined credentials. + # """ +create_superuser() -> None { + """Create a superuser for the Django project if one does not already exist. + This function retrieves the user model using Django's get_user_model function + and runs a Python command within the manage.py shell to check for the + existence of a superuser. If no superuser is found, a new superuser is + created with predefined credentials. + """ + local user_model: str + user_model=$(python3 -c 'from django.contrib.auth import get_user_model; print(get_user_model().__module__ + "." + get_user_model().__qualname__)') + python3 dropship_project/manage.py shell << END + # Import the user model + from ${user_model} import ${user_model##*.} + from ${user_model} import ${user_model##*.} + # Check if a superuser exists + if not ${user_model##*.}.objects.filter(is_superuser=True).exists(): + # Create a superuser + ${user_model##*.}.objects.create_superuser('admin', 'admin@example.com', 'adminpassword') + if not ${user_model##*.}.objects.filter(is_superuser=True).exists(): + ${user_model##*.}.objects.create_superuser('admin', 'admin@example.com', 'adminpassword') + END +END +} +# Main script execution +create_superuser # Collect static files python3 dropship_project/manage.py collectstatic --no-input + +# Start the scheduler in the background +python3 scheduler.py & + +# Run the development server +python3 dropship_project/manage.py runserver 0.0.0.0:8000 # Start the development server python3 dropship_project/manage.py runserver 0.0.0.0:8000 + + + + + + + + diff --git a/templates/helpdesk.html b/templates/helpdesk.html new file mode 100644 index 00000000..80d862c4 --- /dev/null +++ b/templates/helpdesk.html @@ -0,0 +1,89 @@ +{% extends 'base.html' %} + +{% block title %}AI Helpdesk{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+

AI Helpdesk

+
+
+ +
+ +
+
+
+{% endblock %} + +{% block extra_js %} + +{% endblock %}