From 092a531d33c5078b332885f7fd1981c752e9c596 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Wed, 21 Feb 2024 21:55:34 +0100 Subject: [PATCH] Add new mutation for module and chapter highlights --- server/books/schema/nodes/module.py | 5 ++ server/notes/inputs.py | 7 ++- ..._alter_highlight_content_index_and_more.py | 22 +++++++ server/notes/models.py | 4 +- server/notes/mutations.py | 58 ++++++++++++++++++- server/notes/schema.py | 8 ++- server/schema.graphql | 31 ++++++++-- 7 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 server/notes/migrations/0009_alter_highlight_content_index_and_more.py diff --git a/server/books/schema/nodes/module.py b/server/books/schema/nodes/module.py index 7a6f367a..69dd96c3 100644 --- a/server/books/schema/nodes/module.py +++ b/server/books/schema/nodes/module.py @@ -56,6 +56,7 @@ class ModuleNode(DjangoObjectType): level = graphene.Field(ModuleLevelNode) category = graphene.Field(ModuleCategoryNode) language = graphene.String() + highlights = graphene.List("notes.schema.HighlightNode") def resolve_chapters(self, info, **kwargs): return Chapter.get_by_parent(self) @@ -123,6 +124,10 @@ class ModuleNode(DjangoObjectType): def resolve_language(parent: Module, info, **kwargs): return parent.locale.language_code + @staticmethod + def resolve_highlights(root: Module, info, **kwargs): + return root.highlights.filter(user=info.context.user) + class RecentModuleNode(DjangoObjectType): class Meta: diff --git a/server/notes/inputs.py b/server/notes/inputs.py index d1f1c72c..17d707af 100644 --- a/server/notes/inputs.py +++ b/server/notes/inputs.py @@ -17,10 +17,13 @@ class UpdateNoteArgument(InputObjectType): class AddHighlightArgument(InputObjectType): page = graphene.String(required=True) - content_index = graphene.Int(required=True) - content_uuid = graphene.UUID(required=True) paragraph_index = graphene.Int(required=True) text = graphene.String(required=True) start_position = graphene.Int(required=True) selection_length = graphene.Int(required=True) color = graphene.String(required=True) + + +class AddContentHighlightArgument(AddHighlightArgument): + content_index = graphene.Int(required=True) + content_uuid = graphene.UUID(required=True) diff --git a/server/notes/migrations/0009_alter_highlight_content_index_and_more.py b/server/notes/migrations/0009_alter_highlight_content_index_and_more.py new file mode 100644 index 00000000..402e6736 --- /dev/null +++ b/server/notes/migrations/0009_alter_highlight_content_index_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.8 on 2024-02-21 14:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("notes", "0008_rename_content_block_highlight_page"), + ] + + operations = [ + migrations.AlterField( + model_name="highlight", + name="content_index", + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name="highlight", + name="content_uuid", + field=models.UUIDField(null=True), + ), + ] diff --git a/server/notes/models.py b/server/notes/models.py index 1a2e9825..a75309ee 100644 --- a/server/notes/models.py +++ b/server/notes/models.py @@ -57,8 +57,8 @@ class Highlight(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) page = models.ForeignKey(Page, on_delete=models.CASCADE, related_name="highlights") # see highlight.ts for comments - content_index = models.IntegerField() - content_uuid = models.UUIDField() + content_index = models.IntegerField(null=True) + content_uuid = models.UUIDField(null=True) paragraph_index = models.IntegerField() start_position = models.IntegerField() selection_length = models.IntegerField() diff --git a/server/notes/mutations.py b/server/notes/mutations.py index 8dc75134..b226251d 100644 --- a/server/notes/mutations.py +++ b/server/notes/mutations.py @@ -8,7 +8,13 @@ from books.models import Chapter, ContentBlock, Module from django.db import IntegrityError from graphene import relay from graphql_relay import from_global_id -from notes.inputs import AddHighlightArgument, AddNoteArgument, UpdateNoteArgument +from core.logger import get_logger +from notes.inputs import ( + AddContentHighlightArgument, + AddHighlightArgument, + AddNoteArgument, + UpdateNoteArgument, +) from notes.models import ( ChapterBookmark, ContentBlockBookmark, @@ -19,6 +25,8 @@ from notes.models import ( ) from notes.schema import HighlightNode, NoteNode +logger = get_logger(__name__) + class UpdateContentBookmark(relay.ClientIDMutation): class Input: @@ -285,6 +293,53 @@ class AddHighlight(relay.ClientIDMutation): if highlight is None: raise Exception("No highlight provided, should not happen") + page_id = highlight.get("page") + paragraph_index = highlight.get("paragraph_index") + text = highlight.get("text") + start_position = highlight.get("start_position") + selection_length = highlight.get("selection_length") + color = highlight.get("color") + + page_type, page_id = from_global_id(page_id) + if page_type == "ModuleNode": + page = Module.objects.get(id=page_id) + elif page_type == "ChapterNode": + page = Chapter.objects.get(id=page_id) + else: + raise Exception("wrong type") + + logger.debug(page) + new_highlight = Highlight.objects.create( + page=page, + user=user, + paragraph_index=paragraph_index, + text=text, + start_position=start_position, + selection_length=selection_length, + color=color, + ) + logger.debug(new_highlight) + logger.debug(new_highlight.page) + + return cls(highlight=new_highlight) + + +class AddContentHighlight(relay.ClientIDMutation): + class Input: + highlight = graphene.Argument(AddContentHighlightArgument) + + highlight = graphene.Field(HighlightNode) + + @classmethod + def mutate_and_get_payload(cls, root, info, **kwargs): + user = info.context.user + + highlight = kwargs.get("highlight") + + if highlight is None: + raise Exception("No highlight provided, should not happen") + + logger.debug(highlight) page_id = highlight.get("page") content_index = highlight.get("content_index") content_uuid = highlight.get("content_uuid") @@ -320,6 +375,7 @@ class AddHighlight(relay.ClientIDMutation): class NoteMutations: add_note = AddNote.Field() add_highlight = AddHighlight.Field() + add_content_highlight = AddContentHighlight.Field() delete_highlight = DeleteHighlight.Field() update_highlight = UpdateHighlight.Field() update_note = UpdateNote.Field() diff --git a/server/notes/schema.py b/server/notes/schema.py index 01ff11b4..ad0606f8 100644 --- a/server/notes/schema.py +++ b/server/notes/schema.py @@ -1,8 +1,10 @@ import graphene from basicknowledge.queries import InstrumentNode -from books.schema.nodes.content import ContentBlockNode +from books.schema.nodes import ContentBlockNode, ModuleNode from graphene import relay from graphene_django import DjangoObjectType +from books.schema.nodes.chapter import ChapterNode +from core.logger import get_logger from notes.models import ( ChapterBookmark, ContentBlockBookmark, @@ -12,6 +14,8 @@ from notes.models import ( Note, ) +logger = get_logger(__name__) + class NoteNode(DjangoObjectType): pk = graphene.Int() @@ -67,7 +71,7 @@ class InstrumentBookmarkNode(DjangoObjectType): class HighlightableNode(graphene.Union): class Meta: - types = (ContentBlockNode, InstrumentNode) + types = (ContentBlockNode, InstrumentNode, ModuleNode, ChapterNode) class HighlightNode(DjangoObjectType): diff --git a/server/schema.graphql b/server/schema.graphql index b6b4cd0e..a4acb3b2 100644 --- a/server/schema.graphql +++ b/server/schema.graphql @@ -128,6 +128,7 @@ type ModuleNode implements ModuleInterface { myChapterBookmarks(offset: Int, before: String, after: String, first: Int, last: Int): ChapterBookmarkNodeConnection snapshots: [SnapshotNode] language: String + highlights: [HighlightNode] } interface ModuleInterface { @@ -624,8 +625,8 @@ type HighlightNode implements Node { id: ID! user: PrivateUserNode! page: HighlightableNode - contentIndex: Int! - contentUuid: UUID! + contentIndex: Int + contentUuid: UUID paragraphIndex: Int! startPosition: Int! selectionLength: Int! @@ -634,7 +635,7 @@ type HighlightNode implements Node { color: String! } -union HighlightableNode = ContentBlockNode | InstrumentNode +union HighlightableNode = ContentBlockNode | InstrumentNode | ModuleNode | ChapterNode type SnapshotObjectiveGroupNode implements Node { """The ID of the object""" @@ -1041,6 +1042,7 @@ type Mutation { spellCheck(input: SpellCheckInput!): SpellCheckPayload addNote(input: AddNoteInput!): AddNotePayload addHighlight(input: AddHighlightInput!): AddHighlightPayload + addContentHighlight(input: AddContentHighlightInput!): AddContentHighlightPayload deleteHighlight(input: DeleteHighlightInput!): DeleteHighlightPayload updateHighlight(input: UpdateHighlightInput!): UpdateHighlightPayload updateNote(input: UpdateNoteInput!): UpdateNotePayload @@ -1154,8 +1156,6 @@ input AddHighlightInput { input AddHighlightArgument { page: String! - contentIndex: Int! - contentUuid: UUID! paragraphIndex: Int! text: String! startPosition: Int! @@ -1163,6 +1163,27 @@ input AddHighlightArgument { color: String! } +type AddContentHighlightPayload { + highlight: HighlightNode + clientMutationId: String +} + +input AddContentHighlightInput { + highlight: AddContentHighlightArgument + clientMutationId: String +} + +input AddContentHighlightArgument { + page: String! + paragraphIndex: Int! + text: String! + startPosition: Int! + selectionLength: Int! + color: String! + contentIndex: Int! + contentUuid: UUID! +} + type DeleteHighlightPayload { success: Boolean! clientMutationId: String