Skip to content

Feat/117 quiz library endpoint#144

Draft
WiktorGruszczynski wants to merge 4 commits intomasterfrom
feat/117-quiz-library-endpoint
Draft

Feat/117 quiz library endpoint#144
WiktorGruszczynski wants to merge 4 commits intomasterfrom
feat/117-quiz-library-endpoint

Conversation

@WiktorGruszczynski
Copy link
Contributor

@WiktorGruszczynski WiktorGruszczynski commented Feb 8, 2026

Done. Dodałem model SharedFolder analogiczny jak SharedQuiz. Napisałem testy.

Response z endpointu /library/
image

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ę ograniczamy

Testy - (nawet przechodzą)
image


Important

Add library endpoints to retrieve user-specific folders and quizzes, introducing SharedFolder model for sharing logic.

  • Endpoints:
    • Adds /library/ and /library/{folder_id} endpoints in views.py to retrieve library items based on user ownership and sharing permissions.
  • Models:
    • Adds SharedFolder model in models.py to handle folder sharing with users and study groups.
  • Serializers:
    • Adds LibraryItemSerializer in serializers.py to serialize folders and quizzes for library endpoints.
  • Tests:
    • Adds test_library_endpoint.py to test new library endpoints, including access control and item retrieval.
  • URLs:
    • Updates urls.py to include new library endpoints.

This description was created by Ellipsis for 149b73e. You can customize this summary. It will automatically update as commits are pushed.

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

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 SharedFolder model + migration to represent folder sharing (user or study group).
  • Added LibraryItemSerializer and 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.

Comment on lines +38 to +45
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)
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

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).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

@WiktorGruszczynski wdg mnie słuszna uwaga

Copy link
Collaborator

@MoonPrincess06 MoonPrincess06 left a comment

Choose a reason for hiding this comment

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

jakbyś tylko mógł jeszcze zadbać o to, żeby nie było możliwe duplikowanie udostępnień tzn uniqueness dla (folder, user) (folder, study_group) to byłoby super:) I zerknij może na opis tego issue którego skomentowałam

Comment on lines +38 to +45
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)
Copy link
Collaborator

Choose a reason for hiding this comment

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

@WiktorGruszczynski wdg mnie słuszna uwaga

Copilot AI review requested due to automatic review settings February 8, 2026 19:45
@Antoni-Czaplicki Antoni-Czaplicki force-pushed the feat/117-quiz-library-endpoint branch from d454d6f to 149b73e Compare February 8, 2026 19:45
Copy link
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

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))

Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
items.sort(key=lambda item: item.created_at, reverse=True)

Copilot uses AI. Check for mistakes.
Comment on lines +792 to +793
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)
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +542 to +564
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)
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
@Antoni-Czaplicki Antoni-Czaplicki marked this pull request as draft February 8, 2026 20:10
@Antoni-Czaplicki
Copy link
Member

Putting on hold until library design is finalized

@MarvinRucinski MarvinRucinski linked an issue Feb 19, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Endpointy to wyświetlania quizów w bibliotece

4 participants