Skip to content

Feature/week 06#90

Open
pratikr-3046 wants to merge 8 commits into
Rippling:mainfrom
pratikr-3046:feature/week-06
Open

Feature/week 06#90
pratikr-3046 wants to merge 8 commits into
Rippling:mainfrom
pratikr-3046:feature/week-06

Conversation

@pratikr-3046

@pratikr-3046 pratikr-3046 commented Apr 18, 2026

Copy link
Copy Markdown

Completed basic and advanced Week 06 tasks.


Note

Medium Risk
Adds new HTTP endpoints for CRUD and bulk ingestion and connects to MongoDB via mongoengine, which can impact data integrity and security (notably @csrf_exempt handlers) if deployed beyond local dev.

Overview
Adds a new week_04 Django project that connects to MongoDB and exposes JSON APIs to create/read/update/delete product categories and create/list products, including endpoints to assign/remove a product’s category and a products/bulk-upload/ CSV ingestion route.

Updates the existing Django hello endpoint to return a JSON greeting using a name query param, and adds a simple week_06 static page that fetches /api/products/ and renders product tiles. Frontend housekeeping includes switching App.tsx styling to App.scss and pinning Yarn via packageManager in package.json.

Reviewed by Cursor Bugbot for commit 6ab44c4. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 6ab44c4. Configure here.

Comment thread week_06/app.js Outdated
<h2 class="title">${product.name}</h2>
<p class="description">Brand: ${product.brand}</p>
<div class="price">$${product.price}</div>
`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XSS vulnerability via unsanitized innerHTML injection

High Severity

API response values (product.name, product.brand, product.price) are interpolated directly into innerHTML without any sanitization. Since the backend API accepts arbitrary strings for product names and brands (via both the POST endpoint and bulk_upload_products), an attacker can store a malicious payload like <img src=x onerror=alert(1)> as a product name, creating a stored XSS vulnerability that executes when any user loads the page. Using textContent or DOM creation methods instead of innerHTML would avoid this.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ab44c4. Configure here.

Comment thread week_04/products/views.py
category_id=row.get('category_id')
)

return JsonResponse({"status": "Bulk upload complete"}) No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bulk upload lacks method check and error handling

Medium Severity

bulk_upload_products has two issues: it doesn't verify request.method == 'POST', so any HTTP method (GET, PUT, DELETE) triggers CSV processing; and it lacks error handling around the loop, so if create_product raises (e.g., invalid category_id), previously created products remain committed while the endpoint returns a 500 error. This causes silent partial writes with no indication of which rows succeeded.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ab44c4. Configure here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Comment thread week_04/products/views.py Outdated
return JsonResponse({"status": "Success", "message": f"{product.name} removed from category"})
return JsonResponse({"error": "Product not found"}, status=404)
except Exception as e:
return JsonResponse({"error": str(e)})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View returns None for unsupported HTTP methods

Low Severity

api_for_a_product has no fallback return at the end. When an unsupported HTTP method (e.g., PATCH) is sent with a product_id, execution falls through all conditionals and the function implicitly returns None, causing Django to raise a ValueError and return a 500 error. The same issue applies to api_for_a_category. Both views lack a default return for unmatched methods.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ab44c4. Configure here.

Comment thread week_04/products/views.py Outdated
return JsonResponse({"status": "Success", "product": product.name, "category_id": str(product.category.id)})
return JsonResponse({"error": "Product not found"}, status=404)
except Exception as e:
return JsonResponse({"error": str(e)})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PUT errors return 200 instead of 404

Medium Severity

add_product_to_category raises ValueError for not-found products/categories, unlike the other service methods (e.g., remove_product_from_category) which return None. The view's PUT handler expects a None return to trigger the 404 response on line 125, but the ValueError is caught by the except block on line 126, which returns a 200 status (no status code specified). This means "product not found" and "category not found" errors on PUT always return HTTP 200 instead of a proper error status, making the 404 on line 125 unreachable dead code.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ab44c4. Configure here.

Comment thread week_04/products/services.py Outdated
# objects() is a special funciton written in the original document class from which ProductCategory is inherited
# we can use it without intantiating the class
def get_category_by_id(self, category_id):
return ProductCategory.objects(id=category_id).first()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can create a repo layer for model queries.
Like in repo file expose a function get_product_category_by_id(..)

Comment thread week_04/products/services.py Outdated
return ProductCategory.objects(id=category_id).first()

def delete_category(self,category_id):
category = ProductCategory.objects(id=category_id).first()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here also

Comment thread week_04/products/services.py Outdated
class ProductService():

def get_all_products(self):
return Product.objects()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for all model related queries we can expose the methods for responsibility segregation

Comment thread week_04/products/services.py Outdated
def add_product_to_category(self, product_id, category_id):
product = Product.objects(id=product_id).first()
if not product:
raise ValueError("product not found")

@anujsharma13rippling anujsharma13rippling Apr 19, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always try to return Id also along with error message like ( same for all exceptions)
product not found with id = "123456789"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated code to put id when method fails

Comment thread week_04/products/views.py Outdated
@csrf_exempt
def api_for_a_category(request, category_id=None):

if request.method == 'GET':

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As GET, POST, PUT, DELETE will be used at multiple views, we can define a constant for these rather than hardcoding

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made a new file with all the http constants and all the error codes

Comment thread week_04/products/views.py Outdated
if request.method == 'GET':
if category_id:
try:
c = category_service.get_category_by_id(category_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can always try using meaningful variable names, like category

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed c and p to meaningful names

Comment thread week_04/products/views.py Outdated
success = category_service.delete_category(category_id)
if success:
return JsonResponse({"status": "deleted"})
return JsonResponse({"error": "category not found"}, status=404)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as "category not found" error message is used at multiple places, can be defined in constants file.

Also we can define a map of Status code -> Error message.

Comment thread week_04/products/views.py Outdated
try:
p = product_service.get_product_by_id(product_id)
if p:
return JsonResponse({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than manually creating key -> Values, we can define a DTO/Model to return as a response along with serializer, it will reduce the manual effort.

Comment thread week_04/products/views.py Outdated
return JsonResponse({"title": c.title, "description": c.description})
return JsonResponse({"error": "Category not found"}, status=404)
except Exception as e:
return JsonResponse({"error": str(e)})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default the status code will be 200, if its a error we can send 4XX, 5XX based on error.

from .models import ProductCategory, Product
from .repositories import category_repo, product_repo

class CategoryService:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seperate file for each service.

from .models import ProductCategory, Product

class CategoryRepository:
def get_by_id(self, category_id):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here we can create seperate files for both

Comment thread week_06/app.js
@@ -0,0 +1,31 @@
const container = document.getElementById('product-container');

fetch('http://127.0.0.1:8000/api/products/')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

url should not be hard coded in same file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants