diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 05ca50d23b..9ddbb6b27f 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -15,14 +15,11 @@ jobs: # list of things to do uses: actions/setup-node@v3 with: node-version: 16 - - name: Code Checkout uses: actions/checkout@v3 - - name: Install Dependencies run: npm install working-directory: functions/sample/nodejs - - name: Code Linting run: npm run lint working-directory: functions/sample/nodejs diff --git a/server/db.sqlite3 b/server/db.sqlite3 new file mode 100644 index 0000000000..fd2361b960 Binary files /dev/null and b/server/db.sqlite3 differ diff --git a/server/djangoapp/admin.py b/server/djangoapp/admin.py index b1039e16b8..763f4c73ca 100644 --- a/server/djangoapp/admin.py +++ b/server/djangoapp/admin.py @@ -1,13 +1,22 @@ from django.contrib import admin -# from .models import related models +from .models import CarMake, CarModel # Register your models here. # CarModelInline class +class CarModelInline(admin.StackedInline): + model = CarModel # CarModelAdmin class +class CarModelAdmin(admin.ModelAdmin): + list_display = ('name',) # CarMakeAdmin class with CarModelInline +class CarMakeAdmin(admin.ModelAdmin): + inlines = [CarModelInline] + list_display = ('name',) # Register models here +admin.site.register(CarMake, CarMakeAdmin) +admin.site.register(CarModel, CarModelAdmin) diff --git a/server/djangoapp/models.py b/server/djangoapp/models.py index 27d96f4eff..27e4f6cd0d 100644 --- a/server/djangoapp/models.py +++ b/server/djangoapp/models.py @@ -4,24 +4,75 @@ # Create your models here. -# Create a Car Make model `class CarMake(models.Model)`: -# - Name -# - Description -# - Any other fields you would like to include in car make model -# - __str__ method to print a car make object +# Create a Car Make model +class CarMake(models.Model): + name = models.CharField(max_length=50) + description = models.CharField(max_length=500) + def __str__(self): + return self.name + ": " + self.description + + + +# Create a Car Model model +class CarModel(models.Model): + car_make = models.ForeignKey(CarMake, on_delete=models.CASCADE) + name = models.CharField(max_length=50) + dealer_id = models.IntegerField() + car_type = models.CharField(max_length=20, choices=(('SEDAN', 'SEDAN',), ('SUV', 'SUV'), ('HATCHBACK', 'HATCHBACK'),('WAGON', 'WAGON'),('MINIVAN', 'MINIVAN'))) + year = models.DateField() + + 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 Car Models, using ForeignKey field) -# - Name -# - Dealer id, used to refer a dealer created in cloudant database -# - Type (CharField with a choices argument to provide limited choices such as Sedan, SUV, WAGON, etc.) -# - Year (DateField) -# - Any other fields you would like to include in car model -# - __str__ method to print a car make object # Create a plain Python class `CarDealer` to hold dealer data +class CarDealer: + def __init__(self, address, city, full_name, id, lat, long, short_name, st, zip): + # Dealer address + self.address = address + # Dealer city + self.city = city + # Dealer Full Name + self.full_name = full_name + # Dealer id + self.id = id + # Location lat + self.lat = lat + # Location long + self.long = long + # Dealer short name + self.short_name = short_name + # Dealer state + self.st = st + # Dealer zip + self.zip = zip + + def __str__(self): + return "Dealer name: " + self.full_name # Create a plain Python class `DealerReview` to hold review data +class DealerReview: + + def __init__(self, dealership, name, purchase, review): + # Required attributes + self.dealership = dealership + self.name = name + self.purchase = purchase + self.review = review + # Optional attributes + self.purchase_date = "" + self.car_make = "" + self.car_model = "" + self.car_year = "" + self.sentiment = "" + self.id = "" + + def __str__(self): + return "Review: " + self.review + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) \ No newline at end of file diff --git a/server/djangoapp/restapis.py b/server/djangoapp/restapis.py index b4d13f596a..aed12ee31a 100644 --- a/server/djangoapp/restapis.py +++ b/server/djangoapp/restapis.py @@ -1,28 +1,125 @@ import requests import json -# import related models here +from .models import CarDealer from requests.auth import HTTPBasicAuth # Create a `get_request` to make HTTP GET requests # e.g., response = requests.get(url, params=params, headers={'Content-Type': 'application/json'}, # auth=HTTPBasicAuth('apikey', api_key)) - +def get_request(url, **kwargs): + api_key = kwargs.get("api_key") + print("GET from {} ".format(url)) + try: + if api_key: + params = dict() + params["text"] = kwargs["text"] + params["version"] = kwargs["version"] + params["features"] = kwargs["features"] + params["return_analyzed_text"] = kwargs["return_analyzed_text"] + requests.get(url, params=params, headers={'Content-Type': 'application/json'}, + auth=HTTPBasicAuth('apikey', api_key)) + else: + response = requests.get(url, headers={'Content-Type': 'application/json'}, + params=kwargs) + except: + # If any error occurs + print("Network exception occurred") + status_code = response.status_code + print("With status {} ".format(status_code)) + json_data = json.loads(response.text) + return json_data # Create a `post_request` to make HTTP POST requests # e.g., response = requests.post(url, params=kwargs, json=payload) - +def post_request(url, payload, **kwargs): + print(kwargs) + print("POST to {} ".format(url)) + print(payload) + response = requests.post(url, params=kwargs, json=payload) + status_code = response.status_code + print("With status {} ".format(status_code)) + json_data = json.loads(response.text) + return json_data # Create a get_dealers_from_cf method to get dealers from a cloud function # def get_dealers_from_cf(url, **kwargs): # - Call get_request() with specified arguments # - Parse JSON results into a CarDealer object list +def get_dealers_from_cf(url, **kwargs): + results = [] + # Call get_request with a URL parameter + json_result = get_request(url) + if json_result: + # Get the row list in JSON as dealers + dealers = json_result["rows"] + # For each dealer object + for dealer in dealers: + # Get its content in `doc` object + dealer_doc = dealer["doc"] + # Create a CarDealer object with values in `doc` object + dealer_obj = CarDealer(address=dealer_doc["address"], city=dealer_doc["city"], full_name=dealer_doc["full_name"], + id=dealer_doc["id"], lat=dealer_doc["lat"], long=dealer_doc["long"], + short_name=dealer_doc["short_name"], + st=dealer_doc["st"], zip=dealer_doc["zip"]) + results.append(dealer_obj) + return results + +def get_dealer_by_id_from_cf(url, id): + result = {} + # Call get_request with a URL parameter + json_result = get_request(url, did=id) + if json_result: + # Get the row list in JSON as dealers + dealers = json_result["rows"] + # For each dealer object + dealer = dealers[0] + # Create a CarDealer object with values in `doc` object + dealer_obj = CarDealer(address=dealer["address"], city=dealer["city"], full_name=dealer["full_name"], + id=dealer["id"], lat=dealer["lat"], long=dealer["long"], + short_name=dealer["short_name"], + st=dealer["st"], zip=dealer["zip"]) + result = dealer_obj + return result +def get_dealers_by_state_from_cf(url, state, **kwargs): + results = [] + # Call get_request with a URL parameter + json_result = get_request(url, state=state) + if json_result: + # Get the row list in JSON as dealers + dealers = json_result["rows"] + # For each dealer object + for dealer in dealers: + dealer_doc = dealer["doc"] + # Create a CarDealer object with values in `doc` object + dealer_obj = CarDealer(address=dealer_doc["address"], city=dealer_doc["city"], full_name=dealer_doc["full_name"], + id=dealer_doc["id"], lat=dealer_doc["lat"], long=dealer_doc["long"], + short_name=dealer_doc["short_name"], + st=dealer_doc["st"], zip=dealer_doc["zip"]) + results.append(dealer_obj) + return results # Create a get_dealer_reviews_from_cf method to get reviews by dealer id from a cloud function # def get_dealer_by_id_from_cf(url, dealerId): # - Call get_request() with specified arguments # - Parse JSON results into a DealerView object list +def get_dealer_reviews_from_cf(url, id): + results = [] + # Call get_request with a URL parameter + json_result = get_request(url, did=id) + if json_result: + # Get the row list in JSON as dealers + reviews = json_result["rows"] + # For each dealer object + for review in reviews: + # Create a CarDealer object with values in `doc` object + review_obj = DealerReview(id=review["id"], dealership=review["dealership"], name=review["name"], purchase=review["purchase"], + review=review["review"], purchase_date=review["purchase_date"], car_make=review["car_make"], + car_model=review["car_model"], car_year=review["car_year"], sentiment="") + review_obj.sentiment = analyze_review_sentiments(review_obj.review) + results.append(review_obj) + return results # Create an `analyze_review_sentiments` method to call Watson NLU and analyze text diff --git a/server/djangoapp/templates/djangoapp/about.html b/server/djangoapp/templates/djangoapp/about.html new file mode 100644 index 0000000000..a8ea401624 --- /dev/null +++ b/server/djangoapp/templates/djangoapp/about.html @@ -0,0 +1,49 @@ + + + + + Dealership Review + + + + + + + + + + + +

