Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@rinkitadhana
Copy link
Contributor

@rinkitadhana rinkitadhana commented Oct 14, 2025

fixes #4624

Screen.Recording.2025-10-14.at.11.mp4

Summary by CodeRabbit

  • New Features
    • Domains: Replaced card layout with a four-column table (Domain, URL, Status, Actions). Added View/Edit/Delete controls with a confirm-before-delete flow; preserved empty-state and Add Domain CTA.
    • Roles: Complete roles management revamp with a unified roles table, Add/Edit modals, conditional Actions based on permissions and ownership protections, richer role details, and clearer success/error messages.
  • Accessibility & UX
    • Improved modal behavior (Escape-key and overlay-click to close), updated header/content layout, refreshed page metadata, and removed the previous loading overlay.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

Converted domain listing to a four-column table with client-side delete form submission. Rebuilt roles UI into a single manage-roles page with Add/Edit modals, client-side modal handlers, and consolidated roles table. Server view refactored to enforce permissions and handle add/update/remove role actions with richer context.

Changes

Cohort / File(s) Summary
Domains management template overhaul
website/templates/organization/dashboard/organization_manage_domains.html
Replaced card-style domain list with a 4-column table (Domain, URL, Status, Actions). Removed per-item inline forms and loading overlay. Added confirmDelete(domainId, domainName) JS that builds/submits a dynamic DELETE form to the domain route. Preserved empty-state and Add Domain CTA.
Roles management template redesign + modal workflows
website/templates/organization/dashboard/organization_manage_roles.html
Rewrote page layout to header + main content; replaced per-domain UI with a unified roles table, Add/Edit Role modals, client-side modal open/close (ESC/overlay) handlers, conditional action buttons and ownership safeguards. Renamed template block {% block js %}{% block scripts %} and updated meta blocks.
Roles view permission and action handling
website/views/company.py
Overhauled OrganizationDashboardManageRolesView: added permission checks (org admin/manager/owner), assembled roles_data with user/domain details, computed available_users and role counts, and implemented POST handlers for add_role, update_role, and remove_role with validations (prevent self/owner edits/removals, prevent duplicates). Added OrganizationAdmin import and expanded template context.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant B as Browser
  participant S as Server (ManageRolesView)
  participant DB as Data Store

  rect rgb(242,248,255)
  note over U,B: Load Manage Roles (GET)
  U->>B: Navigate to manage-roles
  B->>S: GET /manage-roles
  S->>DB: Fetch org, current_user_role, roles, domains, users
  S-->>B: 200 HTML (roles table, modals, context)
  end

  rect rgb(245,255,250)
  note over U,B: Add Role (modal)
  U->>B: Open & submit Add Role
  B->>S: POST action=add_role
  S->>S: Validate permissions, duplicates, self-assignment
  S->>DB: Create role
  S-->>B: Redirect/response with outcome
  end

  rect rgb(255,250,240)
  note over U,B: Edit Role (modal)
  U->>B: Open & submit Edit Role
  B->>S: POST action=update_role
  S->>S: Validate (no self/owner modification)
  S->>DB: Update role
  S-->>B: Redirect/response with outcome
  end

  rect rgb(255,240,245)
  note over U,B: Remove Role (confirm)
  U->>B: Click Remove, confirm
  B->>S: POST action=remove_role
  S->>S: Validate (no self/owner removal)
  S->>DB: Deactivate role
  S-->>B: Redirect/response with outcome
  end
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant B as Browser
  participant T as Domains JS
  participant S as Server (Domains Endpoint)

  U->>B: Click "Delete" on domain row
  B->>T: Trigger confirmDelete(domainId, domainName)
  T->>U: Browser confirm dialog (custom)
  alt Confirmed
    T->>S: Submit dynamic form (DELETE via domain route)
    S-->>T: Redirect/response with outcome
  else Canceled
    T-->>U: No action
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The pull request includes updates to the organization_manage_domains template, which are unrelated to the linked issue #4624 focused solely on the manage roles page, indicating code changes outside the defined scope of the issue. Extract the domain management template modifications into a separate pull request to keep the scope aligned with issue #4624.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately and concisely describes the primary change in the pull request, focusing on the redesign and fixes for the manage roles page, which aligns with the main scope of the changeset. It uses clear terminology and avoids unnecessary details, making it easy to understand at a glance.
Linked Issues Check ✅ Passed The pull request implements the requested redesign and fixes for the manage roles page by overhauling the UI template, adding modals for add/edit, enforcing permission checks in the view, and handling role add/update/remove actions, which fully addresses issue #4624.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
website/views/company.py (3)

