Commit 520f7cd0 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'tc-api-remove-comments-endpoint' into 'master'

API: Make the /notes endpoint work with noteable iid instead of id

Closes #29871

See merge request !10258
parents 15ca592f add5cd99
---
title: 'API: Make the /notes endpoint work with noteable iid instead of id'
merge_request:
author:
...@@ -9,13 +9,13 @@ Notes are comments on snippets, issues or merge requests. ...@@ -9,13 +9,13 @@ Notes are comments on snippets, issues or merge requests.
Gets a list of all notes for a single issue. Gets a list of all notes for a single issue.
``` ```
GET /projects/:id/issues/:issue_id/notes GET /projects/:id/issues/:issue_iid/notes
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `issue_id` (required) - The ID of an issue - `issue_iid` (required) - The IID of an issue
```json ```json
[ [
...@@ -63,13 +63,13 @@ Parameters: ...@@ -63,13 +63,13 @@ Parameters:
Returns a single note for a specific project issue Returns a single note for a specific project issue
``` ```
GET /projects/:id/issues/:issue_id/notes/:note_id GET /projects/:id/issues/:issue_iid/notes/:note_id
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `issue_id` (required) - The ID of a project issue - `issue_iid` (required) - The IID of a project issue
- `note_id` (required) - The ID of an issue note - `note_id` (required) - The ID of an issue note
### Create new issue note ### Create new issue note
...@@ -78,13 +78,13 @@ Creates a new note to a single project issue. If you create a note where the bod ...@@ -78,13 +78,13 @@ Creates a new note to a single project issue. If you create a note where the bod
only contains an Award Emoji, you'll receive this object back. only contains an Award Emoji, you'll receive this object back.
``` ```
POST /projects/:id/issues/:issue_id/notes POST /projects/:id/issues/:issue_iid/notes
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `issue_id` (required) - The ID of an issue - `issue_id` (required) - The IID of an issue
- `body` (required) - The content of a note - `body` (required) - The content of a note
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z - `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
...@@ -93,13 +93,13 @@ Parameters: ...@@ -93,13 +93,13 @@ Parameters:
Modify existing note of an issue. Modify existing note of an issue.
``` ```
PUT /projects/:id/issues/:issue_id/notes/:note_id PUT /projects/:id/issues/:issue_iid/notes/:note_id
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `issue_id` (required) - The ID of an issue - `issue_iid` (required) - The IID of an issue
- `note_id` (required) - The ID of a note - `note_id` (required) - The ID of a note
- `body` (required) - The content of a note - `body` (required) - The content of a note
...@@ -108,7 +108,7 @@ Parameters: ...@@ -108,7 +108,7 @@ Parameters:
Deletes an existing note of an issue. Deletes an existing note of an issue.
``` ```
DELETE /projects/:id/issues/:issue_id/notes/:note_id DELETE /projects/:id/issues/:issue_iid/notes/:note_id
``` ```
Parameters: Parameters:
...@@ -116,7 +116,7 @@ Parameters: ...@@ -116,7 +116,7 @@ Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project | | `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The ID of an issue | | `issue_iid` | integer | yes | The IID of an issue |
| `note_id` | integer | yes | The ID of a note | | `note_id` | integer | yes | The ID of a note |
```bash ```bash
...@@ -228,26 +228,26 @@ curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://git ...@@ -228,26 +228,26 @@ curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://git
Gets a list of all notes for a single merge request. Gets a list of all notes for a single merge request.
``` ```
GET /projects/:id/merge_requests/:merge_request_id/notes GET /projects/:id/merge_requests/:merge_request_iid/notes
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of a project merge request - `merge_request_iid` (required) - The IID of a project merge request
### Get single merge request note ### Get single merge request note
Returns a single note for a given merge request. Returns a single note for a given merge request.
``` ```
GET /projects/:id/merge_requests/:merge_request_id/notes/:note_id GET /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of a project merge request - `merge_request_iid` (required) - The IID of a project merge request
- `note_id` (required) - The ID of a merge request note - `note_id` (required) - The ID of a merge request note
```json ```json
...@@ -278,13 +278,13 @@ If you create a note where the body only contains an Award Emoji, you'll receive ...@@ -278,13 +278,13 @@ If you create a note where the body only contains an Award Emoji, you'll receive
this object back. this object back.
``` ```
POST /projects/:id/merge_requests/:merge_request_id/notes POST /projects/:id/merge_requests/:merge_request_iid/notes
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of a merge request - `merge_request_iid` (required) - The IID of a merge request
- `body` (required) - The content of a note - `body` (required) - The content of a note
### Modify existing merge request note ### Modify existing merge request note
...@@ -292,13 +292,13 @@ Parameters: ...@@ -292,13 +292,13 @@ Parameters:
Modify existing note of a merge request. Modify existing note of a merge request.
``` ```
PUT /projects/:id/merge_requests/:merge_request_id/notes/:note_id PUT /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
``` ```
Parameters: Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `merge_request_id` (required) - The ID of a merge request - `merge_request_iid` (required) - The IID of a merge request
- `note_id` (required) - The ID of a note - `note_id` (required) - The ID of a note
- `body` (required) - The content of a note - `body` (required) - The content of a note
...@@ -307,7 +307,7 @@ Parameters: ...@@ -307,7 +307,7 @@ Parameters:
Deletes an existing note of a merge request. Deletes an existing note of a merge request.
``` ```
DELETE /projects/:id/merge_requests/:merge_request_id/notes/:note_id DELETE /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
``` ```
Parameters: Parameters:
...@@ -315,7 +315,7 @@ Parameters: ...@@ -315,7 +315,7 @@ Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project | | `id` | integer | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of a merge request | | `merge_request_iid` | integer | yes | The IID of a merge request |
| `note_id` | integer | yes | The ID of a note | | `note_id` | integer | yes | The ID of a note |
```bash ```bash
......
...@@ -90,6 +90,11 @@ module API ...@@ -90,6 +90,11 @@ module API
MergeRequestsFinder.new(current_user, project_id: user_project.id).find_by!(iid: iid) MergeRequestsFinder.new(current_user, project_id: user_project.id).find_by!(iid: iid)
end end
def find_project_snippet(id)
finder_params = { filter: :by_project, project: user_project }
SnippetsFinder.new.execute(current_user, finder_params).find(id)
end
def find_merge_request_with_access(iid, access_level = :read_merge_request) def find_merge_request_with_access(iid, access_level = :read_merge_request)
merge_request = user_project.merge_requests.find_by!(iid: iid) merge_request = user_project.merge_requests.find_by!(iid: iid)
authorize! access_level, merge_request authorize! access_level, merge_request
......
...@@ -226,41 +226,6 @@ module API ...@@ -226,41 +226,6 @@ module API
.cancel(merge_request) .cancel(merge_request)
end end
desc 'Get the comments of a merge request' do
success Entities::MRNote
end
params do
use :pagination
end
get ':id/merge_requests/:merge_request_iid/comments' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
present paginate(merge_request.notes.fresh), with: Entities::MRNote
end
desc 'Post a comment to a merge request' do
success Entities::MRNote
end
params do
requires :note, type: String, desc: 'The text of the comment'
end
post ':id/merge_requests/:merge_request_iid/comments' do
merge_request = find_merge_request_with_access(params[:merge_request_iid], :create_note)
opts = {
note: params[:note],
noteable_type: 'MergeRequest',
noteable_id: merge_request.id
}
note = ::Notes::CreateService.new(user_project, current_user, opts).execute
if note.save
present note, with: Entities::MRNote
else
render_api_error!("Failed to save note #{note.errors.messages}", 400)
end
end
desc 'List issues that will be closed on merge' do desc 'List issues that will be closed on merge' do
success Entities::MRNote success Entities::MRNote
end end
......
...@@ -21,7 +21,7 @@ module API ...@@ -21,7 +21,7 @@ module API
use :pagination use :pagination
end end
get ":id/#{noteables_str}/:noteable_id/notes" do get ":id/#{noteables_str}/:noteable_id/notes" do
noteable = user_project.send(noteables_str.to_sym).find(params[:noteable_id]) noteable = find_project_noteable(noteables_str, params[:noteable_id])
if can?(current_user, noteable_read_ability_name(noteable), noteable) if can?(current_user, noteable_read_ability_name(noteable), noteable)
# We exclude notes that are cross-references and that cannot be viewed # We exclude notes that are cross-references and that cannot be viewed
...@@ -49,7 +49,7 @@ module API ...@@ -49,7 +49,7 @@ module API
requires :noteable_id, type: Integer, desc: 'The ID of the noteable' requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
end end
get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
noteable = user_project.send(noteables_str.to_sym).find(params[:noteable_id]) noteable = find_project_noteable(noteables_str, params[:noteable_id])
note = noteable.notes.find(params[:note_id]) note = noteable.notes.find(params[:note_id])
can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user) can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user)
...@@ -69,14 +69,14 @@ module API ...@@ -69,14 +69,14 @@ module API
optional :created_at, type: String, desc: 'The creation date of the note' optional :created_at, type: String, desc: 'The creation date of the note'
end end
post ":id/#{noteables_str}/:noteable_id/notes" do post ":id/#{noteables_str}/:noteable_id/notes" do
noteable = find_project_noteable(noteables_str, params[:noteable_id])
opts = { opts = {
note: params[:body], note: params[:body],
noteable_type: noteables_str.classify, noteable_type: noteables_str.classify,
noteable_id: params[:noteable_id] noteable_id: noteable.id
} }
noteable = user_project.send(noteables_str.to_sym).find(params[:noteable_id])
if can?(current_user, noteable_read_ability_name(noteable), noteable) if can?(current_user, noteable_read_ability_name(noteable), noteable)
if params[:created_at] && (current_user.is_admin? || user_project.owner == current_user) if params[:created_at] && (current_user.is_admin? || user_project.owner == current_user)
opts[:created_at] = params[:created_at] opts[:created_at] = params[:created_at]
...@@ -137,6 +137,10 @@ module API ...@@ -137,6 +137,10 @@ module API
end end
helpers do helpers do
def find_project_noteable(noteables_str, noteable_id)
public_send("find_project_#{noteables_str.singularize}", noteable_id)
end
def noteable_read_ability_name(noteable) def noteable_read_ability_name(noteable)
"read_#{noteable.class.to_s.underscore}".to_sym "read_#{noteable.class.to_s.underscore}".to_sym
end end
......
...@@ -623,64 +623,6 @@ describe API::MergeRequests, api: true do ...@@ -623,64 +623,6 @@ describe API::MergeRequests, api: true do
end end
end end
describe "POST /projects/:id/merge_requests/:merge_request_iid/comments" do
it "returns comment" do
original_count = merge_request.notes.size
post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/comments", user), note: "My comment"
expect(response).to have_http_status(201)
expect(json_response['note']).to eq('My comment')
expect(json_response['author']['name']).to eq(user.name)
expect(json_response['author']['username']).to eq(user.username)
expect(merge_request.reload.notes.size).to eq(original_count + 1)
end
it "returns 400 if note is missing" do
post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/comments", user)
expect(response).to have_http_status(400)
end
it "returns 404 if merge request iid is invalid" do
post api("/projects/#{project.id}/merge_requests/404/comments", user),
note: 'My comment'
expect(response).to have_http_status(404)
end
it "returns 404 if merge request id is used instead of iid" do
post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user),
note: 'My comment'
expect(response).to have_http_status(404)
end
end
describe "GET :id/merge_requests/:merge_request_iid/comments" do
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
it "returns merge_request comments ordered by created_at" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/comments", user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
expect(json_response.first['note']).to eq("a comment on a MR")
expect(json_response.first['author']['id']).to eq(user.id)
expect(json_response.last['note']).to eq("another comment on a MR")
end
it "returns a 404 error if merge_request_iid is invalid" do
get api("/projects/#{project.id}/merge_requests/999/comments", user)
expect(response).to have_http_status(404)
end
it "returns a 404 error if merge_request id is used instead of iid" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user)
expect(response).to have_http_status(404)
end
end
describe 'GET :id/merge_requests/:merge_request_iid/closes_issues' do describe 'GET :id/merge_requests/:merge_request_iid/closes_issues' do
it 'returns the issue that will be closed on merge' do it 'returns the issue that will be closed on merge' do
issue = create(:issue, project: project) issue = create(:issue, project: project)
......
This diff is collapsed.
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