Skip to content
代码片段 群组 项目
提交 cecdc701 编辑于 作者: Jonas Wälter's avatar Jonas Wälter 提交者: Tiger Watson
浏览文件

Add `without_projects` parameter to Topics API

Changelog: added
上级 e1c0634c
No related branches found
No related tags found
无相关合并请求
...@@ -13,6 +13,7 @@ def initialize(params: {}) ...@@ -13,6 +13,7 @@ def initialize(params: {})
def execute def execute
topics = Projects::Topic.order_by_non_private_projects_count topics = Projects::Topic.order_by_non_private_projects_count
topics = by_without_projects(topics)
by_search(topics) by_search(topics)
end end
...@@ -25,5 +26,11 @@ def by_search(topics) ...@@ -25,5 +26,11 @@ def by_search(topics)
topics.search(params[:search]).reorder_by_similarity(params[:search]) topics.search(params[:search]).reorder_by_similarity(params[:search])
end end
def by_without_projects(topics)
return topics unless params[:without_projects]
topics.without_assigned_projects
end
end end
end end
...@@ -15,6 +15,7 @@ class Topic < ApplicationRecord ...@@ -15,6 +15,7 @@ class Topic < ApplicationRecord
has_many :project_topics, class_name: 'Projects::ProjectTopic' has_many :project_topics, class_name: 'Projects::ProjectTopic'
has_many :projects, through: :project_topics has_many :projects, through: :project_topics
scope :without_assigned_projects, -> { where(total_projects_count: 0) }
scope :order_by_non_private_projects_count, -> { order(non_private_projects_count: :desc).order(id: :asc) } scope :order_by_non_private_projects_count, -> { order(non_private_projects_count: :desc).order(id: :asc) }
scope :reorder_by_similarity, -> (search) do scope :reorder_by_similarity, -> (search) do
order_expression = Gitlab::Database::SimilarityScore.build_expression(search: search, rules: [ order_expression = Gitlab::Database::SimilarityScore.build_expression(search: search, rules: [
......
...@@ -20,11 +20,12 @@ GET /topics ...@@ -20,11 +20,12 @@ GET /topics
Supported attributes: Supported attributes:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ---------- | ------- | ---------------------- | ----------- | | ------------------ | ------- | ---------------------- | ----------- |
| `page` | integer | **{dotted-circle}** No | Page to retrieve. Defaults to `1`. | | `page` | integer | **{dotted-circle}** No | Page to retrieve. Defaults to `1`. |
| `per_page` | integer | **{dotted-circle}** No | Number of records to return per page. Defaults to `20`. | | `per_page` | integer | **{dotted-circle}** No | Number of records to return per page. Defaults to `20`. |
| `search` | string | **{dotted-circle}** No | Search topics against their `name`. | | `search` | string | **{dotted-circle}** No | Search topics against their `name`. |
| `without_projects` | boolean | **{dotted-circle}** No | Limit results to topics without assigned projects. |
Example request: Example request:
......
...@@ -12,6 +12,7 @@ class Topics < ::API::Base ...@@ -12,6 +12,7 @@ class Topics < ::API::Base
end end
params do params do
optional :search, type: String, desc: 'Return list of topics matching the search criteria' optional :search, type: String, desc: 'Return list of topics matching the search criteria'
optional :without_projects, type: Boolean, desc: 'Return list of topics without assigned projects'
use :pagination use :pagination
end end
get 'topics' do get 'topics' do
......
...@@ -5,13 +5,13 @@ ...@@ -5,13 +5,13 @@
RSpec.describe Projects::TopicsFinder do RSpec.describe Projects::TopicsFinder do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let!(:topic1) { create(:topic, name: 'topicB') } let_it_be(:topic1) { create(:topic, name: 'topicB') }
let!(:topic2) { create(:topic, name: 'topicC') } let_it_be(:topic2) { create(:topic, name: 'topicC') }
let!(:topic3) { create(:topic, name: 'topicA') } let_it_be(:topic3) { create(:topic, name: 'topicA') }
let!(:project1) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC, topicA, topicB') } let_it_be(:project1) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC, topicA, topicB') }
let!(:project2) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC, topicA') } let_it_be(:project2) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC, topicA') }
let!(:project3) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC') } let_it_be(:project3) { create(:project, :public, namespace: user.namespace, topic_list: 'topicC') }
describe '#execute' do describe '#execute' do
it 'returns topics' do it 'returns topics' do
...@@ -41,5 +41,21 @@ ...@@ -41,5 +41,21 @@
end end
end end
end end
context 'filter by without_projects' do
let_it_be(:topic4) { create(:topic, name: 'unassigned topic') }
it 'returns topics without assigned projects' do
topics = described_class.new(params: { without_projects: true }).execute
expect(topics).to contain_exactly(topic4)
end
it 'returns topics without assigned projects' do
topics = described_class.new(params: { without_projects: false }).execute
expect(topics).to contain_exactly(topic1, topic2, topic3, topic4)
end
end
end end
end end
...@@ -30,6 +30,17 @@ ...@@ -30,6 +30,17 @@
end end
describe 'scopes' do describe 'scopes' do
describe 'without_assigned_projects' do
let_it_be(:unassigned_topic) { create(:topic, name: 'unassigned topic') }
let_it_be(:project) { create(:project, :public, topic_list: 'topic') }
it 'returns topics without assigned projects' do
topics = described_class.without_assigned_projects
expect(topics).to contain_exactly(unassigned_topic)
end
end
describe 'order_by_non_private_projects_count' do describe 'order_by_non_private_projects_count' do
let!(:topic1) { create(:topic, name: 'topicB') } let!(:topic1) { create(:topic, name: 'topicB') }
let!(:topic2) { create(:topic, name: 'topicC') } let!(:topic2) { create(:topic, name: 'topicC') }
......
...@@ -36,6 +36,22 @@ ...@@ -36,6 +36,22 @@
expect(json_response[2]['total_projects_count']).to eq(1) expect(json_response[2]['total_projects_count']).to eq(1)
end end
context 'with without_projects' do
let_it_be(:topic_4) { create(:topic, name: 'unassigned topic', total_projects_count: 0) }
it 'returns topics without assigned projects' do
get api('/topics'), params: { without_projects: true }
expect(json_response.map { |t| t['id'] }).to contain_exactly(topic_4.id)
end
it 'returns topics without assigned projects' do
get api('/topics'), params: { without_projects: false }
expect(json_response.map { |t| t['id'] }).to contain_exactly(topic_1.id, topic_2.id, topic_3.id, topic_4.id)
end
end
context 'with search' do context 'with search' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册