Merge branch 'bw-serializer-tech-debit' into 'master'

Extract code into IssueBoardEntity / serializer

See merge request gitlab-org/gitlab-ce!22760
This commit is contained in:
Douwe Maan 2018-11-06 18:33:13 +00:00
commit aa9a662b66
11 changed files with 153 additions and 32 deletions

View file

@ -100,18 +100,12 @@ module Boards
.merge(board_id: params[:board_id], list_id: params[:list_id], request: request)
end
def serializer
IssueSerializer.new(current_user: current_user)
end
def serialize_as_json(resource)
resource.as_json(
only: [:id, :iid, :project_id, :title, :confidential, :due_date, :relative_position, :weight],
labels: true,
issue_endpoints: true,
include_full_project_path: board.group_board?,
include: {
project: { only: [:id, :path] },
assignees: { only: [:id, :name, :username], methods: [:avatar_url] },
milestone: { only: [:id, :title] }
}
)
serializer.represent(resource, serializer: 'board', include_full_project_path: board.group_board?)
end
def whitelist_query_limiting

View file

@ -231,20 +231,6 @@ class Issue < ActiveRecord::Base
def as_json(options = {})
super(options).tap do |json|
if options.key?(:issue_endpoints) && project
url_helper = Gitlab::Routing.url_helpers
issue_reference = options[:include_full_project_path] ? to_reference(full: true) : to_reference
json.merge!(
reference_path: issue_reference,
real_path: url_helper.project_issue_path(project, self),
issue_sidebar_endpoint: url_helper.project_issue_path(project, self, format: :json, serializer: 'sidebar'),
toggle_subscription_endpoint: url_helper.toggle_subscription_project_issue_path(project, self),
assignable_labels_endpoint: url_helper.project_labels_path(project, format: :json, include_ancestor_groups: true)
)
end
if options.key?(:labels)
json[:labels] = labels.as_json(
project: project,

View file

@ -180,7 +180,7 @@ def index
render json: MyResourceSerializer
.new(current_user: @current_user)
.represent_details(@project.resources)
nd
end
end
```
@ -196,7 +196,7 @@ def index
.represent_details(@project.resources),
count: @project.resources.count
}
nd
end
end
```

View file

@ -0,0 +1,51 @@
# frozen_string_literal: true
class IssueBoardEntity < Grape::Entity
include RequestAwareEntity
expose :id
expose :iid
expose :title
expose :confidential
expose :due_date
expose :project_id
expose :relative_position
expose :weight, if: -> (*) { respond_to?(:weight) }
expose :project do |issue|
API::Entities::Project.represent issue.project, only: [:id, :path]
end
expose :milestone, expose_nil: false do |issue|
API::Entities::Project.represent issue.milestone, only: [:id, :title]
end
expose :assignees do |issue|
API::Entities::UserBasic.represent issue.assignees, only: [:id, :name, :username, :avatar_url]
end
expose :labels do |issue|
LabelEntity.represent issue.labels, project: issue.project, only: [:id, :title, :description, :color, :priority, :text_color]
end
expose :reference_path, if: -> (issue) { issue.project } do |issue, options|
options[:include_full_project_path] ? issue.to_reference(full: true) : issue.to_reference
end
expose :real_path, if: -> (issue) { issue.project } do |issue|
project_issue_path(issue.project, issue)
end
expose :issue_sidebar_endpoint, if: -> (issue) { issue.project } do |issue|
project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar')
end
expose :toggle_subscription_endpoint, if: -> (issue) { issue.project } do |issue|
toggle_subscription_project_issue_path(issue.project, issue)
end
expose :assignable_labels_endpoint, if: -> (issue) { issue.project } do |issue|
project_labels_path(issue.project, format: :json, include_ancestor_groups: true)
end
end

View file

@ -4,15 +4,17 @@ class IssueSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `issue` based on `basic` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
def represent(merge_request, opts = {})
def represent(issue, opts = {})
entity =
case opts[:serializer]
when 'sidebar'
IssueSidebarEntity
when 'board'
IssueBoardEntity
else
IssueEntity
end
super(merge_request, opts, entity)
super(issue, opts, entity)
end
end

View file

@ -12,4 +12,8 @@ class LabelEntity < Grape::Entity
expose :text_color
expose :created_at
expose :updated_at
expose :priority, if: -> (*) { options.key?(:project) } do |label|
label.priority(options[:project])
end
end

View file

@ -50,7 +50,7 @@ describe Boards::IssuesController do
parsed_response = JSON.parse(response.body)
expect(response).to match_response_schema('issues')
expect(response).to match_response_schema('entities/issue_boards')
expect(parsed_response['issues'].length).to eq 2
expect(development.issues.map(&:relative_position)).not_to include(nil)
end
@ -121,7 +121,7 @@ describe Boards::IssuesController do
parsed_response = JSON.parse(response.body)
expect(response).to match_response_schema('issues')
expect(response).to match_response_schema('entities/issue_boards')
expect(parsed_response['issues'].length).to eq 2
end
end
@ -168,7 +168,7 @@ describe Boards::IssuesController do
it 'returns the created issue' do
create_issue user: user, board: board, list: list1, title: 'New issue'
expect(response).to match_response_schema('issue')
expect(response).to match_response_schema('entities/issue_board')
end
end

View file

@ -0,0 +1,38 @@
{
"type": "object",
"properties" : {
"id": { "type": "integer" },
"iid": { "type": "integer" },
"title": { "type": "string" },
"confidential": { "type": "boolean" },
"due_date": { "type": "date" },
"project_id": { "type": "integer" },
"relative_position": { "type": ["integer", "null"] },
"weight": { "type": "integer" },
"project": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"path": { "type": "string" }
}
},
"milestone": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"title": { "type": "string" }
}
},
"assignees": { "type": ["array", "null"] },
"labels": {
"type": "array",
"items": { "$ref": "label.json" }
},
"reference_path": { "type": "string" },
"real_path": { "type": "string" },
"issue_sidebar_endpoint": { "type": "string" },
"toggle_subscription_endpoint": { "type": "string" },
"assignable_labels_endpoint": { "type": "string" }
},
"additionalProperties": false
}

View file

@ -0,0 +1,15 @@
{
"type": "object",
"required" : [
"issues",
"size"
],
"properties" : {
"issues": {
"type": "array",
"items": { "$ref": "issue_board.json" }
},
"size": { "type": "integer" }
},
"additionalProperties": false
}

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'spec_helper'
describe IssueBoardEntity do
let(:project) { create(:project) }
let(:resource) { create(:issue, project: project) }
let(:user) { create(:user) }
let(:request) { double('request', current_user: user) }
subject { described_class.new(resource, request: request).as_json }
it 'has basic attributes' do
expect(subject).to include(:id, :iid, :title, :confidential, :due_date, :project_id, :relative_position,
:project, :labels)
end
it 'has path and endpoints' do
expect(subject).to include(:reference_path, :real_path, :issue_sidebar_endpoint,
:toggle_subscription_endpoint, :assignable_labels_endpoint)
end
end

View file

@ -24,4 +24,12 @@ describe IssueSerializer do
expect(json_entity).to match_schema('entities/issue_sidebar')
end
end
context 'board issue serialization' do
let(:serializer) { 'board' }
it 'matches board issue json schema' do
expect(json_entity).to match_schema('entities/issue_board')
end
end
end