diff options
author | Luke Duncalfe <lduncalfe@eml.cc> | 2019-07-04 15:33:14 +1200 |
---|---|---|
committer | Luke Duncalfe <lduncalfe@eml.cc> | 2019-07-10 12:13:48 +1200 |
commit | 073c8b25ea36b6b96eab05eb675e8726b1d5318e (patch) | |
tree | 5f83a17cf6e461106d8ddf8f1b84f743a09547d6 /app | |
parent | 254f78f5dc36d4aef26d1ab2a924e4fa916221c6 (diff) | |
download | gitlab-ce-073c8b25ea36b6b96eab05eb675e8726b1d5318e.tar.gz |
GraphQL support for Notes created in discussions62826-graphql-note-mutations
A new `discussion_id` argument on the `createNote` mutation allows
people to create a note within that discussion.
The ability to lazy-load Discussions has been added, so
GraphQL.object_from_id can treat Discussions the same as AR objects and
batch load them.
https://gitlab.com/gitlab-org/gitlab-ce/issues/62826
https://gitlab.com/gitlab-org/gitlab-ee/issues/9489
Diffstat (limited to 'app')
-rw-r--r-- | app/graphql/gitlab_schema.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/notes/create/note.rb | 29 | ||||
-rw-r--r-- | app/graphql/types/notes/discussion_type.rb | 8 | ||||
-rw-r--r-- | app/models/discussion.rb | 11 | ||||
-rw-r--r-- | app/models/note.rb | 2 |
5 files changed, 52 insertions, 0 deletions
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb index 152ebb930e2..7edd14e48f7 100644 --- a/app/graphql/gitlab_schema.rb +++ b/app/graphql/gitlab_schema.rb @@ -66,6 +66,8 @@ class GitlabSchema < GraphQL::Schema if gid.model_class < ApplicationRecord Gitlab::Graphql::Loaders::BatchModelLoader.new(gid.model_class, gid.model_id).find + elsif gid.model_class.respond_to?(:lazy_find) + gid.model_class.lazy_find(gid.model_id) else gid.find end diff --git a/app/graphql/mutations/notes/create/note.rb b/app/graphql/mutations/notes/create/note.rb index 3c571a4538f..5236e48026e 100644 --- a/app/graphql/mutations/notes/create/note.rb +++ b/app/graphql/mutations/notes/create/note.rb @@ -5,6 +5,35 @@ module Mutations module Create class Note < Base graphql_name 'CreateNote' + + argument :discussion_id, + GraphQL::ID_TYPE, + required: false, + description: 'The global id of the discussion this note is in reply to' + + private + + def create_note_params(noteable, args) + discussion_id = nil + + if args[:discussion_id] + discussion = GitlabSchema.object_from_id(args[:discussion_id]) + authorize_discussion!(discussion) + + discussion_id = discussion.id + end + + super(noteable, args).merge({ + in_reply_to_discussion_id: discussion_id + }) + end + + def authorize_discussion!(discussion) + unless Ability.allowed?(current_user, :read_note, discussion, scope: :user) + raise Gitlab::Graphql::Errors::ResourceNotAvailable, + "The discussion does not exist or you don't have permission to perform this action" + end + end end end end diff --git a/app/graphql/types/notes/discussion_type.rb b/app/graphql/types/notes/discussion_type.rb index c4691942f2d..a3fb28298f6 100644 --- a/app/graphql/types/notes/discussion_type.rb +++ b/app/graphql/types/notes/discussion_type.rb @@ -8,8 +8,16 @@ module Types authorize :read_note field :id, GraphQL::ID_TYPE, null: false + field :reply_id, GraphQL::ID_TYPE, null: false, description: 'The ID used to reply to this discussion' field :created_at, Types::TimeType, null: false field :notes, Types::Notes::NoteType.connection_type, null: false, description: "All notes in the discussion" + + # The gem we use to generate Global IDs is hard-coded to work with + # `id` properties. To generate a GID for the `reply_id` property, + # we must use the ::Gitlab::GlobalId module. + def reply_id + ::Gitlab::GlobalId.build(object, id: object.reply_id) + end end end end diff --git a/app/models/discussion.rb b/app/models/discussion.rb index ae13cdfd85f..dd896f77084 100644 --- a/app/models/discussion.rb +++ b/app/models/discussion.rb @@ -38,6 +38,17 @@ class Discussion grouped_notes.values.map { |notes| build(notes, context_noteable) } end + def self.lazy_find(discussion_id) + BatchLoader.for(discussion_id).batch do |discussion_ids, loader| + results = Note.where(discussion_id: discussion_ids).fresh.to_a.group_by(&:discussion_id) + results.each do |discussion_id, notes| + next if notes.empty? + + loader.call(discussion_id, Discussion.build(notes)) + end + end + end + # Returns an alphanumeric discussion ID based on `build_discussion_id` def self.discussion_id(note) Digest::SHA1.hexdigest(build_discussion_id(note).join("-")) diff --git a/app/models/note.rb b/app/models/note.rb index 4e9ea146485..5c31cff9816 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -158,6 +158,8 @@ class Note < ApplicationRecord Discussion.build_collection(all.includes(:noteable).fresh, context_noteable) end + # Note: Where possible consider using Discussion#lazy_find to return + # Discussions in order to benefit from having records batch loaded. def find_discussion(discussion_id) notes = where(discussion_id: discussion_id).fresh.to_a |