659-661: Expose is_active to template.

Needed for Manage Domains status badge.

-        domains = domains_query.values(
-            "id", "name", "url", "logo", "has_security_txt", "security_txt_checked_at"
-        ).order_by("name")
+        domains = domains_query.values(
+            "id", "name", "url", "logo", "is_active", "has_security_txt", "security_txt_checked_at"
+        ).order_by("name")

930-938: Authorization gap: ensure domain belongs to the organization before deleting.

Currently any member could delete a domain from another org by ID. Enforce org match.

     def delete(self, request, id, *args, **kwargs):
         domain_id = request.POST.get("domain_id", None)
-        domain = get_object_or_404(Domain, id=domain_id)
+        domain = get_object_or_404(Domain, id=domain_id)
         if domain is None:
             messages.error(request, "Domain not found.")
             return redirect("organization_manage_domains", id=id)
+        if domain.organization_id != id:
+            messages.error(request, "You do not have permission to delete this domain.")
+            return redirect("organization_manage_domains", id=id)
         domain.delete()
         messages.success(request, "Domain deleted successfully")
         return redirect("organization_manage_domains", id=id)

878-879: Don’t disable TLS verification.

verify=False weakens security and can hide MITM. Use default verification.

-                    response = requests.get(safe_url, timeout=5, verify=False)
+                    response = requests.get(safe_url, timeout=5)
🧹 Nitpick comments (4)
website/views/company.py (4)

695-697: Remove debug print.

Leftover print floods stdout.

-        elif method == "put":
-            print("*" * 100)
-            return self.put(request, *args, **kwargs)
+        elif method == "put":
+            return self.put(request, *args, **kwargs)

1341-1344: Robustly extract organization email domain from URL.

urlparse(...).netloc is empty for bare domains like example.com. Fall back to path.

-        organization_url = organization_obj.url
-        parsed_url = urlparse(organization_url).netloc
-        organization_domain = parsed_url.replace("www.", "").strip()
+        organization_url = organization_obj.url or ""
+        parsed = urlparse(organization_url)
+        host = (parsed.netloc or parsed.path or "").strip()
+        organization_domain = host.replace("www.", "").strip().lower()

1485-1488: Improve exception handling and logging.

Avoid broad Exception and use logger.exception for stack traces.

-            except User.DoesNotExist:
-                messages.error(request, "User not found or inactive")
-            except Exception as e:
-                logger.error(f"Error adding role: {str(e)}")
-                messages.error(request, "An error occurred while adding the role. Please try again.")
+            except User.DoesNotExist:
+                messages.error(request, "User not found or inactive")
+            except Exception:
+                logger.exception("Error adding role")
+                messages.error(request, "An error occurred while adding the role. Please try again.")
@@
-            except OrganizationAdmin.DoesNotExist:
-                messages.error(request, "Role not found")
-            except Exception as e:
-                logger.error(f"Error updating role: {str(e)}")
-                messages.error(request, "An error occurred while updating the role. Please try again.")
+            except OrganizationAdmin.DoesNotExist:
+                messages.error(request, "Role not found")
+            except Exception:
+                logger.exception("Error updating role")
+                messages.error(request, "An error occurred while updating the role. Please try again.")
@@
-            except OrganizationAdmin.DoesNotExist:
-                messages.error(request, "Role not found")
-            except Exception as e:
-                logger.error(f"Error removing role: {str(e)}")
-                messages.error(request, "An error occurred while removing the role. Please try again.")
+            except OrganizationAdmin.DoesNotExist:
+                messages.error(request, "Role not found")
+            except Exception:
+                logger.exception("Error removing role")
+                messages.error(request, "An error occurred while removing the role. Please try again.")

As per coding guidelines and static analysis

Also applies to: 1523-1526, 1551-1554


1413-1413: Nit: Remove unused args/kwargs in post.

Silences ARG002 and clarifies signature.

-    def post(self, request, id, *args, **kwargs):
+    def post(self, request, id, *_args, **_kwargs):
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between fbd3912 and 9f2f2d9.

📒 Files selected for processing (3)
  • website/templates/organization/dashboard/organization_manage_domains.html (3 hunks)
  • website/templates/organization/dashboard/organization_manage_roles.html (1 hunks)
  • website/views/company.py (2 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
website/templates/organization/dashboard/organization_manage_roles.html

[warning] 348-352: DOM text reinterpreted as HTML
DOM text is reinterpreted as HTML without escaping meta-characters.

website/templates/organization/dashboard/organization_manage_domains.html

[warning] 173-177: DOM text reinterpreted as HTML
DOM text is reinterpreted as HTML without escaping meta-characters.

🪛 Ruff (0.14.0)
website/views/company.py

1413-1413: Unused method argument: args

(ARG002)


1413-1413: Unused method argument: kwargs

(ARG002)


1485-1485: Do not catch blind exception: Exception

(BLE001)


1486-1486: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1486-1486: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1523-1523: Do not catch blind exception: Exception

(BLE001)


1524-1524: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1524-1524: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1551-1551: Do not catch blind exception: Exception

(BLE001)


1552-1552: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1552-1552: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Tests
🔇 Additional comments (1)
website/templates/organization/dashboard/organization_manage_roles.html (1)

304-379: Verified: base template defines {% block scripts %}.

@github-project-automation github-project-automation bot moved this from Backlog to Ready in 📌 OWASP BLT Project Board Oct 14, 2025
Copy link
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

♻️ Duplicate comments (2)
website/templates/organization/dashboard/organization_manage_domains.html (2)

81-85: Status badge remains broken: is_active still missing from context.

This issue was previously flagged. The template checks domain.is_active, but OrganizationDashboardManageDomainsView.get (lines 659-661 in website/views/company.py) returns domains via values(...) without including is_active, so this condition is always false.

Apply this diff to website/views/company.py to fix:

 domains = domains_query.values(
-    "id", "name", "url", "logo", "has_security_txt", "security_txt_checked_at"
+    "id", "name", "url", "logo", "is_active", "has_security_txt", "security_txt_checked_at"
 ).order_by("name")

165-183: Fix innerHTML DOM injection risk flagged by CodeQL.

Using innerHTML to inject form fields (lines 174-178) is a security risk. Even though inputs appear benign, any unescaped content in csrfToken or domainId could be interpreted as HTML/script tags.

Based on static analysis

Apply this diff to use createElement instead:

 function confirmDelete(domainId, domainName) {
-    if (confirm(`Are you sure you want to delete ${domainName}? This action cannot be undone.`)) {
+    if (!confirm(`Are you sure you want to delete ${domainName}? This action cannot be undone.`)) return;
+
         const form = document.createElement('form');
         form.method = 'post';
         form.action = '{% url "add_domain" organization %}';
         
         const csrfElement = document.querySelector('[name=csrfmiddlewaretoken]');
         const csrfToken = csrfElement ? csrfElement.value : '{{ csrf_token|escapejs }}';
         
-        form.innerHTML = `
-            <input type="hidden" name="csrfmiddlewaretoken" value="${csrfToken}">
-            <input type="hidden" name="_method" value="delete">
-            <input type="hidden" name="domain_id" value="${domainId}">
-        `;
+        const csrfField = document.createElement('input');
+        csrfField.type = 'hidden';
+        csrfField.name = 'csrfmiddlewaretoken';
+        csrfField.value = csrfToken;
+
+        const methodField = document.createElement('input');
+        methodField.type = 'hidden';
+        methodField.name = '_method';
+        methodField.value = 'delete';
+
+        const idField = document.createElement('input');
+        idField.type = 'hidden';
+        idField.name = 'domain_id';
+        idField.value = String(domainId);
+
+        form.append(csrfField, methodField, idField);
         
         document.body.appendChild(form);
         form.submit();
-    }
 }
🧹 Nitpick comments (3)
website/views/company.py (3)

1338-1369: Consider the heuristic nature of email domain matching.

The code extracts the domain from organization.url (lines 1341-1346) and matches users with emails ending in @{domain} (lines 1350-1354). This heuristic assumes the organization's URL domain matches their email domain, which may not always be true (e.g., URL example.com but emails @exampleinc.com).

The fallback to all active users (lines 1357-1362, 1365-1369) mitigates this limitation, but consider:

  • Adding an explicit email_domain field to the Organization model for precise matching
  • Or documenting this heuristic behavior for users

1416-1416: Remove unused method parameters.

The args and kwargs parameters are not used in this method.

Based on static analysis

Apply this diff:

-    def post(self, request, id, *args, **kwargs):
+    def post(self, request, id):

1459-1466: Consider reactivating inactive roles instead of creating duplicates.

The check at lines 1459-1466 only looks for existing active roles. If a user previously had a role that was deactivated (via remove_role), this logic will create a new OrganizationAdmin record, leaving the inactive one orphaned.

Consider reactivating existing inactive roles:

# Check for existing roles (active or inactive)
existing_role = OrganizationAdmin.objects.filter(
    user=user, organization=organization_obj
).first()

if existing_role:
    if existing_role.is_active:
        messages.error(request, f"{user.username} already has an active role in this organization")
        return redirect("organization_manage_roles", id=id)
    else:
        # Reactivate and update the existing role
        existing_role.is_active = True
        existing_role.role = int(role)
        existing_role.domain = domain
        existing_role.save()
        messages.success(request, f"Reactivated and updated role for {user.username}")
        return redirect("organization_manage_roles", id=id)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9f2f2d9 and c541e47.

📒 Files selected for processing (2)
  • website/templates/organization/dashboard/organization_manage_domains.html (3 hunks)
  • website/views/company.py (2 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
website/templates/organization/dashboard/organization_manage_domains.html

[warning] 173-177: DOM text reinterpreted as HTML
DOM text is reinterpreted as HTML without escaping meta-characters.

🪛 Ruff (0.14.0)
website/views/company.py

1416-1416: Unused method argument: args

(ARG002)


1416-1416: Unused method argument: kwargs

(ARG002)


1488-1488: Do not catch blind exception: Exception

(BLE001)


1489-1489: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1489-1489: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1526-1526: Do not catch blind exception: Exception

(BLE001)


1527-1527: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1527-1527: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1554-1554: Do not catch blind exception: Exception

(BLE001)


1555-1555: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1555-1555: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Tests
🔇 Additional comments (3)
website/views/company.py (3)

1303-1329: LGTM! Thorough permission checks.

The permission logic correctly:

  • Verifies user is admin or manager (lines 1304-1309)
  • Retrieves the user's role level via OrganizationAdmin (lines 1312-1323)
  • Restricts role management to admins only (lines 1325-1328)
  • Grants full access to organization owners even without an explicit role

1371-1399: LGTM! Clean data formatting.

The role data assembly is thorough and handles edge cases:

  • Safely accesses user.userprofile with hasattr check (lines 1383-1385)
  • Marks organization owner roles (line 1392)
  • Provides role counts for UI display (lines 1396-1399)

1546-1548: LGTM! Soft delete approach is good for audit trail.

Deactivating roles (is_active = False) instead of hard-deleting preserves the audit trail and allows potential reactivation.

Copy link
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

🧹 Nitpick comments (2)
website/views/company.py (2)

1341-1369: Consider limiting available_users query scope.

The fallback logic fetches up to 100 active users when no organization domain match exists. For large user bases, this could be inefficient or expose unnecessary user data.

Consider adding a search/autocomplete interface instead of pre-loading all users, or further restricting the fallback query (e.g., users who have interacted with the organization).


1416-1416: Remove unused method arguments.

The args and kwargs parameters are unused in the POST method signature.

Based on static analysis

Apply this diff:

-    def post(self, request, id, *args, **kwargs):
+    def post(self, request, id):
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between d0cf932 and d76e8fb.

📒 Files selected for processing (2)
  • website/templates/organization/dashboard/organization_manage_roles.html (1 hunks)
  • website/views/company.py (4 hunks)
🧰 Additional context used
🪛 Ruff (0.14.0)
website/views/company.py

1416-1416: Unused method argument: args

(ARG002)


1416-1416: Unused method argument: kwargs

(ARG002)


1489-1489: Redundant exception object included in logging.exception call

(TRY401)


1527-1527: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1527-1527: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1530-1530: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1530-1530: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1533-1533: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1533-1533: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1564-1564: Redundant exception object included in logging.exception call

(TRY401)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (7)
website/templates/organization/dashboard/organization_manage_roles.html (4)

107-149: LGTM! Action visibility logic now correctly prevents owner/self edits.

The conditional logic at line 107 ({% if not role.is_owner and role.user_id != request.user.id %}) properly blocks editing both owner roles and the current user's own role. The escapejs filter on lines 108 and 120 correctly mitigates XSS risks when passing usernames to JavaScript.


339-382: LGTM! DOM manipulation hardened with createElement.

The function now:

  • Sanitizes the username for display (line 341)
  • Robustly finds the CSRF token with error handling (lines 345-349)
  • Uses createElement and .value assignment instead of innerHTML (lines 357-377)

This addresses the CodeQL warning about DOM text reinterpretation.

Based on static analysis


385-402: LGTM! Accessibility features implemented.

The modal close handlers for Escape key (lines 387-392) and overlay clicks (lines 395-401) improve keyboard navigation and user experience.


108-108: Fix role value handling in JavaScript call.

When role.role is falsy, |default:"null" produces the string "null" instead of JavaScript's null, causing type mismatches.

Apply this diff:

-<button onclick="openEditRoleModal({{ role.id }}, '{{ role.username|escapejs }}', {{ role.role|default:"null" }}, {% if role.domain_id %}{{ role.domain_id }}{% else %}null{% endif %})"
+<button onclick="openEditRoleModal({{ role.id }}, '{{ role.username|escapejs }}', {{ role.role|default:0 }}, {% if role.domain_id %}{{ role.domain_id }}{% else %}null{% endif %})"

Likely an incorrect or invalid review comment.

website/views/company.py (3)

1303-1329: LGTM! Permission checks are comprehensive and correctly enforced.

The permission logic:

  • Verifies user is org admin or manager (lines 1304-1309)
  • Retrieves current user's role level (lines 1312-1323)
  • Only allows admins (role=0) or org owner to manage roles (lines 1326-1328)

This properly restricts role management to authorized users.


1443-1491: LGTM! Role addition logic includes proper safeguards.

The add_role action:

  • Accepts either user_id or email (lines 1451-1457)
  • Prevents duplicate roles (lines 1460-1466)
  • Prevents self-assignment (lines 1469-1471)
  • Handles optional domain assignment (lines 1474-1476)
  • Uses specific exception types instead of blind catch-all

1539-1566: LGTM! Role removal safely deactivates instead of deleting.

The remove_role action:

  • Prevents removing own role (lines 1546-1548)
  • Prevents removing owner's role (lines 1551-1553)
  • Deactivates role instead of deleting (lines 1556-1557), preserving audit trail

Comment on lines +1488 to +1490
except (ValidationError, IntegrityError) as e:
logger.exception(f"Error adding role: {e!s}")
messages.error(request, "An error occurred while adding the role. Please try again.")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix redundant exception in logging.exception call.

Line 1489 includes {e!s} when logger.exception already includes the exception info automatically.

Based on static analysis

Apply this diff:

-            except (ValidationError, IntegrityError) as e:
-                logger.exception(f"Error adding role: {e!s}")
+            except (ValidationError, IntegrityError):
+                logger.exception("Error adding role")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except (ValidationError, IntegrityError) as e:
logger.exception(f"Error adding role: {e!s}")
messages.error(request, "An error occurred while adding the role. Please try again.")
except (ValidationError, IntegrityError):
logger.exception("Error adding role")
messages.error(request, "An error occurred while adding the role. Please try again.")
🧰 Tools
🪛 Ruff (0.14.0)

1489-1489: Redundant exception object included in logging.exception call

(TRY401)

🤖 Prompt for AI Agents
In website/views/company.py around lines 1488 to 1490, remove the redundant
{e!s} from the logger.exception f-string; change the call to simply
logger.exception("Error adding role") (or logger.exception("Error adding role:
%s", e) if you prefer an inline message) so the exception info is not duplicated
and the stacktrace is still logged automatically.

Comment on lines +1524 to +1537
except OrganizationAdmin.DoesNotExist:
messages.error(request, "Role not found")
except ValueError as e:
logger.error(f"Invalid value provided when updating role: {str(e)}")
messages.error(request, str(e))
except ValidationError as e:
logger.error(f"Validation error when updating role: {str(e)}")
messages.error(request, str(e))
except IntegrityError as e:
logger.error(f"Database integrity error when updating role: {str(e)}")
messages.error(request, "Database integrity error: Unable to update role due to conflicting data")
except Exception as e:
logger.exception("Error updating role")
messages.error(request, "An error occurred while updating the role. " + str(e))
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Improve exception logging consistency.

Lines 1527, 1530, 1533 use logger.error instead of logger.exception, preventing traceback capture. The final catch-all (line 1536) correctly uses logger.exception.

Based on static analysis

Apply this diff:

             except OrganizationAdmin.DoesNotExist:
                 messages.error(request, "Role not found")
             except ValueError as e:
-                logger.error(f"Invalid value provided when updating role: {str(e)}")
+                logger.exception("Invalid value provided when updating role")
                 messages.error(request, str(e))
             except ValidationError as e:
-                logger.error(f"Validation error when updating role: {str(e)}")
+                logger.exception("Validation error when updating role")
                 messages.error(request, str(e))
             except IntegrityError as e:
-                logger.error(f"Database integrity error when updating role: {str(e)}")
+                logger.exception("Database integrity error when updating role")
                 messages.error(request, "Database integrity error: Unable to update role due to conflicting data")
             except Exception as e:
                 logger.exception("Error updating role")
                 messages.error(request, "An error occurred while updating the role. " + str(e))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except OrganizationAdmin.DoesNotExist:
messages.error(request, "Role not found")
except ValueError as e:
logger.error(f"Invalid value provided when updating role: {str(e)}")
messages.error(request, str(e))
except ValidationError as e:
logger.error(f"Validation error when updating role: {str(e)}")
messages.error(request, str(e))
except IntegrityError as e:
logger.error(f"Database integrity error when updating role: {str(e)}")
messages.error(request, "Database integrity error: Unable to update role due to conflicting data")
except Exception as e:
logger.exception("Error updating role")
messages.error(request, "An error occurred while updating the role. " + str(e))
except OrganizationAdmin.DoesNotExist:
messages.error(request, "Role not found")
except ValueError as e:
logger.exception("Invalid value provided when updating role")
messages.error(request, str(e))
except ValidationError as e:
logger.exception("Validation error when updating role")
messages.error(request, str(e))
except IntegrityError as e:
logger.exception("Database integrity error when updating role")
messages.error(request, "Database integrity error: Unable to update role due to conflicting data")
except Exception as e:
logger.exception("Error updating role")
messages.error(request, "An error occurred while updating the role. " + str(e))
🧰 Tools
🪛 Ruff (0.14.0)

1527-1527: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1527-1527: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1530-1530: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1530-1530: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1533-1533: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1533-1533: Use explicit conversion flag

Replace with conversion flag

(RUF010)

🤖 Prompt for AI Agents
In website/views/company.py around lines 1524 to 1537, the specific except
blocks for ValueError (line ~1527), ValidationError (line ~1530) and
IntegrityError (line ~1533) use logger.error which prevents tracebacks from
being captured; change those three logger.error calls to logger.exception so the
stack traces are logged while leaving the user-facing messages unchanged, and
keep the final generic except using logger.exception as is.

Comment on lines +1563 to +1565
except (ValidationError, ValueError) as e:
logger.exception(f"Error removing role: {e!s}")
messages.error(request, "An error occurred while removing the role. Please try again.")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix redundant exception in logging.exception call.

Line 1564 includes {e!s} when logger.exception already includes the exception info automatically.

Based on static analysis

Apply this diff:

-            except (ValidationError, ValueError) as e:
-                logger.exception(f"Error removing role: {e!s}")
+            except (ValidationError, ValueError):
+                logger.exception("Error removing role")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except (ValidationError, ValueError) as e:
logger.exception(f"Error removing role: {e!s}")
messages.error(request, "An error occurred while removing the role. Please try again.")
except (ValidationError, ValueError):
logger.exception("Error removing role")
messages.error(request, "An error occurred while removing the role. Please try again.")
🧰 Tools
🪛 Ruff (0.14.0)

1564-1564: Redundant exception object included in logging.exception call

(TRY401)

🤖 Prompt for AI Agents
In website/views/company.py around lines 1563 to 1565, the logger.exception call
redundantly interpolates the exception with {e!s}; remove the formatted
exception from the message and call logger.exception with a descriptive string
(e.g., "Error removing role") so the exception info is recorded automatically;
keep the messages.error line unchanged.

@DonnieBLT DonnieBLT merged commit 82ad67c into OWASP-BLT:main Oct 14, 2025
17 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix manage roles page

2 participants