Add full JSON endpoints for issue notes and discussions
This commit is contained in:
parent
cb2287df0a
commit
76c3d2d434
15 changed files with 149 additions and 24 deletions
|
@ -11,14 +11,16 @@ module NotesActions
|
|||
|
||||
notes_json = { notes: [], last_fetched_at: current_fetched_at }
|
||||
|
||||
@notes = notes_finder.execute.inc_relations_for_view
|
||||
@notes = notes_finder.execute.inc_relations_for_view.to_a
|
||||
@notes.reject! { |n| n.cross_reference_not_visible_for?(current_user) }
|
||||
@notes = prepare_notes_for_rendering(@notes)
|
||||
|
||||
@notes.each do |note|
|
||||
next if note.cross_reference_not_visible_for?(current_user)
|
||||
|
||||
notes_json[:notes] << note_json(note)
|
||||
end
|
||||
notes_json[:notes] =
|
||||
if params[:full_data]
|
||||
note_serializer.represent(@notes)
|
||||
else
|
||||
@notes.map { |note| note_json(note) }
|
||||
end
|
||||
|
||||
render json: notes_json
|
||||
end
|
||||
|
@ -80,22 +82,27 @@ module NotesActions
|
|||
}
|
||||
|
||||
if note.persisted?
|
||||
attrs.merge!(
|
||||
valid: true,
|
||||
id: note.id,
|
||||
discussion_id: note.discussion_id(noteable),
|
||||
html: note_html(note),
|
||||
note: note.note
|
||||
)
|
||||
attrs[:valid] = true
|
||||
|
||||
discussion = note.to_discussion(noteable)
|
||||
unless discussion.individual_note?
|
||||
if params[:full_data]
|
||||
attrs.merge!(note_serializer.represent(note))
|
||||
else
|
||||
attrs.merge!(
|
||||
discussion_resolvable: discussion.resolvable?,
|
||||
|
||||
diff_discussion_html: diff_discussion_html(discussion),
|
||||
discussion_html: discussion_html(discussion)
|
||||
id: note.id,
|
||||
discussion_id: note.discussion_id(noteable),
|
||||
html: note_html(note),
|
||||
note: note.note
|
||||
)
|
||||
|
||||
discussion = note.to_discussion(noteable)
|
||||
unless discussion.individual_note?
|
||||
attrs.merge!(
|
||||
discussion_resolvable: discussion.resolvable?,
|
||||
|
||||
diff_discussion_html: diff_discussion_html(discussion),
|
||||
discussion_html: discussion_html(discussion)
|
||||
)
|
||||
end
|
||||
end
|
||||
else
|
||||
attrs.merge!(
|
||||
|
@ -177,4 +184,8 @@ module NotesActions
|
|||
def notes_finder
|
||||
@notes_finder ||= NotesFinder.new(project, current_user, finder_params)
|
||||
end
|
||||
|
||||
def note_serializer
|
||||
NoteSerializer.new(project: project, noteable: noteable, current_user: current_user)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -97,6 +97,14 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def discussions
|
||||
@discussions = @issue.discussions
|
||||
@discussions.reject! { |d| d.individual_note? && d.first_note.cross_reference_not_visible_for?(current_user) }
|
||||
prepare_notes_for_rendering(@discussions.flat_map(&:notes))
|
||||
|
||||
render json: DiscussionSerializer.new(project: @project, noteable: @issue, current_user: current_user).represent(@discussions)
|
||||
end
|
||||
|
||||
def create
|
||||
create_params = issue_params.merge(spammable_params).merge(
|
||||
merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
|
||||
|
|
|
@ -119,7 +119,7 @@ module IssuesHelper
|
|||
end
|
||||
|
||||
def awards_sort(awards)
|
||||
awards.sort_by do |award, notes|
|
||||
awards.sort_by do |award, award_emojis|
|
||||
if award == "thumbsup"
|
||||
0
|
||||
elsif award == "thumbsdown"
|
||||
|
|
|
@ -21,8 +21,14 @@ module SystemNoteHelper
|
|||
'outdated' => 'icon_edit'
|
||||
}.freeze
|
||||
|
||||
def system_note_icon_name(note)
|
||||
ICON_NAMES_BY_ACTION[note.system_note_metadata&.action]
|
||||
end
|
||||
|
||||
def icon_for_system_note(note)
|
||||
icon_name = ICON_NAMES_BY_ACTION[note.system_note_metadata&.action]
|
||||
icon_name = system_note_icon_name(note)
|
||||
custom_icon(icon_name) if icon_name
|
||||
end
|
||||
|
||||
extend self
|
||||
end
|
||||
|
|
|
@ -81,6 +81,10 @@ class Discussion
|
|||
last_note.author
|
||||
end
|
||||
|
||||
def updated?
|
||||
last_updated_at != created_at
|
||||
end
|
||||
|
||||
def id
|
||||
first_note.discussion_id(context_noteable)
|
||||
end
|
||||
|
|
4
app/serializers/award_emoji_entity.rb
Normal file
4
app/serializers/award_emoji_entity.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class AwardEmojiEntity < Grape::Entity
|
||||
expose :name
|
||||
expose :user, using: API::Entities::UserSafe
|
||||
end
|
20
app/serializers/discussion_entity.rb
Normal file
20
app/serializers/discussion_entity.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
class DiscussionEntity < Grape::Entity
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :id, :reply_id
|
||||
expose :expanded?, as: :expanded
|
||||
expose :author, using: UserEntity
|
||||
|
||||
expose :created_at
|
||||
|
||||
expose :last_updated_at, if: -> (discussion, _) { discussion.updated? }
|
||||
expose :last_updated_by, if: -> (discussion, _) { discussion.updated? }, using: UserEntity
|
||||
|
||||
expose :notes, using: NoteEntity
|
||||
|
||||
expose :individual_note?, as: :individual_note
|
||||
|
||||
expose :can_reply do |discussion|
|
||||
can?(request.current_user, :create_note, discussion.project)
|
||||
end
|
||||
end
|
3
app/serializers/discussion_serializer.rb
Normal file
3
app/serializers/discussion_serializer.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class DiscussionSerializer < BaseSerializer
|
||||
entity DiscussionEntity
|
||||
end
|
5
app/serializers/note_attachment_entity.rb
Normal file
5
app/serializers/note_attachment_entity.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class NoteAttachmentEntity < Grape::Entity
|
||||
expose :url
|
||||
expose :filename
|
||||
expose :image?, as: :image
|
||||
end
|
58
app/serializers/note_entity.rb
Normal file
58
app/serializers/note_entity.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
class NoteEntity < API::Entities::Note
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :type
|
||||
|
||||
expose :author, using: UserEntity
|
||||
|
||||
expose :human_access do |note|
|
||||
note.project.team.human_max_access(note.author_id)
|
||||
end
|
||||
|
||||
unexpose :note, as: :body
|
||||
expose :note
|
||||
|
||||
expose :redacted_note_html, as: :note_html
|
||||
|
||||
expose :last_edited_at, if: -> (note, _) { note.is_edited? }
|
||||
expose :last_edited_by, using: UserEntity, if: -> (note, _) { note.is_edited? }
|
||||
|
||||
expose :can_edit do |note|
|
||||
Ability.can_edit_note?(request.current_user, note)
|
||||
end
|
||||
|
||||
expose :system_note_icon_name, if: -> (note, _) { note.system? } do |note|
|
||||
SystemNoteHelper.system_note_icon_name(note)
|
||||
end
|
||||
|
||||
expose :discussion_id do |note|
|
||||
note.discussion_id(request.noteable)
|
||||
end
|
||||
|
||||
expose :emoji_awardable?, as: :emoji_awardable
|
||||
expose :award_emoji, if: -> (note, _) { note.emoji_awardable? }, using: AwardEmojiEntity
|
||||
expose :toggle_award_path, if: -> (note, _) { note.emoji_awardable? } do |note|
|
||||
if note.for_personal_snippet?
|
||||
toggle_award_emoji_snippet_note_path(note.noteable, note)
|
||||
else
|
||||
toggle_award_emoji_namespace_project_note_path(note.project.namespace, note.project, note.id)
|
||||
end
|
||||
end
|
||||
|
||||
expose :report_abuse_path do |note|
|
||||
new_abuse_report_path(user_id: note.author.id, ref_url: Gitlab::UrlBuilder.build(note))
|
||||
end
|
||||
|
||||
expose :path do |note|
|
||||
if note.for_personal_snippet?
|
||||
snippet_note_path(note.noteable, note)
|
||||
else
|
||||
namespace_project_note_path(note.project.namespace, note.project, note)
|
||||
end
|
||||
end
|
||||
|
||||
expose :attachment, using: NoteAttachmentEntity
|
||||
expose :delete_attachment_path, if: -> (note, _) { note.attachment? } do |note|
|
||||
delete_attachment_namespace_project_note_path(note.project.namespace, note.project, note)
|
||||
end
|
||||
end
|
3
app/serializers/note_serializer.rb
Normal file
3
app/serializers/note_serializer.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class NoteSerializer < BaseSerializer
|
||||
entity NoteEntity
|
||||
end
|
|
@ -1,6 +1,8 @@
|
|||
class UserEntity < API::Entities::UserBasic
|
||||
include RequestAwareEntity
|
||||
|
||||
unexpose :web_url
|
||||
|
||||
expose :path do |user|
|
||||
user_path(user)
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
by
|
||||
= link_to_member(@project, discussion.resolved_by, avatar: false)
|
||||
= time_ago_with_tooltip(discussion.resolved_at, placement: "bottom")
|
||||
- elsif discussion.last_updated_at != discussion.created_at
|
||||
- elsif discussion.updated?
|
||||
.discussion-headline-light.js-discussion-headline
|
||||
Last updated
|
||||
- if discussion.last_updated_by
|
||||
|
|
|
@ -308,6 +308,7 @@ constraints(ProjectUrlConstrainer.new) do
|
|||
get :can_create_branch
|
||||
get :realtime_changes
|
||||
post :create_merge_request
|
||||
get :discussions, format: :json
|
||||
end
|
||||
collection do
|
||||
post :bulk_update
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module API
|
||||
module Entities
|
||||
class UserSafe < Grape::Entity
|
||||
expose :name, :username
|
||||
expose :id, :name, :username
|
||||
end
|
||||
|
||||
class UserBasic < UserSafe
|
||||
expose :id, :state
|
||||
expose :state
|
||||
expose :avatar_url do |user, options|
|
||||
user.avatar_url(only_path: false)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue