Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new “library” API for listing quizzes and folders visible to a user (owned + shared), including root-level listing and folder-scoped listing. Introduces a SharedFolder model analogous to SharedQuiz and adds endpoint-level tests.
Changes:
- Added
/library/and/library/<folder_id>/endpoints with visibility logic for owned and shared folders/quizzes. - Introduced
SharedFoldermodel + migration to represent folder sharing (user or study group). - Added
LibraryItemSerializerand a test suite for the new library endpoints.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
quizzes/views.py |
Implements the new library endpoints and visibility rules for folders/quizzes. |
quizzes/urls.py |
Adds routes for /library/ and /library/<uuid:folder_id>/. |
quizzes/tests/test_library_endpoint.py |
Adds tests for library root + folder access behavior. |
quizzes/serializers.py |
Adds a polymorphic-ish serializer for returning either a folder or a quiz as a “library item”. |
quizzes/models.py |
Adds SharedFolder model to represent folder sharing. |
quizzes/migrations/0017_sharedfolder.py |
Creates the SharedFolder table. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| class SharedFolder(models.Model): | ||
| id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) | ||
| folder = models.ForeignKey(Folder, on_delete=models.CASCADE, related_name="shares") | ||
| user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="shared_folders") | ||
| study_group = models.ForeignKey( | ||
| StudyGroup, on_delete=models.CASCADE, null=True, blank=True, related_name="shared_folders" | ||
| ) | ||
| allow_edit = models.BooleanField(default=False) |
There was a problem hiding this comment.
SharedFolder allows rows where both user and study_group are NULL (or both set), which makes the share ambiguous/ineffective and can lead to confusing permission behavior. Add a DB-level CheckConstraint to enforce exactly one of (user, study_group) is set, and consider UniqueConstraint(s) to prevent duplicate shares per (folder,user) / (folder,study_group).
| class SharedFolder(models.Model): | ||
| id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) | ||
| folder = models.ForeignKey(Folder, on_delete=models.CASCADE, related_name="shares") | ||
| user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="shared_folders") | ||
| study_group = models.ForeignKey( | ||
| StudyGroup, on_delete=models.CASCADE, null=True, blank=True, related_name="shared_folders" | ||
| ) | ||
| allow_edit = models.BooleanField(default=False) |
d454d6f to
149b73e
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def get(self, request): | ||
| user = request.user | ||
| items = list(self.get_toplevel_folders(user)) + list(self.get_toplevel_quizzes(user)) | ||
|
|
There was a problem hiding this comment.
The response ordering isn’t actually created_at-desc across all library items: folders are ordered internally, quizzes are ordered internally, then the two lists are concatenated, which breaks global ordering. If clients rely on a single timeline sort, sort the combined items list by created_at (or use a DB-level UNION/annotation) before serializing.
| items.sort(key=lambda item: item.created_at, reverse=True) |
| items = list(self.get_subfolders(user, folder_id)) + list(self.get_quizzes(user, folder_id)) | ||
| return Response(LibraryItemSerializer(items, many=True, context={"request": request}).data) |
There was a problem hiding this comment.
Same as in the root view: subfolders and quizzes are each ordered by created_at, but concatenating the two lists breaks a global created_at sort. Consider sorting the combined items list by created_at before serializing so the folder view matches the advertised ordering.
| class LibraryItemSerializer(serializers.Serializer): | ||
| def to_representation(self, instance): | ||
| user = self.context["request"].user | ||
|
|
||
| if isinstance(instance, Folder): | ||
| return { | ||
| "id": instance.id, | ||
| "name": instance.name, | ||
| "type": "folder", | ||
| "is_shared": (instance.owner_id != user.id), | ||
| "created_at": instance.created_at, | ||
| } | ||
|
|
||
| if isinstance(instance, Quiz): | ||
| return { | ||
| "id": instance.id, | ||
| "title": instance.title, | ||
| "type": "quiz", | ||
| "is_shared": (instance.maintainer_id != user.id), | ||
| "created_at": instance.created_at, | ||
| } | ||
|
|
||
| return super().to_representation(instance) |
There was a problem hiding this comment.
LibraryItemSerializer defines no explicit fields and only overrides to_representation(). This makes the response schema hard/impossible for drf-spectacular to infer (and removes any type/format guarantees for id/created_at), so /library endpoints will likely show up as an untyped/empty object in OpenAPI. Consider defining explicit serializer fields (even if some are optional) or annotating the views with @extend_schema(responses=...) to document the union shape.
|
Putting on hold until library design is finalized |
Done. Dodałem model SharedFolder analogiczny jak SharedQuiz. Napisałem testy.
Response z endpointu

/library/LibraryItem - to poprostu quiz albo folder.
/library- zwraca itemy które należą do użytkownika i nie są w żadnym folderze, są udostępnione przez innego użytkownika i albo u niego nie znajdują się w żadnym folderze lub znajdują się w folderze do którego użytkownik nie ma dostępu/library/{folder_id}- analogicznie jak wyżej, różnica taka że możemy sobie wybrać do którego folderu się ograniczamyTesty - (nawet przechodzą)

Important
Add library endpoints to retrieve user-specific folders and quizzes, introducing
SharedFoldermodel for sharing logic./library/and/library/{folder_id}endpoints inviews.pyto retrieve library items based on user ownership and sharing permissions.SharedFoldermodel inmodels.pyto handle folder sharing with users and study groups.LibraryItemSerializerinserializers.pyto serialize folders and quizzes for library endpoints.test_library_endpoint.pyto test new library endpoints, including access control and item retrieval.urls.pyto include new library endpoints.This description was created by
for 149b73e. You can customize this summary. It will automatically update as commits are pushed.