Skip to content

users can delete their course#533

Merged
A1L13N merged 9 commits into
alphaonelabs:mainfrom
IITI-tushar:users-delete-course
Apr 25, 2025
Merged

users can delete their course#533
A1L13N merged 9 commits into
alphaonelabs:mainfrom
IITI-tushar:users-delete-course

Conversation

@IITI-tushar
Copy link
Copy Markdown
Contributor

@IITI-tushar IITI-tushar commented Apr 11, 2025

fixes : issue#532
image
image
image

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Enhanced the course deletion process to automatically remove associated images.
    • Added a "Delete" button on the course detail page for straightforward course removal.
    • Improved the deletion confirmation form to correctly submit to the deletion endpoint with necessary course information.
  • Bug Fixes
    • Updated error message for unauthorized deletion attempts to be clearer and more user-friendly.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2025

Walkthrough

This pull request adds a custom delete method to the Course model to ensure that the associated image file is deleted from storage when the course is deleted. The course deletion confirmation template was updated to specify the form's action attribute targeting the correct deletion URL. The delete_course view function now includes a docstring, modifies the unauthorized error message, and clarifies that deleting the course also deletes the associated image. Additionally, the course detail page was enhanced by adding a "Delete" button linking to the course deletion URL.

Changes

File(s) Change Summary
web/models.py Added a custom delete method in the Course model to delete the associated image file from storage before deleting the course instance.
web/views.py Updated delete_course view: added a docstring, changed unauthorized error message, and clarified deletion logic regarding the associated image.
web/templates/courses/delete_confirm.html Updated the deletion confirmation form to include an explicit action attribute pointing to the course deletion URL using the course slug; CSRF token remains included once.
web/templates/courses/detail.html Added a "Delete" button linking to the course deletion URL, styled with a red background and accessible label, placed alongside existing teacher action buttons.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant T as Template
    participant V as delete_course View
    participant M as Course Model
    participant S as Storage

    U->>T: Submit deletion confirmation form
    T->>V: POST deletion request (with course slug)
    alt Authorized
        V->>M: Invoke custom delete() method
        M->>S: If image exists, delete image (save=False)
        M->>M: Delete Course instance
        V->>U: Redirect to profile page
    else Unauthorized
        V->>U: Display error: "You are not authorized to delete this course."
    end
Loading

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3deba1 and 2469edf.

📒 Files selected for processing (2)
  • web/templates/courses/delete_confirm.html (1 hunks)
  • web/templates/courses/detail.html (1 hunks)
🔇 Additional comments (2)
web/templates/courses/delete_confirm.html (1)

16-18: Ensure correct URL routing and HTTP method
The form now correctly uses the POST method and slug-based routing (course.slug) for the delete_course endpoint. Please verify that your URL pattern in web/urls.py uses <slug:slug> and that the delete_course view enforces request.method == 'POST' for deletion.

web/templates/courses/detail.html (1)

540-546: Approve Delete button integration
The new “Delete” button aligns with existing teacher actions, uses course.slug for the URL, and includes ARIA attributes for accessibility. Confirm it’s wrapped in the {% if user == course.teacher %} block so only authorized users see it, and that it leads to the confirmation flow.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e82b66 and 01e5e2e.

📒 Files selected for processing (3)
  • web/models.py (1 hunks)
  • web/templates/courses/delete_confirm.html (1 hunks)
  • web/views.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/models.py (1)
web/forms.py (5)
  • save (245-283)
  • save (594-619)
  • save (704-721)
  • save (1424-1437)
  • save (1616-1631)
🪛 Ruff (0.8.2)
web/models.py

315-315: Missing return type annotation for public function delete

Add return type annotation: None

(ANN201)


315-315: Missing type annotation for *args

(ANN002)


315-315: Missing type annotation for **kwargs

(ANN003)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run Tests
  • GitHub Check: build-and-test

Comment thread web/models.py
Comment thread web/views.py
Comment thread web/templates/courses/delete_confirm.html Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
web/templates/courses/delete_confirm.html (1)

1-36: Overall Template Quality and CSRF Handling.
The template maintains a clear structure and consistent styling that aligns with the project’s design guidelines. Notably, the issue from previous revisions regarding duplicate {% csrf_token %} instances has been resolved, as only one token is now present.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01e5e2e and f9cdf0a.

📒 Files selected for processing (2)
  • web/templates/courses/delete_confirm.html (1 hunks)
  • web/views.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
web/views.py

923-923: Logging statement uses f-string

(G004)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run Tests
  • GitHub Check: build-and-test
🔇 Additional comments (7)
web/templates/courses/delete_confirm.html (3)

16-20: Enhanced Form Submission Configuration.
The <form> tag now includes the action attribute using {% url 'delete_course' course.id %}, which ensures that deletion requests are correctly routed to the proper endpoint. Additionally, the presence of the hidden input field for course_id and a single {% csrf_token %} adheres to Django best practices.


22-31: Clear and Accessible Action Buttons.
The design of the Cancel link and Delete Course button is clear. The Cancel link effectively redirects users to the course details page via {% url 'course_detail' course.slug %}, while the Delete Course button is styled to emphasize the destructive nature of the action.


11-15: User Confirmation Prompt Clarity.
The confirmation message clearly informs the user that deleting the course (i.e., "{{ course.title }}") is irreversible, thereby reducing the risk of accidental deletion.

web/views.py (4)

909-909: Good addition of a clear docstring.

The addition of a docstring clearly explains the function's dual purpose of handling both course and image deletion, improving code maintainability.


914-914: Improved error message for unauthorized access.

The updated error message "You are not authorized to delete this course" is more professional and generic than the previous message, providing better clarity to users.


918-924: Well-implemented image deletion with proper error handling.

This code properly checks if an image exists before attempting deletion and includes error handling for potential file system issues. The warning is appropriately logged if deletion fails, which aids in debugging.

# Delete the course image if it exists
if course.image and os.path.isfile(course.image.path):
    try:
        os.remove(course.image.path)
    except (PermissionError, OSError) as e:
        logger.warning(f"Failed to delete image for course {course.slug}: {e}")
🧰 Tools
🪛 Ruff (0.8.2)

923-923: Logging statement uses f-string

(G004)


928-928: Good post-deletion redirect.

After successful deletion, redirecting to the profile page is appropriate as it returns the user to a relevant page in the application flow.

Comment thread web/views.py Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 11, 2025
Copy link
Copy Markdown
Contributor

@A1L13N A1L13N left a comment

Choose a reason for hiding this comment

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

Please add a screenshot

@IITI-tushar IITI-tushar force-pushed the users-delete-course branch from 917b0b7 to e51f610 Compare April 13, 2025 16:08
@IITI-tushar IITI-tushar force-pushed the users-delete-course branch from e51f610 to 13eb036 Compare April 14, 2025 10:50
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
web/views.py (1)

967-984: 🧹 Nitpick (assertive)

Good implementation of image deletion before course removal.

The function now properly handles image cleanup during course deletion with:

  1. A clear docstring explaining the purpose
  2. An improved error message for unauthorized access
  3. Checks if an image exists and removes it from the filesystem

While this works well, consider adding error handling for the file deletion operation to prevent potential issues with file permissions:

# Delete the course image if it exists
if course.image and os.path.isfile(course.image.path):
-    os.remove(course.image.path)
+    try:
+        os.remove(course.image.path)
+    except (PermissionError, OSError) as e:
+        logger.warning(f"Failed to delete image for course {course.slug}: {e}")
web/models.py (1)

315-318: 🧹 Nitpick (assertive)

Good implementation for proper resource cleanup.

This method ensures that any associated image files are properly removed from storage when a Course instance is deleted, preventing orphaned files in the filesystem.

To align with static analysis recommendations, consider adding type annotations:

-    def delete(self, *args, **kwargs):
+    def delete(self, *args: Any, **kwargs: Any) -> None:
         if self.image:
             self.image.delete(save=False)
         super().delete(*args, **kwargs)

You would need to add from typing import Any at the top of the file.

🧰 Tools
🪛 Ruff (0.8.2)

315-315: Missing return type annotation for public function delete

Add return type annotation: None

(ANN201)


315-315: Missing type annotation for *args

(ANN002)


315-315: Missing type annotation for **kwargs

(ANN003)

web/templates/courses/delete_confirm.html (1)

16-20: ⚠️ Potential issue

Form implementation looks good but contains a duplicate CSRF token.

The form action is correctly set to target the delete_course view with the course ID, and the hidden input field properly passes the course identifier to the backend.

There's a duplicate CSRF token in the form (line 21). Since Django only requires one token per form, remove the duplicate:

  <form method="post"
        action="{% url 'delete_course' course.id %}"
        class="space-y-6">
    {% csrf_token %}
    <input type="hidden" name="course_id" value="{{ course.id }}" />
-   {% csrf_token %}
    <div class="flex justify-center space-x-4">
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e51f610 and 13eb036.

📒 Files selected for processing (4)
  • web/models.py (1 hunks)
  • web/templates/courses/delete_confirm.html (1 hunks)
  • web/templates/courses/detail.html (1 hunks)
  • web/views.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/views.py (1)
web/models.py (4)
  • Course (233-332)
  • image (1246-1251)
  • delete (315-318)
  • delete (472-478)
🪛 Ruff (0.8.2)
web/models.py

315-315: Missing return type annotation for public function delete

Add return type annotation: None

(ANN201)


315-315: Missing type annotation for *args

(ANN002)


315-315: Missing type annotation for **kwargs

(ANN003)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build-and-test
  • GitHub Check: Run Tests

Comment thread web/templates/courses/detail.html
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
web/models.py (1)

315-318: Great implementation of proper resource cleanup!

The override of the delete method ensures that any associated image files are properly removed from storage when a Course instance is deleted, preventing orphaned files in the filesystem. This is good practice for resource management.

Consider adding type annotations to align with the static analysis recommendations:

-    def delete(self, *args, **kwargs):
+    def delete(self, *args: Any, **kwargs: Any) -> None:
         if self.image:
             self.image.delete(save=False)
         super().delete(*args, **kwargs)

You would need to add from typing import Any at the top of the file.

🧰 Tools
🪛 Ruff (0.8.2)

315-315: Missing return type annotation for public function delete

Add return type annotation: None

(ANN201)


315-315: Missing type annotation for *args

(ANN002)


315-315: Missing type annotation for **kwargs

(ANN003)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13eb036 and d8f71ce.

📒 Files selected for processing (3)
  • web/models.py (1 hunks)
  • web/templates/courses/detail.html (1 hunks)
  • web/views.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/views.py (1)
web/models.py (4)
  • Course (233-332)
  • image (1248-1253)
  • delete (315-318)
  • delete (472-478)
🪛 Ruff (0.8.2)
web/models.py

315-315: Missing return type annotation for public function delete

Add return type annotation: None

(ANN201)


315-315: Missing type annotation for *args

(ANN002)


315-315: Missing type annotation for **kwargs

(ANN003)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run Tests
  • GitHub Check: build-and-test
🔇 Additional comments (3)
web/views.py (3)

967-970: Docstring and spacing improvements enhance readability.

The addition of a clear docstring and proper spacing improves code readability and maintainability.


972-973: Improved error message for unauthorized access.

The error message is now more clear and professional, which improves the user experience.


983-983: Appropriate redirection after course deletion.

Redirecting to the profile page after deleting a course provides a clear user flow.

Comment thread web/templates/courses/detail.html
Comment thread web/views.py Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 19, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8f71ce and a3deba1.

📒 Files selected for processing (3)
  • web/templates/courses/delete_confirm.html (1 hunks)
  • web/templates/courses/detail.html (1 hunks)
  • web/views.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/views.py (1)
web/models.py (3)
  • Course (233-332)
  • delete (315-318)
  • delete (472-478)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build-and-test
  • GitHub Check: Run Tests
🔇 Additional comments (2)
web/templates/courses/delete_confirm.html (1)

16-18:

Details

✅ Verification successful

Confirm the form action matches your URL pattern name and parameter
The addition of

action="{% url 'delete_course' course.slug %}"

ensures the form submits to the delete view, but please verify that your URLconf declares a delete_course route accepting a slug (not id).

Run this script to locate and inspect the pattern in your URL definitions:


🏁 Script executed:

#!/bin/bash
# Verify the delete_course URL pattern exists and uses <slug:slug>
rg -n "delete_course" -A2

Length of output: 1203


Confirmed delete_course URL pattern uses <slug:slug>
The URLconf in web/urls.py defines:

path("courses/<slug:slug>/delete/", views.delete_course, name="delete_course")

and the view signature delete_course(request, slug) matches. The form’s action="{% url 'delete_course' course.slug %}" is correct.

web/views.py (1)

965-982: Well-implemented course deletion function.

The changes to the delete_course function properly handle course deletion by:

  1. Adding a clear docstring explaining the purpose
  2. Improving the error message for unauthorized access
  3. Relying on the model's delete method to handle image deletion automatically
  4. Including a clarifying comment about how the course image gets removed

This implementation correctly addresses the prior feedback by eliminating redundant image deletion logic which could have caused errors.

🧰 Tools
🪛 Ruff (0.8.2)

966-966: Missing return type annotation for public function delete_course

(ANN201)


966-966: Missing type annotation for function argument request

(ANN001)


966-966: Missing type annotation for function argument slug

(ANN001)

Comment thread web/templates/courses/delete_confirm.html Outdated
Comment thread web/templates/courses/detail.html
@IITI-tushar IITI-tushar force-pushed the users-delete-course branch from b6f706c to 2469edf Compare April 19, 2025 07:46
@A1L13N A1L13N added this pull request to the merge queue Apr 25, 2025
Merged via the queue into alphaonelabs:main with commit 4a4e6ce Apr 25, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a way for users to delete their course, make sure the image is deleted from the media folder as well

2 participants