Commit 034c6496 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '28807-search-for-milestone-by-title-in-rest-api' into 'master'

Enable filtering milestones by search criteria in the API

Closes #28807

See merge request !9606
parents d4154195 61baf352
---
title: Enable filtering milestones by search criteria in the API
merge_request: 9606
author:
...@@ -10,6 +10,7 @@ GET /projects/:id/milestones?iid=42 ...@@ -10,6 +10,7 @@ GET /projects/:id/milestones?iid=42
GET /projects/:id/milestones?iid[]=42&iid[]=43 GET /projects/:id/milestones?iid[]=42&iid[]=43
GET /projects/:id/milestones?state=active GET /projects/:id/milestones?state=active
GET /projects/:id/milestones?state=closed GET /projects/:id/milestones?state=closed
GET /projects/:id/milestones?search=version
``` ```
Parameters: Parameters:
...@@ -19,6 +20,7 @@ Parameters: ...@@ -19,6 +20,7 @@ Parameters:
| `id` | integer | yes | The ID of a project | | `id` | integer | yes | The ID of a project |
| `iid` | Array[integer] | optional | Return only the milestone having the given `iid` | | `iid` | Array[integer] | optional | Return only the milestone having the given `iid` |
| `state` | string | optional | Return only `active` or `closed` milestones` | | `state` | string | optional | Return only `active` or `closed` milestones` |
| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash ```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/milestones curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/milestones
......
...@@ -164,6 +164,10 @@ module API ...@@ -164,6 +164,10 @@ module API
items.where(iid: iid) items.where(iid: iid)
end end
def filter_by_search(items, text)
items.search(text)
end
# error helpers # error helpers
def forbidden!(reason = nil) def forbidden!(reason = nil)
......
...@@ -31,6 +31,7 @@ module API ...@@ -31,6 +31,7 @@ module API
optional :state, type: String, values: %w[active closed all], default: 'all', optional :state, type: String, values: %w[active closed all], default: 'all',
desc: 'Return "active", "closed", or "all" milestones' desc: 'Return "active", "closed", or "all" milestones'
optional :iid, type: Array[Integer], desc: 'The IID of the milestone' optional :iid, type: Array[Integer], desc: 'The IID of the milestone'
optional :search, type: String, desc: 'The search criteria for the title or description of the milestone'
use :pagination use :pagination
end end
get ":id/milestones" do get ":id/milestones" do
...@@ -39,6 +40,7 @@ module API ...@@ -39,6 +40,7 @@ module API
milestones = user_project.milestones milestones = user_project.milestones
milestones = filter_milestones_state(milestones, params[:state]) milestones = filter_milestones_state(milestones, params[:state])
milestones = filter_by_iid(milestones, params[:iid]) if params[:iid].present? milestones = filter_by_iid(milestones, params[:iid]) if params[:iid].present?
milestones = filter_by_search(milestones, params[:search]) if params[:search]
present paginate(milestones), with: Entities::Milestone present paginate(milestones), with: Entities::Milestone
end end
......
...@@ -4,8 +4,8 @@ describe API::Milestones, api: true do ...@@ -4,8 +4,8 @@ describe API::Milestones, api: true do
include ApiHelpers include ApiHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let!(:project) { create(:empty_project, namespace: user.namespace ) } let!(:project) { create(:empty_project, namespace: user.namespace ) }
let!(:closed_milestone) { create(:closed_milestone, project: project) } let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
let!(:milestone) { create(:milestone, project: project) } let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') }
before { project.team << [user, :developer] } before { project.team << [user, :developer] }
...@@ -60,17 +60,28 @@ describe API::Milestones, api: true do ...@@ -60,17 +60,28 @@ describe API::Milestones, api: true do
get api("/projects/#{project.id}/milestones", user), iid: [milestone.iid, closed_milestone.iid] get api("/projects/#{project.id}/milestones", user), iid: [milestone.iid, closed_milestone.iid]
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.size).to eq(2) expect(json_response.size).to eq(2)
expect(json_response.first['title']).to eq milestone.title expect(json_response.first['title']).to eq milestone.title
expect(json_response.first['id']).to eq milestone.id expect(json_response.first['id']).to eq milestone.id
end end
it 'returns a project milestone by iid array' do it 'returns a project milestone by searching for title' do
get api("/projects/#{project.id}/milestones", user), iid: [milestone.iid, closed_milestone.iid] get api("/projects/#{project.id}/milestones", user), search: 'version2'
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response.size).to eq(2) expect(json_response.size).to eq(1)
expect(json_response.first['title']).to eq milestone.title
expect(json_response.first['id']).to eq milestone.id
end
it 'returns a project milestones by searching for description' do
get api("/projects/#{project.id}/milestones", user), search: 'open'
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.size).to eq(1)
expect(json_response.first['title']).to eq milestone.title expect(json_response.first['title']).to eq milestone.title
expect(json_response.first['id']).to eq milestone.id expect(json_response.first['id']).to eq milestone.id
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