+ Welcome to Best Cars dealership, home to the best cars in North America. We sell domestic and imported cars at reasonable prices. +

+ + \ No newline at end of file diff --git a/server/djangoapp/templates/djangoapp/contact.html b/server/djangoapp/templates/djangoapp/contact.html new file mode 100644 index 0000000000..37f4d1cf48 --- /dev/null +++ b/server/djangoapp/templates/djangoapp/contact.html @@ -0,0 +1,55 @@ + + + + + Dealership Review + + + + + + + + + + +
+

+ Contact information +

+
+
    Phone No: 555 834 6626
+
    Email: EpicCars11@gmail.com"
+
    Address:1818 West Way Ct.
+
+
+ + \ No newline at end of file diff --git a/server/djangoapp/templates/djangoapp/dealer_details.html b/server/djangoapp/templates/djangoapp/dealer_details.html index 25bd9a223d..1c132f6dfc 100644 --- a/server/djangoapp/templates/djangoapp/dealer_details.html +++ b/server/djangoapp/templates/djangoapp/dealer_details.html @@ -10,8 +10,55 @@ + +
+ {% for review in reviews %} +
+
{{review.name}}
+ +
+
{{ review.car_make }}, {{ review.car_model }}
+
{{ review.car_year }}
+

{{ review.review }}

