Support custom attributes on groups
This commit is contained in:
parent
6902848a9c
commit
1f773a8ef5
|
@ -15,6 +15,8 @@
|
|||
# Anonymous users will never return any `owned` groups. They will return all
|
||||
# public groups instead, even if `all_available` is set to false.
|
||||
class GroupsFinder < UnionFinder
|
||||
include CustomAttributesFilter
|
||||
|
||||
def initialize(current_user = nil, params = {})
|
||||
@current_user = current_user
|
||||
@params = params
|
||||
|
@ -22,8 +24,12 @@ class GroupsFinder < UnionFinder
|
|||
|
||||
def execute
|
||||
items = all_groups.map do |item|
|
||||
by_parent(item)
|
||||
item = by_parent(item)
|
||||
item = by_custom_attributes(item)
|
||||
|
||||
item
|
||||
end
|
||||
|
||||
find_union(items, Group).with_route.order_id_desc
|
||||
end
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class Group < Namespace
|
|||
has_many :notification_settings, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :labels, class_name: 'GroupLabel'
|
||||
has_many :variables, class_name: 'Ci::GroupVariable'
|
||||
has_many :custom_attributes, class_name: 'GroupCustomAttribute'
|
||||
|
||||
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
|
||||
validate :visibility_level_allowed_by_projects
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class GroupCustomAttribute < ActiveRecord::Base
|
||||
belongs_to :group
|
||||
|
||||
validates :group, :key, :value, presence: true
|
||||
validates :key, uniqueness: { scope: [:group_id] }
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Support custom attributes on groups and projects
|
||||
merge_request: 14593
|
||||
author: Markus Koller
|
||||
type: changed
|
|
@ -0,0 +1,19 @@
|
|||
class CreateGroupCustomAttributes < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
create_table :group_custom_attributes do |t|
|
||||
t.timestamps_with_timezone null: false
|
||||
t.references :group, null: false
|
||||
t.string :key, null: false
|
||||
t.string :value, null: false
|
||||
|
||||
t.index [:group_id, :key], unique: true
|
||||
t.index [:key, :value]
|
||||
end
|
||||
|
||||
add_foreign_key :group_custom_attributes, :namespaces, column: :group_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
|
||||
end
|
||||
end
|
12
db/schema.rb
12
db/schema.rb
|
@ -693,6 +693,17 @@ ActiveRecord::Schema.define(version: 20171026082505) do
|
|||
add_index "gpg_signatures", ["gpg_key_subkey_id"], name: "index_gpg_signatures_on_gpg_key_subkey_id", using: :btree
|
||||
add_index "gpg_signatures", ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree
|
||||
|
||||
create_table "group_custom_attributes", force: :cascade do |t|
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.integer "group_id", null: false
|
||||
t.string "key", null: false
|
||||
t.string "value", null: false
|
||||
end
|
||||
|
||||
add_index "group_custom_attributes", ["group_id", "key"], name: "index_group_custom_attributes_on_group_id_and_key", unique: true, using: :btree
|
||||
add_index "group_custom_attributes", ["key", "value"], name: "index_group_custom_attributes_on_key_and_value", using: :btree
|
||||
|
||||
create_table "identities", force: :cascade do |t|
|
||||
t.string "extern_uid"
|
||||
t.string "provider"
|
||||
|
@ -1840,6 +1851,7 @@ ActiveRecord::Schema.define(version: 20171026082505) do
|
|||
add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify
|
||||
add_foreign_key "gpg_signatures", "gpg_keys", on_delete: :nullify
|
||||
add_foreign_key "gpg_signatures", "projects", on_delete: :cascade
|
||||
add_foreign_key "group_custom_attributes", "namespaces", column: "group_id", on_delete: :cascade
|
||||
add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade
|
||||
add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade
|
||||
add_foreign_key "issue_metrics", "issues", on_delete: :cascade
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
# Custom Attributes API
|
||||
|
||||
Every API call to custom attributes must be authenticated as administrator.
|
||||
Custom attributes are currently available on users and projects, which will
|
||||
be referred to as "resource" in this documentation.
|
||||
|
||||
Custom attributes are currently available on users, groups, and projects,
|
||||
which will be referred to as "resource" in this documentation.
|
||||
|
||||
## List custom attributes
|
||||
|
||||
|
@ -10,6 +11,7 @@ Get all custom attributes on a resource.
|
|||
|
||||
```
|
||||
GET /users/:id/custom_attributes
|
||||
GET /groups/:id/custom_attributes
|
||||
GET /projects/:id/custom_attributes
|
||||
```
|
||||
|
||||
|
@ -42,6 +44,7 @@ Get a single custom attribute on a resource.
|
|||
|
||||
```
|
||||
GET /users/:id/custom_attributes/:key
|
||||
GET /groups/:id/custom_attributes/:key
|
||||
GET /projects/:id/custom_attributes/:key
|
||||
```
|
||||
|
||||
|
@ -70,6 +73,7 @@ or newly created otherwise.
|
|||
|
||||
```
|
||||
PUT /users/:id/custom_attributes/:key
|
||||
PUT /groups/:id/custom_attributes/:key
|
||||
PUT /projects/:id/custom_attributes/:key
|
||||
```
|
||||
|
||||
|
@ -98,6 +102,7 @@ Delete a custom attribute on a resource.
|
|||
|
||||
```
|
||||
DELETE /users/:id/custom_attributes/:key
|
||||
DELETE /groups/:id/custom_attributes/:key
|
||||
DELETE /projects/:id/custom_attributes/:key
|
||||
```
|
||||
|
||||
|
|
|
@ -74,6 +74,12 @@ GET /groups?statistics=true
|
|||
|
||||
You can search for groups by name or path, see below.
|
||||
|
||||
You can filter by [custom attributes](custom_attributes.md) with:
|
||||
|
||||
```
|
||||
GET /groups?custom_attributes[key]=value&custom_attributes[other_key]=other_value
|
||||
```
|
||||
|
||||
## List a group's projects
|
||||
|
||||
Get a list of projects in this group. When accessed without authentication, only
|
||||
|
|
|
@ -37,6 +37,8 @@ module API
|
|||
end
|
||||
|
||||
resource :groups do
|
||||
include CustomAttributesEndpoints
|
||||
|
||||
desc 'Get a groups list' do
|
||||
success Entities::Group
|
||||
end
|
||||
|
@ -51,7 +53,12 @@ module API
|
|||
use :pagination
|
||||
end
|
||||
get do
|
||||
find_params = { all_available: params[:all_available], owned: params[:owned] }
|
||||
find_params = {
|
||||
all_available: params[:all_available],
|
||||
owned: params[:owned],
|
||||
custom_attributes: params[:custom_attributes]
|
||||
}
|
||||
|
||||
groups = GroupsFinder.new(current_user, find_params).execute
|
||||
groups = groups.search(params[:search]) if params[:search].present?
|
||||
groups = groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present?
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
FactoryGirl.define do
|
||||
factory :group_custom_attribute do
|
||||
group
|
||||
sequence(:key) { |n| "key#{n}" }
|
||||
sequence(:value) { |n| "value#{n}" }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe GroupCustomAttribute do
|
||||
describe 'assocations' do
|
||||
it { is_expected.to belong_to(:group) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
subject { build :group_custom_attribute }
|
||||
|
||||
it { is_expected.to validate_presence_of(:group) }
|
||||
it { is_expected.to validate_presence_of(:key) }
|
||||
it { is_expected.to validate_presence_of(:value) }
|
||||
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:group_id) }
|
||||
end
|
||||
end
|
|
@ -17,6 +17,7 @@ describe Group do
|
|||
it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
|
||||
it { is_expected.to have_many(:uploads).dependent(:destroy) }
|
||||
it { is_expected.to have_one(:chat_team) }
|
||||
it { is_expected.to have_many(:custom_attributes).class_name('GroupCustomAttribute') }
|
||||
|
||||
describe '#members & #requesters' do
|
||||
let(:requester) { create(:user) }
|
||||
|
|
|
@ -618,4 +618,14 @@ describe API::Groups do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'custom attributes endpoints', 'groups' do
|
||||
let(:attributable) { group1 }
|
||||
let(:other_attributable) { group2 }
|
||||
let(:user) { user1 }
|
||||
|
||||
before do
|
||||
group2.add_owner(user1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue