diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..c6e57ca812 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,48 @@ +name: Lint Code + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + +jobs: + lint_python: + name: Lint Python Files + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 # official action :contentReference[oaicite:0]{index=0} + with: + python-version: "3.12" + + - name: Install Flake8 + run: | + python -m pip install --upgrade pip + pip install flake8 # standard CLI install :contentReference[oaicite:1]{index=1} + + - name: Run Flake8 + run: flake8 . --extend-ignore=F401,F403,E225,E231,E265,E301,E302,E303,E722,E501,W292,W293,W391,W503,W504,W605,E731,E203,W291,E211,E275,F712,E275,811,E402,E722,E731,E201,E131,E117,F841,E712,E811,E501,E722,E731,E203,W291,E211,E275,F712,E275,F811,E402,E722,E731,E201,E131,E117,F841,E712,W503,W504,W605 + #ignore: F401,F403,E225,E231,E265,E301,E302,E303,E722,E501,W292,W293,W391,W503,W504,W605,E722,E731 + + + lint_js: + name: Lint JavaScript Files + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Node + uses: actions/setup-node@v3 # GitHub‑maintained action :contentReference[oaicite:2]{index=2} + with: + node-version: "18" # any modern LTS is fine :contentReference[oaicite:3]{index=3} + + - name: Install JSHint + run: npm install --global jshint # official install cmd :contentReference[oaicite:4]{index=4} + + - name: Run JSHint + run: jshint ./server/database diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000000..facd0daa8b --- /dev/null +++ b/.jshintrc @@ -0,0 +1,7 @@ +{ + "esversion": 8, // enable ES2017: const/let, =>, async/await ✔ :contentReference[oaicite:2]{index=2} + "node": true, // recognise Node globals (require, module, etc.) ✔ :contentReference[oaicite:3]{index=3} + "asi": true, // allow automatic semicolon insertion ✔ :contentReference[oaicite:4]{index=4} + "sub": true, // no dot‑notation nag for obj['prop'] ✔ :contentReference[oaicite:5]{index=5} + "expr": true // permit lone expressions (optional) +} diff --git a/README.md b/README.md index 5884e26a5b..87b540caef 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# coding-project-template \ No newline at end of file +# coding-project-template +#Coding start now 03/17/2025 \ No newline at end of file diff --git a/auth/Online_course_blog b/auth/Online_course_blog new file mode 160000 index 0000000000..2b14b1b6d8 --- /dev/null +++ b/auth/Online_course_blog @@ -0,0 +1 @@ +Subproject commit 2b14b1b6d83f46cc5af9748c1e8ebe4a81bb7fb7 diff --git a/auth/online1/crud/models.py b/auth/online1/crud/models.py new file mode 100644 index 0000000000..b2212625f5 --- /dev/null +++ b/auth/online1/crud/models.py @@ -0,0 +1,20 @@ +from django.db import models +from django.utils.timezone import now + +# Define your models from here: + +# class User(models.Model): +# first_name = models.CharField(null=False,max_length=30, default='jitendra') +# last_name = models.CharField(null=False,max_length=30, default='kumar') +# dob = models.DateField(null=True) + +# def __str__(self): +# return self.first_name + " " + \ +# self.last_name +# class Instructor(models.Model): +# full_time = models.BooleanField(default=True) +# total_learners = models.IntegerField() +# def __str__(self): +# return "First name :" +self.first_name + " ," + \ +# "Last name :" +self.last_name+ " ," + \ +# "Is full time :"+ str(self.full) diff --git a/auth/online1/manage.py b/auth/online1/manage.py new file mode 100644 index 0000000000..57b0209564 --- /dev/null +++ b/auth/online1/manage.py @@ -0,0 +1,18 @@ +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) \ No newline at end of file diff --git a/auth/online1/read_courses.py b/auth/online1/read_courses.py new file mode 100644 index 0000000000..e36ae047ea --- /dev/null +++ b/auth/online1/read_courses.py @@ -0,0 +1,14 @@ +# Django specific settings +import inspect +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") +from django.db import connection +# Ensure settings are read +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +from crud.models import * +from datetime import date + + +# Your code starts from here: diff --git a/auth/online1/read_instructors.py b/auth/online1/read_instructors.py new file mode 100644 index 0000000000..e36ae047ea --- /dev/null +++ b/auth/online1/read_instructors.py @@ -0,0 +1,14 @@ +# Django specific settings +import inspect +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") +from django.db import connection +# Ensure settings are read +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +from crud.models import * +from datetime import date + + +# Your code starts from here: diff --git a/auth/online1/read_learners.py b/auth/online1/read_learners.py new file mode 100644 index 0000000000..e36ae047ea --- /dev/null +++ b/auth/online1/read_learners.py @@ -0,0 +1,14 @@ +# Django specific settings +import inspect +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") +from django.db import connection +# Ensure settings are read +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +from crud.models import * +from datetime import date + + +# Your code starts from here: diff --git a/auth/online1/settings.py b/auth/online1/settings.py new file mode 100644 index 0000000000..8fdfced359 --- /dev/null +++ b/auth/online1/settings.py @@ -0,0 +1,46 @@ +# PostgreSQL +# This is a sample settings.py file for a Django project using PostgreSQL +# 'OPTIONS': { +# 'context_processors': [ + +# 'django.template.context_processors.debug', +# 'django.template.context_processors.request', +# 'django.contrib.auth.context_processors.auth', +# 'django.template.context_processors.media', +# 'django.contrib.messages.context_processors.messages', +# ], +# }, +# }, +# ] +# +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'postgres', + 'USER': 'postgres', + 'PASSWORD': '#Replace it with generated password#', + 'HOST': 'postgres', + 'PORT': '5432', + + } + +} +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ +STATIC_URL = '/static/' +# SECURITY WARNING: keep the secret key used in production secret! +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True +ALLOWED_HOSTS = ['*'] +# Application definition +# SECURITY WARNING: keep the secret key used in production secret! +# SECURITY WARNING: don't run with debug turned on in production! +# SECURITY WARNING: don't run with debug turned on in production! +# SECURITY WARNING: don't run with debug turned on in production! +# SECURITY WARNING: don't run with debug turned on in production! + +INSTALLED_APPS = ( + 'crud', +) + +SECRET_KEY = 'SECRET KEY for this Django Project' diff --git a/auth/online1/write.py b/auth/online1/write.py new file mode 100644 index 0000000000..e36ae047ea --- /dev/null +++ b/auth/online1/write.py @@ -0,0 +1,14 @@ +# Django specific settings +import inspect +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") +from django.db import connection +# Ensure settings are read +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +from crud.models import * +from datetime import date + + +# Your code starts from here: diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000000..a428ee22bc --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.12.0-slim-bookworm + +ENV PYTHONBUFFERED=1 +ENV PYTHONWRITEBYTECODE=1 + +ENV APP=/app + +# Change the workdir. +WORKDIR $APP + +# Install the requirements +COPY requirements.txt $APP + +RUN pip3 install -r requirements.txt + +# Copy the rest of the files +COPY . $APP + +EXPOSE 8000 + +RUN chmod +x /app/entrypoint.sh + +ENTRYPOINT ["/bin/bash","/app/entrypoint.sh"] + +CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "djangoproj.wsgi"] \ No newline at end of file diff --git a/server/database/app.js b/server/database/app.js index 00f52b2008..a75dd2e2cb 100644 --- a/server/database/app.js +++ b/server/database/app.js @@ -59,16 +59,38 @@ app.get('/fetchReviews/dealer/:id', async (req, res) => { // Express route to fetch all dealerships app.get('/fetchDealers', async (req, res) => { //Write your code here + try { + const documents = await Dealerships.find(); + res.json(documents); + } catch (error) { + res.status(500).json({ error: 'Error fetching documents' }); + } }); // Express route to fetch Dealers by a particular state app.get('/fetchDealers/:state', async (req, res) => { //Write your code here + try{ + const documents = await Dealerships.find({state: req.params.state}); + res.json(documents); + } catch (error) { + res.status(500).json({ error: 'Error fetching documents' }); + } }); // Express route to fetch dealer by a particular id app.get('/fetchDealer/:id', async (req, res) => { //Write your code here + try { + const documents = await Dealerships.find({id: req.params.id}); + if (!documents) { + return res.status(404).json({ error: 'Dealership not found' }); + } + res.json(documents); + } catch (error) { + res.status(500).json({ error: 'Error fetching documents' }); + } + }); //Express route to insert review diff --git a/server/database/docker-compose.yml b/server/database/docker-compose.yml index 95c4909643..16d9e1b506 100644 --- a/server/database/docker-compose.yml +++ b/server/database/docker-compose.yml @@ -11,6 +11,10 @@ services: volumes: - mongo_data:/data/db + #Postgres service + + + # Node api service api: image: nodeapp @@ -18,6 +22,8 @@ services: - 3030:3030 depends_on: - mongo_db - + volumes: mongo_data: {} + + \ No newline at end of file diff --git a/server/deployment.yaml b/server/deployment.yaml new file mode 100644 index 0000000000..0d2ee0ab0e --- /dev/null +++ b/server/deployment.yaml @@ -0,0 +1,30 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: dealership + name: dealership +spec: + replicas: 1 + selector: + matchLabels: + run: dealership + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + run: dealership + spec: + containers: + - image: docker.io/dragonwin1/dealership-app:latest + imagePullPolicy: Always + name: dealership + ports: + - containerPort: 8000 + protocol: TCP + + restartPolicy: Always \ No newline at end of file diff --git a/server/djangoapp/.env b/server/djangoapp/.env index 01822e542a..4d49a0b97a 100644 --- a/server/djangoapp/.env +++ b/server/djangoapp/.env @@ -1,2 +1,2 @@ -backend_url =your backend url -sentiment_analyzer_url=your code engine deployment url +backend_url =http://127.0.0.1:3030 +sentiment_analyzer_url=http://localhost:5000/ diff --git a/server/djangoapp/admin.py b/server/djangoapp/admin.py index 433657fc64..82dcbe2d61 100644 --- a/server/djangoapp/admin.py +++ b/server/djangoapp/admin.py @@ -1,8 +1,11 @@ -# from django.contrib import admin +from django.contrib import admin # from .models import related models +from .models import CarModel, CarMake # Register your models here. +admin.site.register(CarModel) +admin.site.register(CarMake) # CarModelInline class diff --git a/server/djangoapp/models.py b/server/djangoapp/models.py index eb101a68c8..b0dc3192ab 100644 --- a/server/djangoapp/models.py +++ b/server/djangoapp/models.py @@ -4,6 +4,10 @@ # from django.utils.timezone import now # from django.core.validators import MaxValueValidator, MinValueValidator +from django.db import models +from django.utils.timezone import now +from django.core.validators import MaxValueValidator, MinValueValidator + # Create your models here. @@ -13,6 +17,11 @@ # - Any other fields you would like to include in car make model # - __str__ method to print a car make object +class CarMake(models.Model): + name=models.CharField(null=False,max_length=100, default='CarMake') + description=models.CharField( max_length=100, default='Description') + def __str__(self): + return self.name # Create a Car Model model `class CarModel(models.Model):`: # - Many-To-One relationship to Car Make model (One Car Make has many @@ -23,3 +32,16 @@ # - Year (IntegerField) with min value 2015 and max value 2023 # - Any other fields you would like to include in car model # - __str__ method to print a car make object + +class CarModel(models.Model): + car_make=models.ForeignKey(CarMake, on_delete=models.CASCADE) + name=models.CharField(max_length=100, default='CarModel') + CAR_TYPE = ( + ('Sedan', 'Sedan'), + ('SUV', 'SUV'), + ('WAGON', 'Wagon'), + ) + type=models.CharField(max_length=100, choices=CAR_TYPE, default='Sedan') + year=models.IntegerField(validators=[MinValueValidator(2015), MaxValueValidator(2023)]) + def __str__(self): + return self.name \ No newline at end of file diff --git a/server/djangoapp/populate.py b/server/djangoapp/populate.py index 1927e09e18..8cd5c55d64 100644 --- a/server/djangoapp/populate.py +++ b/server/djangoapp/populate.py @@ -1,2 +1,39 @@ +from .models import CarMake,CarModel def initiate(): print("Populate not implemented. Add data manually") + car_make_data = [ + {"name":"NISSAN", "description":"Great cars. Japanese technology"}, + {"name":"Mercedes", "description":"Great cars. German technology"}, + {"name":"Audi", "description":"Great cars. German technology"}, + {"name":"Kia", "description":"Great cars. Korean technology"}, + {"name":"Toyota", "description":"Great cars. Japanese technology"}, + ] + + car_make_instances = [] + + for data in car_make_data: + car_make_instances.append(CarMake.objects.create(name=data['name'],description=data['description'])) + + #Create CarModel instances with the Correspoding CarMake instance + # + car_model_data = [ + {"name":"Pathfinder", "type":"SUV", "year": 2023, "car_make":car_make_instances[0]}, + {"name":"Qashqai", "type":"SUV", "year": 2023, "car_make":car_make_instances[0]}, + {"name":"XTRAIL", "type":"SUV", "year": 2023, "car_make":car_make_instances[0]}, + {"name":"A-Class", "type":"SUV", "year": 2023, "car_make":car_make_instances[1]}, + {"name":"C-Class", "type":"SUV", "year": 2023, "car_make":car_make_instances[1]}, + {"name":"E-Class", "type":"SUV", "year": 2023, "car_make":car_make_instances[1]}, + {"name":"A4", "type":"SUV", "year": 2023, "car_make":car_make_instances[2]}, + {"name":"A5", "type":"SUV", "year": 2023, "car_make":car_make_instances[2]}, + {"name":"A6", "type":"SUV", "year": 2023, "car_make":car_make_instances[2]}, + {"name":"Sorrento", "type":"SUV", "year": 2023, "car_make":car_make_instances[3]}, + {"name":"Carnival", "type":"SUV", "year": 2023, "car_make":car_make_instances[3]}, + {"name":"Cerato", "type":"Sedan", "year": 2023, "car_make":car_make_instances[3]}, + {"name":"Corolla", "type":"Sedan", "year": 2023, "car_make":car_make_instances[4]}, + {"name":"Camry", "type":"Sedan", "year": 2023, "car_make":car_make_instances[4]}, + {"name":"Kluger", "type":"SUV", "year": 2023, "car_make":car_make_instances[4]}, + # Add more CarModel instances as needed + ] + + for data in car_model_data: + CarModel.objects.create(name=data['name'], car_make=data['car_make'], type=data['type'], year=data['year']) \ No newline at end of file diff --git a/server/djangoapp/restapis.py b/server/djangoapp/restapis.py index 90709d9e3b..466a1ae2c4 100644 --- a/server/djangoapp/restapis.py +++ b/server/djangoapp/restapis.py @@ -2,6 +2,7 @@ # import requests import os from dotenv import load_dotenv +import requests load_dotenv() @@ -9,9 +10,56 @@ 'backend_url', default="http://localhost:3030") sentiment_analyzer_url = os.getenv( 'sentiment_analyzer_url', - default="http://localhost:5050/") + default="http://localhost:5000/") # def get_request(endpoint, **kwargs): +def get_request(endpoint, **kwargs): + params = "" + if(kwargs): + for key, value in kwargs.items(): + params += params + key + "=" + value+ "&" + request_url = backend_url + endpoint +"?"+ params + + print("GET from {}".format(request_url)) + try: + response = requests.get(request_url) + return response.json() + except: + print("Network exception occurred") + +def analyze_review_sentiments(text): + request_url = sentiment_analyzer_url+"analyze/"+text + try: + # Call get method of requests library with URL and parameters + response = requests.get(request_url) + return response.json() + except Exception as err: + print(f"Unexpected {err=}, {type(err)=}") + print("Network exception occurred") + +def post_review(data_dict): + request_url = backend_url + "/insert_review" + try: + # Call post method of requests library with URL and parameters + response = requests.post(request_url, json=data_dict) + print(response.json()) + return response.json() + except Exception as err: + print(f"Unexpected {err=}, {type(err)=}") + print("Network exception occurred") + # print("POST to {}".format(request_url)) + + + + + + + + + + + + # Add code for get requests to back end # def analyze_review_sentiments(text): @@ -20,3 +68,4 @@ # def post_review(data_dict): # Add code for posting review + diff --git a/server/djangoapp/text.text b/server/djangoapp/text.text new file mode 100644 index 0000000000..5c37c6d258 --- /dev/null +++ b/server/djangoapp/text.text @@ -0,0 +1,2 @@ +https://sentianalyzer1.1uclblihlz9o.us-south.codeengine.appdomain.cloud +tytrydfdsfdfdsfds \ No newline at end of file diff --git a/server/djangoapp/urls.py b/server/djangoapp/urls.py index 0edc274f90..a574386309 100644 --- a/server/djangoapp/urls.py +++ b/server/djangoapp/urls.py @@ -1,15 +1,33 @@ # Uncomment the imports before you add the code -# from django.urls import path +from django.urls import path from django.conf.urls.static import static from django.conf import settings -# from . import views +from . import views app_name = 'djangoapp' urlpatterns = [ # # path for registration # path for login - # path(route='login', view=views.login_user, name='login'), + path(route='login', view=views.login_user, name='login'), + path(route='logout', view=views.logout_request, name='logout'), + path(route='registration', view=views.registration, name='registration'), + # path for car makes view + path(route='get_cars', view=views.get_cars, name='getcars'), + #get_dealerships + path(route='get_dealers', view=views.get_dealerships, name='get_dealers'), + path(route='get_dealers/', view=views.get_dealerships, name='get_dealers_by_state'), + path(route='dealer/', view=views.get_dealer_details, name='dealer_details'), + + #dealer review + path(route='reviews/dealer/', view=views.get_dealer_reviews, name='dealer_reviews'), + + #add review + path(route='add_review', view=views.add_review, name='add_review'), + + + # path for home view + # path for dealer reviews view diff --git a/server/djangoapp/views.py b/server/djangoapp/views.py index b16409f419..743d551988 100644 --- a/server/djangoapp/views.py +++ b/server/djangoapp/views.py @@ -1,19 +1,25 @@ # Uncomment the required imports before adding the code -# from django.shortcuts import render -# from django.http import HttpResponseRedirect, HttpResponse -# from django.contrib.auth.models import User -# from django.shortcuts import get_object_or_404, render, redirect -# from django.contrib.auth import logout -# from django.contrib import messages -# from datetime import datetime +from django.shortcuts import render +from django.http import HttpResponseRedirect, HttpResponse +from django.contrib.auth.models import User +from django.shortcuts import get_object_or_404, render, redirect +from django.contrib.auth import logout +from django.contrib import messages +from datetime import datetime from django.http import JsonResponse from django.contrib.auth import login, authenticate import logging import json from django.views.decorators.csrf import csrf_exempt -# from .populate import initiate +from .models import CarModel, CarMake +from .populate import initiate +from .restapis import get_request +from .restapis import analyze_review_sentiments +from .restapis import post_review + + # Get an instance of a logger @@ -39,27 +45,107 @@ def login_user(request): return JsonResponse(data) # Create a `logout_request` view to handle sign out request -# def logout_request(request): -# ... +def logout_request(request): + logout(request) + data ={"userName": ""} + return JsonResponse(data) # Create a `registration` view to handle sign up request -# @csrf_exempt -# def registration(request): -# ... +@csrf_exempt +def registration(request): + context = {} + data = json.loads(request.body) + username = data['userName'] + password = data['password'] + first_name = data['firstName'] + last_name = data['lastName'] + email = data['email'] + username_exist = False + email_exist = False + try: + # Check if user already exists + User.objects.get(username=username) + username_exist = True + except: + # If not, simply log this is a new user + logger.debug("{} is new user".format(username)) + # If it is a new user + if not username_exist: + # Create user in auth_user table + user = User.objects.create_user(username=username, first_name=first_name, last_name=last_name,password=password, email=email) + # Login the user and redirect to list page + login(request, user) + data = {"userName":username,"status":"Authenticated"} + return JsonResponse(data) + else : + data = {"userName":username,"error":"Already Registered"} + return JsonResponse(data) # # Update the `get_dealerships` view to render the index page with # a list of dealerships -# def get_dealerships(request): -# ... +def get_dealerships(request, state="All"): + # Get dealers from the URL + if(state == "All"): + endpoint = "/fetchDealers" + else: + endpoint = "/fetchDealers/" + state + dealerships = get_request(endpoint) + # Render the index page with the list of dealerships + return JsonResponse({"status": "200", "dealers": dealerships}) # Create a `get_dealer_reviews` view to render the reviews of a dealer -# def get_dealer_reviews(request,dealer_id): -# ... +def get_dealer_reviews(request,dealer_id): + if(dealer_id): + endpoint = "/fetchReviews/" + str(dealer_id) + reviews = get_request(endpoint) + # Add this check before iterating + if reviews is None: + return JsonResponse({"status": "404", "message": "No reviews found for this dealer"}) + return JsonResponse({"status": "200", "reviews": reviews}) + else: + return JsonResponse({"status": "404", "message": "Bad Request"}) # Create a `get_dealer_details` view to render the dealer details -# def get_dealer_details(request, dealer_id): -# ... - +def get_dealer_details(request, dealer_id): + if(dealer_id): + endpoint = "/fetchDealer/"+str(dealer_id) + dealership = get_request(endpoint) + return JsonResponse({"status":200,"dealer":dealership}) + else: + return JsonResponse({"status":400,"message":"Bad Request"}) +def get_dealer_reviews(request, dealer_id): + # if dealer id has been provided + if(dealer_id): + endpoint = "/fetchReviews/dealer/"+str(dealer_id) + reviews = get_request(endpoint) + print(reviews) + for review_detail in reviews: + response = analyze_review_sentiments(review_detail['review']) + print(response) + review_detail['sentiment'] = response['sentiment'] + return JsonResponse({"status":200,"reviews":reviews}) + else: + return JsonResponse({"status":400,"message":"Bad Request"}) # Create a `add_review` view to submit a review -# def add_review(request): -# ... +def add_review(request): + if(request.user.is_anonymous == False): + data =json.loads(request.body) + try: + response = post_review(data) + return JsonResponse({"status":200,"message":"Review Submitted"}) + except: + return JsonResponse({"status":401,"message":"Error in posting review"}) + else: + return JsonResponse({"status":403,"message":"unauthorized"}) + +def get_cars(request): + count = CarMake.objects.filter().count() + print(count) + if(count == 0): + initiate() + car_models =CarModel.objects.select_related ('car_make') + cars = [] + for car_model in car_models: + cars.append({"CarModel" : car_model.name, "CarMake" :car_model.car_make.name}) + return JsonResponse({"CarModels" : cars}) + diff --git a/server/djangoproj/settings.py b/server/djangoproj/settings.py index e0b1092a5c..6254f7ac5f 100644 --- a/server/djangoproj/settings.py +++ b/server/djangoproj/settings.py @@ -28,8 +28,8 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] -CSRF_TRUSTED_ORIGINS = [] +ALLOWED_HOSTS = ['localhost','http://127.0.0.1:8000/',"http://127.0.0.1",'127.0.0.1'] +CSRF_TRUSTED_ORIGINS = ['http://127.0.0.1:8000/'] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [], @@ -61,7 +61,11 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [ + os.path.join(BASE_DIR,'frontend/static'), + os.path.join(BASE_DIR, 'frontend/build'), + os.path.join(BASE_DIR, 'frontend/build/static'), + ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -74,6 +78,8 @@ }, ] + + WSGI_APPLICATION = 'djangoproj.wsgi.application' @@ -134,5 +140,9 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -STATICFILES_DIRS = [] +STATICFILES_DIRS = [ + os.path.join(BASE_DIR,'frontend/static'), + os.path.join(BASE_DIR, 'frontend/build'), + os.path.join(BASE_DIR, 'frontend/build/static'), +] diff --git a/server/djangoproj/urls.py b/server/djangoproj/urls.py index 6808da9141..57019d6f7d 100644 --- a/server/djangoproj/urls.py +++ b/server/djangoproj/urls.py @@ -23,4 +23,13 @@ path('admin/', admin.site.urls), path('djangoapp/', include('djangoapp.urls')), path('', TemplateView.as_view(template_name="Home.html")), + path('about/', TemplateView.as_view(template_name="About.html")), + path('contact/', TemplateView.as_view(template_name="Contact.html")), + path('login/', TemplateView.as_view(template_name="index.html")), + path('register/', TemplateView.as_view(template_name="index.html")), + path('logout/', TemplateView.as_view(template_name="index.html")), + path('dealers/', TemplateView.as_view(template_name="index.html")), + path('dealer/',TemplateView.as_view(template_name="index.html")), + path('postreview/',TemplateView.as_view(template_name="index.html")), + ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/server/entrypoint.sh b/server/entrypoint.sh new file mode 100644 index 0000000000..6c29cf43d0 --- /dev/null +++ b/server/entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# Make migrations and migrate the database. +echo "Making migrations and migrating the database. " +python manage.py makemigrations --noinput +python manage.py migrate --noinput +python manage.py collectstatic --noinput +exec "$@" \ No newline at end of file diff --git a/server/frontend/package-lock.json b/server/frontend/package-lock.json index 0797425307..b9244446c9 100644 --- a/server/frontend/package-lock.json +++ b/server/frontend/package-lock.json @@ -16,6 +16,9 @@ "react-router-dom": "^6.19.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -646,9 +649,17 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { "node": ">=6.9.0" }, @@ -1891,6 +1902,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/server/frontend/src/App.js b/server/frontend/src/App.js index aceac6974d..56d319ffe7 100644 --- a/server/frontend/src/App.js +++ b/server/frontend/src/App.js @@ -1,10 +1,19 @@ import LoginPanel from "./components/Login/Login" +import Register from "./components/Register/Register"; import { Routes, Route } from "react-router-dom"; +import Dealers from "./components/Dealers/Dealers"; +import Dealer from "./components/Dealers/Dealer"; +import PostReview from "./components/Dealers/PostReview"; function App() { return ( } /> + } /> + } /> + } /> + } /> + ); } diff --git a/server/frontend/src/components/Dealers/Dealer.jsx b/server/frontend/src/components/Dealers/Dealer.jsx index 4c162e8a1b..67d1d5cb15 100644 --- a/server/frontend/src/components/Dealers/Dealer.jsx +++ b/server/frontend/src/components/Dealers/Dealer.jsx @@ -75,9 +75,9 @@ return(

{dealer['city']},{dealer['address']}, Zip - {dealer['zip']}, {dealer['state']}

- {reviews.length === 0 && unreviewed === false ? ( - Loading Reviews.... - ): unreviewed === true?
No reviews yet!
: + {reviews.length === '0' ? ( + Loading Reviews.... + ): unreviewed ?
No reviews yet!
: reviews.map(review => (
Sentiment diff --git a/server/frontend/src/components/Dealers/Dealers.jsx b/server/frontend/src/components/Dealers/Dealers.jsx index db3410680c..837168a9db 100644 --- a/server/frontend/src/components/Dealers/Dealers.jsx +++ b/server/frontend/src/components/Dealers/Dealers.jsx @@ -20,7 +20,7 @@ const Dealers = () => { method: "GET" }); const retobj = await res.json(); - if(retobj.status === 200) { + if(retobj.status === '200') { let state_dealers = Array.from(retobj.dealers) setDealersList(state_dealers) } @@ -30,20 +30,27 @@ const Dealers = () => { const res = await fetch(dealer_url, { method: "GET" }); + console.log(res) + const retobj = await res.json(); - if(retobj.status === 200) { + console.log('retobj',retobj) + console.log('retobj.status',retobj.status) + if(retobj.status === '200') { let all_dealers = Array.from(retobj.dealers) let states = []; all_dealers.forEach((dealer)=>{ states.push(dealer.state) }); + console.log('all_dealers', all_dealers) + setStates(Array.from(new Set(states))) setDealersList(all_dealers) } } useEffect(() => { get_dealers(); + console.log("dealersList",dealersList) },[]); diff --git a/server/frontend/src/components/Register/Register.jsx b/server/frontend/src/components/Register/Register.jsx new file mode 100644 index 0000000000..b9c72a0f25 --- /dev/null +++ b/server/frontend/src/components/Register/Register.jsx @@ -0,0 +1,84 @@ +import React, { useState } from "react"; +import "./Register.css"; +import user_icon from "../assets/person.png" +import email_icon from "../assets/email.png" +import password_icon from "../assets/password.png" +import close_icon from "../assets/close.png" +const Register = () => { + const [userName, setUserName] = useState(""); + const [password, setPassword] = useState(""); + const [email, setEmail] = useState(""); + const [firstName, setFirstName] = useState(""); + const [lastName, setlastName] = useState(""); + const gohome = ()=> { + window.location.href = window.location.origin; + } + const register = async (e) => { + e.preventDefault(); + let register_url = window.location.origin+"/djangoapp/registration"; + + const res = await fetch(register_url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + "userName": userName, + "password": password, + "firstName":firstName, + "lastName":lastName, + "email":email + }), + }); + const json = await res.json(); + if (json.status) { + sessionStorage.setItem('username', json.userName); + window.location.href = window.location.origin; + } + else if (json.error === "Already Registered") { + alert("The user with same username is already registered"); + window.location.href = window.location.origin; + } +}; + return( +
+ +
+
+
+ Username + setUserName(e.target.value)}/> +
+
+ First Name + setFirstName(e.target.value)}/> +
+
+ Last Name + setlastName(e.target.value)}/> +
+
+ Email + setEmail(e.target.value)}/> +
+
+ password + setPassword(e.target.value)}/> +
+
+
+ +
+
+
+ ) +} +export default Register; \ No newline at end of file diff --git a/server/frontend/static/About.html b/server/frontend/static/About.html index 484efd960f..b94dd095a7 100644 --- a/server/frontend/static/About.html +++ b/server/frontend/static/About.html @@ -1,6 +1,8 @@ + +