Commit 76c3d2d4 authored by Douwe Maan's avatar Douwe Maan Committed by Fatih Acet

Add full JSON endpoints for issue notes and discussions

parent cb2287df
...@@ -11,14 +11,16 @@ module NotesActions ...@@ -11,14 +11,16 @@ module NotesActions
notes_json = { notes: [], last_fetched_at: current_fetched_at } 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 = prepare_notes_for_rendering(@notes)
@notes.each do |note| notes_json[:notes] =
next if note.cross_reference_not_visible_for?(current_user) if params[:full_data]
note_serializer.represent(@notes)
notes_json[:notes] << note_json(note) else
end @notes.map { |note| note_json(note) }
end
render json: notes_json render json: notes_json
end end
...@@ -80,22 +82,27 @@ module NotesActions ...@@ -80,22 +82,27 @@ module NotesActions
} }
if note.persisted? if note.persisted?
attrs.merge!( attrs[:valid] = true
valid: true,
id: note.id,
discussion_id: note.discussion_id(noteable),
html: note_html(note),
note: note.note
)
discussion = note.to_discussion(noteable) if params[:full_data]
unless discussion.individual_note? attrs.merge!(note_serializer.represent(note))
else
attrs.merge!( attrs.merge!(
discussion_resolvable: discussion.resolvable?, id: note.id,
discussion_id: note.discussion_id(noteable),
diff_discussion_html: diff_discussion_html(discussion), html: note_html(note),
discussion_html: discussion_html(discussion) 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 end
else else
attrs.merge!( attrs.merge!(
...@@ -177,4 +184,8 @@ module NotesActions ...@@ -177,4 +184,8 @@ module NotesActions
def notes_finder def notes_finder
@notes_finder ||= NotesFinder.new(project, current_user, finder_params) @notes_finder ||= NotesFinder.new(project, current_user, finder_params)
end end
def note_serializer
NoteSerializer.new(project: project, noteable: noteable, current_user: current_user)
end
end end
...@@ -97,6 +97,14 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -97,6 +97,14 @@ class Projects::IssuesController < Projects::ApplicationController
end end
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 def create
create_params = issue_params.merge(spammable_params).merge( create_params = issue_params.merge(spammable_params).merge(
merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of], merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
......
...@@ -119,7 +119,7 @@ module IssuesHelper ...@@ -119,7 +119,7 @@ module IssuesHelper
end end
def awards_sort(awards) def awards_sort(awards)
awards.sort_by do |award, notes| awards.sort_by do |award, award_emojis|
if award == "thumbsup" if award == "thumbsup"
0 0
elsif award == "thumbsdown" elsif award == "thumbsdown"
......
...@@ -21,8 +21,14 @@ module SystemNoteHelper ...@@ -21,8 +21,14 @@ module SystemNoteHelper
'outdated' => 'icon_edit' 'outdated' => 'icon_edit'
}.freeze }.freeze
def system_note_icon_name(note)
ICON_NAMES_BY_ACTION[note.system_note_metadata&.action]
end
def icon_for_system_note(note) 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 custom_icon(icon_name) if icon_name
end end
extend self
end end
...@@ -81,6 +81,10 @@ class Discussion ...@@ -81,6 +81,10 @@ class Discussion
last_note.author last_note.author
end end
def updated?
last_updated_at != created_at
end
def id def id
first_note.discussion_id(context_noteable) first_note.discussion_id(context_noteable)
end end
......
class AwardEmojiEntity < Grape::Entity
expose :name
expose :user, using: API::Entities::UserSafe
end
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
class DiscussionSerializer < BaseSerializer
entity DiscussionEntity
end
class NoteAttachmentEntity < Grape::Entity
expose :url
expose :filename
expose :image?, as: :image
end
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
class NoteSerializer < BaseSerializer
entity NoteEntity
end
class UserEntity < API::Entities::UserBasic class UserEntity < API::Entities::UserBasic
include RequestAwareEntity include RequestAwareEntity
unexpose :web_url
expose :path do |user| expose :path do |user|
user_path(user) user_path(user)
end end
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
by by
= link_to_member(@project, discussion.resolved_by, avatar: false) = link_to_member(@project, discussion.resolved_by, avatar: false)
= time_ago_with_tooltip(discussion.resolved_at, placement: "bottom") = 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 .discussion-headline-light.js-discussion-headline
Last updated Last updated
- if discussion.last_updated_by - if discussion.last_updated_by
......
...@@ -308,6 +308,7 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -308,6 +308,7 @@ constraints(ProjectUrlConstrainer.new) do
get :can_create_branch get :can_create_branch
get :realtime_changes get :realtime_changes
post :create_merge_request post :create_merge_request
get :discussions, format: :json
end end
collection do collection do
post :bulk_update post :bulk_update
......
module API module API
module Entities module Entities
class UserSafe < Grape::Entity class UserSafe < Grape::Entity
expose :name, :username expose :id, :name, :username
end end
class UserBasic < UserSafe class UserBasic < UserSafe
expose :id, :state expose :state
expose :avatar_url do |user, options| expose :avatar_url do |user, options|
user.avatar_url(only_path: false) user.avatar_url(only_path: false)
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment