Skip to content

Implemented a dashboard for managing sheets#53

Merged
impxcts merged 6 commits intomainfrom
saved-sheets
Apr 22, 2026
Merged

Implemented a dashboard for managing sheets#53
impxcts merged 6 commits intomainfrom
saved-sheets

Conversation

@Davictory2003
Copy link
Copy Markdown
Contributor

No description provided.

Co-authored-by: Copilot <copilot@github.com>
Copilot AI review requested due to automatic review settings April 21, 2026 20:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a “My Sheets” dashboard and adds authenticated, per-user cheat sheet management across frontend and backend.

Changes:

  • Added a new Dashboard UI (component + CSS) to list, edit, delete, and download saved cheat sheets.
  • Secured backend cheat sheet + compile endpoints with authentication and user scoping, and introduced a user FK on CheatSheet.
  • Updated frontend auth/navigation flow and API calls to include JWT auth where required.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
frontend/src/styles/Dashboard.css Styles for the new dashboard layout/cards/empty/loading states.
frontend/src/hooks/latex.js Adds JWT auth header to /api/compile/ calls now that compilation is authenticated.
frontend/src/context/AuthContext.jsx Redirects successful login to /dashboard.
frontend/src/components/Dashboard.jsx New dashboard component: fetch/list sheets, edit/delete, compile+download PDF.
frontend/src/App.jsx Adds dashboard route/links, passes edit/reset handlers, and includes auth header on sheet save.
backend/api/views.py Requires auth for compile and cheat sheet CRUD; scopes cheat sheet queryset to the user; sets owner on create/from-template.
backend/api/serializers.py Exposes user field as read-only on CheatSheetSerializer.
backend/api/models.py Adds CheatSheet.user foreign key.
backend/api/migrations/0003_cheatsheet_user.py Migration adding the user FK to CheatSheet.
.gitignore Adds additional ignores for .DS_Store (recursive) and Playwright/opencode artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/api/models.py Outdated
@@ -1,5 +1,5 @@
from django.db import models

from django.contrib.auth.models import User
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The model imports User directly for the CheatSheet.user FK. For better compatibility with a swappable user model, prefer referencing settings.AUTH_USER_MODEL (and avoid importing django.contrib.auth.models.User in models). This keeps the model consistent with the migration which targets settings.AUTH_USER_MODEL.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Applied in commit 1462605: CheatSheet.user now references settings.AUTH_USER_MODEL instead of importing User directly, keeping the model consistent with the migration.

Comment thread backend/api/models.py Outdated
Comment on lines +16 to +20
const response = await fetch('/api/cheatsheets/', {
headers: {
'Authorization': `Bearer ${authTokens?.access}`,
},
});
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

These requests always send an Authorization: Bearer ${authTokens?.access} header. If authTokens is temporarily null/undefined (e.g., during initial render or logout transitions), the header becomes Bearer undefined and can cause confusing 401s. Build headers conditionally (only include Authorization when you have a token) or early-return/navigate when the token is missing.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Already addressed in commit 1462605. fetchSheets, handleDelete, and handleDownload all early-return when authTokens?.access is absent, so no `****** header is ever sent.

Comment thread frontend/src/components/Dashboard.jsx Outdated
Comment thread frontend/src/App.jsx
Comment on lines 94 to +99
const response = await fetch(sheetId ? `/api/cheatsheets/${sheetId}/` : '/api/cheatsheets/', {
method: sheetId ? 'PATCH' : 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authTokens?.access}`
},
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

handleSave always includes an Authorization header even when authTokens is falsy, which can result in sending Bearer undefined and returning 401s that are hard to diagnose. Consider conditionally adding the header only when a token exists (and/or blocking save attempts when not authenticated).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Already addressed in commit 1462605. The Authorization header in handleSave is now conditionally spread: ...(authTokens?.access ? { 'Authorization': \****** } : {})`.

Comment thread backend/api/views.py
Comment on lines +213 to +216
permission_classes = [IsAuthenticated]

def get_queryset(self):
return self.queryset.filter(user=self.request.user).order_by('-updated_at')
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

This adds per-user isolation for cheat sheets (IsAuthenticated + get_queryset() filtering by request.user), but there don't appear to be tests asserting that a user cannot list/retrieve/update/delete another user's sheets. Adding a multi-user test case would help prevent regressions in access control behavior.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Already addressed in commit 1462605. Added TestCheatSheetAccessControl with five test cases asserting that list, retrieve, update, delete, and compile all return 404 when a second user attempts to access the first user's sheet.

Comment thread backend/api/views.py
Comment on lines 131 to 133
@api_view(["POST"])
@permission_classes([IsAuthenticated])
def compile_latex(request):
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

While adding IsAuthenticated here is good, compile_latex still resolves cheat_sheet_id later via get_object_or_404(CheatSheet, pk=cheat_sheet_id) without checking that the sheet belongs to request.user. That creates an IDOR risk (authenticated users can compile other users' sheets if they guess IDs). When a cheat_sheet_id is provided, ensure the lookup is restricted to user=request.user (or enforce object-level permissions) and return 404/403 for non-owned sheets.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Already addressed in commit 1462605. compile_latex now uses get_object_or_404(CheatSheet, pk=cheat_sheet_id, user=request.user), returning 404 for any sheet not owned by the requesting user.

@Davictory2003
Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

Davictory2003 and others added 3 commits April 22, 2026 10:55
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…s, access control tests

Agent-Logs-Url: https://github.com/ChicoState/cheat-sheet/sessions/2140163e-e1a0-470c-9140-1093fd4b48ca

Co-authored-by: Davictory2003 <68972845+Davictory2003@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 22, 2026

@copilot apply changes based on the comments in this thread

All review comments addressed in commit 1462605:

  • models.py: Uses settings.AUTH_USER_MODEL for the FK; user is now non-nullable with a new migration (0004_cheatsheet_user_nonnull).
  • Dashboard.jsx: Auth headers built conditionally (early-return when authTokens is absent); functional state update (prevSheets =>) used in handleDelete.
  • App.jsx: Authorization header in handleSave is only included when a token exists.
  • views.py (IDOR): compile_latex now scopes the cheat-sheet lookup to user=request.user, returning 404 for non-owned sheets.
  • tests.py: Added TestCheatSheetAccessControl with tests asserting that list, retrieve, update, delete, and compile all return 404 for another user's sheet.

@impxcts impxcts merged commit abb9605 into main Apr 22, 2026
4 checks passed
@Davictory2003 Davictory2003 deleted the saved-sheets branch April 22, 2026 18:16
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.

6 participants