+
+
+ {% endfor %} {% if reviews|length == 0 %} +

This dealership has no reviews to show

+ {% endif %} +
diff --git a/server/djangoapp/templates/djangoapp/index.html b/server/djangoapp/templates/djangoapp/index.html index 1a9ee6e39a..6b225c4475 100644 --- a/server/djangoapp/templates/djangoapp/index.html +++ b/server/djangoapp/templates/djangoapp/index.html @@ -14,12 +14,68 @@ - - This is the index page of your Django app! + - +
+ + + + + + + + + + + + + {% for dealer in dealerships %} + + + + + + + + + {% endfor %} + +
IDDealer NameCityAddressZipState
{{dealer.id}}{{dealer.full_name}}{{dealer.city}}{{dealer.address}}{{dealer.zip}}{{dealer.st}}
+
- + diff --git a/server/djangoapp/templates/djangoapp/registration.html b/server/djangoapp/templates/djangoapp/registration.html index ae11ea4b71..f33fd2c561 100644 --- a/server/djangoapp/templates/djangoapp/registration.html +++ b/server/djangoapp/templates/djangoapp/registration.html @@ -7,5 +7,32 @@ + +
+
+

Sign Up

+
+ + + + + + + + +
+ {% csrf_token %} + +
+
+
\ No newline at end of file diff --git a/server/djangoapp/urls.py b/server/djangoapp/urls.py index 37b1c89d01..96030db258 100644 --- a/server/djangoapp/urls.py +++ b/server/djangoapp/urls.py @@ -10,19 +10,27 @@ # name the URL # path for about view + path(route='about/', view=views.about, name='about'), # path for contact us view + path(route='contact/', view=views.contact, name='contact'), # path for registration + path(route='registration/', view=views.registration_request, name='registration'), # path for login + path(route='login/', view=views.login_request, name='login'), # path for logout + path(route='logout/', view=views.logout_request, name='logout'), + #path for home path(route='', view=views.get_dealerships, name='index'), - # path for dealer reviews view + # path for dealer reviews + path('dealer//', views.get_dealer_details, name='dealer_details'), # path for add a review view + path(route='dealer//', view=views.get_dealer_details, name='dealer_details') ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/server/djangoapp/views.py b/server/djangoapp/views.py index 61cc664da0..b290324367 100644 --- a/server/djangoapp/views.py +++ b/server/djangoapp/views.py @@ -2,8 +2,8 @@ from django.http import HttpResponseRedirect, HttpResponse from django.contrib.auth.models import User from django.shortcuts import get_object_or_404, render, redirect -# from .models import related models -# from .restapis import related methods +from .models import CarModel, CarMake, CarDealer +from .restapis import get_dealers_from_cf, get_request, get_dealer_reviews_from_cf, get_dealer_by_id_from_cf, post_request from django.contrib.auth import login, logout, authenticate from django.contrib import messages from datetime import datetime @@ -18,37 +18,139 @@ # Create an `about` view to render a static about page -# def about(request): -# ... +def about(request): + context = {} + if request.method == "GET": + return render(request, 'djangoapp/about.html', context) # Create a `contact` view to return a static contact page -#def contact(request): +def contact(request): + context = {} + if request.method == "GET": + return render(request, 'djangoapp/contact.html', context) # Create a `login_request` view to handle sign in request -# def login_request(request): -# ... +def login_request(request): + # Handles POST request + if request.method == "POST": + # Get username and password from request.POST dictionary + username = request.POST['username'] + password = request.POST['psw'] + # Try to check if provide credential can be authenticated + user = authenticate(username=username, password=password) + if user is not None: + # If user is valid, call login method to login current user + login(request, user) + return redirect('djangoapp:index') + else: + # If not, return to login page again + return redirect('djangoapp:index') + else: + return redirect('djangoapp:index') # Create a `logout_request` view to handle sign out request -# def logout_request(request): -# ... +def logout_request(request): + # Get the user object based on session id in request + print("Log out the user `{}`".format(request.user.username)) + # Logout user in the request + logout(request) + # Redirect user back to course list view + return redirect('djangoapp:index') # Create a `registration_request` view to handle sign up request -# def registration_request(request): -# ... +def registration_request(request): + context = {} + # If it is a GET request, just render the registration page + if request.method == 'GET': + return render(request, 'djangoapp/registration.html', context) + # If it is a POST request + elif request.method == 'POST': + # Get user information from request.POST + username = request.POST['username'] + password = request.POST['psw'] + first_name = request.POST['firstname'] + last_name = request.POST['lastname'] + user_exist = False + try: + # Check if user already exists + User.objects.get(username=username) + user_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 user_exist: + # Create user in auth_user table + user = User.objects.create_user(username=username, first_name=first_name, last_name=last_name, password=password) + # Login the user and redirect to course list page + login(request, user) + return redirect("djangoapp:index") + else: + return render(request, 'djangoapp/registration.html', context) # Update the `get_dealerships` view to render the index page with a list of dealerships def get_dealerships(request): context = {} if request.method == "GET": + url = "https://us-south.functions.appdomain.cloud/api/v1/web/3a5a06a6-46c3-4e9e-815b-cc07f4a836f1/dealership-package/get-dealership" + # Get dealers from the URL + context = { + "dealerships": get_dealers_from_cf(url), + } return render(request, 'djangoapp/index.html', context) - + # Create a `get_dealer_details` view to render the reviews of a dealer -# def get_dealer_details(request, dealer_id): -# ... +def get_dealer_details(request, id): + if request.method == "GET": + context = {} + dealer_url = "https://us-south.functions.appdomain.cloud/api/v1/web/3a5a06a6-46c3-4e9e-815b-cc07f4a836f1/dealership-package/get-dealership" + dealer = get_dealer_by_id_from_cf(dealer_url, id=id) + context["dealer"] = dealer + + review_url = "https://us-south.functions.appdomain.cloud/api/v1/web/3a5a06a6-46c3-4e9e-815b-cc07f4a836f1/dealership-package/get-review" + reviews = get_dealer_reviews_from_cf(review_url, id=id) + print(reviews) + context["reviews"] = reviews + + return render(request, 'djangoapp/dealer_details.html', context) # Create a `add_review` view to submit a review # def add_review(request, dealer_id): -# ... +def add_review(request, id): + context = {} + dealer_url = "https://us-south.functions.appdomain.cloud/api/v1/web/3a5a06a6-46c3-4e9e-815b-cc07f4a836f1/dealership-package/get-dealership" + dealer = get_dealer_by_id_from_cf(dealer_url, id=id) + context["dealer"] = dealer + if request.method == 'GET': + cars = CarModel.objects.all() + print(cars) + context["cars"] = cars + return render(request, 'djangoapp/add_review.html', context) + elif request.method == 'POST': + if request.user.is_authenticated: + username = request.user.username + print(request.POST) + payload = dict() + car_id = request.POST["car"] + car = CarModel.objects.get(pk=car_id) + payload["time"] = datetime.utcnow().isoformat() + payload["name"] = username + payload["dealership"] = id + payload["id"] = id + payload["review"] = request.POST["content"] + payload["purchase"] = False + if "purchasecheck" in request.POST: + if request.POST["purchasecheck"] == 'on': + payload["purchase"] = True + payload["purchase_date"] = request.POST["purchasedate"] + payload["car_make"] = car.make.name + payload["car_model"] = car.name + payload["car_year"] = int(car.year.strftime("%Y")) + new_payload = {} + new_payload["review"] = payload + review_post_url = "https://us-south.functions.appdomain.cloud/api/v1/web/3a5a06a6-46c3-4e9e-815b-cc07f4a836f1/dealership-package/post-review" + post_request(review_post_url, new_payload, id=id) + return redirect("djangoapp:dealer_details", id=id)