Merge branch 'rs-blocks-json-serialization' into 'master'

Add BlocksJsonSerialization model concern and include it in User

Closes #37947

See merge request gitlab-org/gitlab-ce!14350
This commit is contained in:
Douwe Maan 2017-12-20 12:02:21 +00:00
commit d318075aba
20 changed files with 66 additions and 32 deletions

View File

@ -8,12 +8,12 @@ class AutocompleteController < ApplicationController
def users def users
@users = AutocompleteUsersFinder.new(params: params, current_user: current_user, project: @project, group: @group).execute @users = AutocompleteUsersFinder.new(params: params, current_user: current_user, project: @project, group: @group).execute
render json: @users, only: [:name, :username, :id], methods: [:avatar_url] render json: UserSerializer.new.represent(@users)
end end
def user def user
@user = User.find(params[:id]) @user = User.find(params[:id])
render json: @user, only: [:name, :username, :id], methods: [:avatar_url] render json: UserSerializer.new.represent(@user)
end end
def projects def projects

View File

@ -35,7 +35,7 @@ module FormHelper
multi_select: true, multi_select: true,
'input-meta': 'name', 'input-meta': 'name',
'always-show-selectbox': true, 'always-show-selectbox': true,
current_user_info: current_user.to_json(only: [:id, :name]) current_user_info: UserSerializer.new.represent(current_user)
} }
} }
end end

View File

@ -362,7 +362,7 @@ module IssuablesHelper
moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable), moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable),
projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id), projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id),
editable: can_edit_issuable, editable: can_edit_issuable,
currentUser: current_user.as_json(only: [:username, :id, :name], methods: :avatar_url), currentUser: UserSerializer.new.represent(current_user),
rootPath: root_path, rootPath: root_path,
fullPath: @project.full_path fullPath: @project.full_path
} }

View File

@ -139,7 +139,7 @@ module SearchHelper
id: "filtered-search-#{type}", id: "filtered-search-#{type}",
placeholder: 'Search or filter results...', placeholder: 'Search or filter results...',
data: { data: {
'username-params' => @users.to_json(only: [:id, :username]) 'username-params' => UserSerializer.new.represent(@users)
}, },
autocomplete: 'off' autocomplete: 'off'
} }

View File

@ -0,0 +1,16 @@
# Overrides `as_json` and `to_json` to raise an exception when called in order
# to prevent accidentally exposing attributes
#
# Not that that would ever happen... but just in case.
module BlocksJsonSerialization
extend ActiveSupport::Concern
JsonSerializationError = Class.new(StandardError)
def to_json(*)
raise JsonSerializationError,
"JSON serialization has been disabled on #{self.class.name}"
end
alias_method :as_json, :to_json
end

View File

@ -24,7 +24,7 @@ module TimeTrackable
# rubocop:disable Gitlab/ModuleWithInstanceVariables # rubocop:disable Gitlab/ModuleWithInstanceVariables
def spend_time(options) def spend_time(options)
@time_spent = options[:duration] @time_spent = options[:duration]
@time_spent_user = options[:user] @time_spent_user = User.find(options[:user_id])
@spent_at = options[:spent_at] @spent_at = options[:spent_at]
@original_total_time_spent = nil @original_total_time_spent = nil

View File

@ -18,6 +18,7 @@ class User < ActiveRecord::Base
include CreatedAtFilterable include CreatedAtFilterable
include IgnorableColumn include IgnorableColumn
include BulkMemberAccessLoad include BulkMemberAccessLoad
include BlocksJsonSerialization
DEFAULT_NOTIFICATION_LEVEL = :participating DEFAULT_NOTIFICATION_LEVEL = :participating

View File

@ -405,7 +405,7 @@ module QuickActions
if time_spent if time_spent
@updates[:spend_time] = { @updates[:spend_time] = {
duration: time_spent, duration: time_spent,
user: current_user, user_id: current_user.id,
spent_at: time_spent_date spent_at: time_spent_date
} }
end end
@ -428,7 +428,7 @@ module QuickActions
current_user.can?(:"admin_#{issuable.to_ability_name}", project) current_user.can?(:"admin_#{issuable.to_ability_name}", project)
end end
command :remove_time_spent do command :remove_time_spent do
@updates[:spend_time] = { duration: :reset, user: current_user } @updates[:spend_time] = { duration: :reset, user_id: current_user.id }
end end
desc "Append the comment with #{SHRUG}" desc "Append the comment with #{SHRUG}"

View File

@ -1,5 +1,4 @@
%board-sidebar{ "inline-template" => true, %board-sidebar{ "inline-template" => true, ":current-user" => (UserSerializer.new.represent(current_user) || {}).to_json }
":current-user" => "#{current_user ? current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) : {}}" }
%transition{ name: "boards-sidebar-slide" } %transition{ name: "boards-sidebar-slide" }
%aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar" } %aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar" }
.issuable-sidebar .issuable-sidebar

View File

@ -85,7 +85,7 @@ module API
update_issuable(spend_time: { update_issuable(spend_time: {
duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)), duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
user: current_user user_id: current_user.id
}) })
end end
@ -97,7 +97,7 @@ module API
authorize! update_issuable_key, load_issuable authorize! update_issuable_key, load_issuable
status :ok status :ok
update_issuable(spend_time: { duration: :reset, user: current_user }) update_issuable(spend_time: { duration: :reset, user_id: current_user.id })
end end
desc "Show time stats for a project #{issuable_name}" desc "Show time stats for a project #{issuable_name}"

View File

@ -86,7 +86,7 @@ module API
update_issuable(spend_time: { update_issuable(spend_time: {
duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)), duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
user: current_user user_id: current_user.id
}) })
end end
@ -98,7 +98,7 @@ module API
authorize! update_issuable_key, load_issuable authorize! update_issuable_key, load_issuable
status :ok status :ok
update_issuable(spend_time: { duration: :reset, user: current_user }) update_issuable(spend_time: { duration: :reset, user_id: current_user.id })
end end
desc "Show time stats for a project #{issuable_name}" desc "Show time stats for a project #{issuable_name}"

View File

@ -82,9 +82,9 @@ feature 'Milestone' do
milestone = create(:milestone, project: project, title: 8.7) milestone = create(:milestone, project: project, title: 8.7)
issue1 = create(:issue, project: project, milestone: milestone) issue1 = create(:issue, project: project, milestone: milestone)
issue2 = create(:issue, project: project, milestone: milestone) issue2 = create(:issue, project: project, milestone: milestone)
issue1.spend_time(duration: 3600, user: user) issue1.spend_time(duration: 3600, user_id: user.id)
issue1.save! issue1.save!
issue2.spend_time(duration: 7200, user: user) issue2.spend_time(duration: 7200, user_id: user.id)
issue2.save! issue2.save!
visit project_milestone_path(project, milestone) visit project_milestone_path(project, milestone)

View File

@ -0,0 +1,17 @@
require 'rails_helper'
describe BlocksJsonSerialization do
DummyModel = Class.new do
include BlocksJsonSerialization
end
it 'blocks as_json' do
expect { DummyModel.new.as_json }
.to raise_error(described_class::JsonSerializationError, /DummyModel/)
end
it 'blocks to_json' do
expect { DummyModel.new.to_json }
.to raise_error(described_class::JsonSerializationError, /DummyModel/)
end
end

View File

@ -291,7 +291,7 @@ describe Issuable do
context 'total_time_spent is updated' do context 'total_time_spent is updated' do
before do before do
issue.spend_time(duration: 2, user: user, spent_at: Time.now) issue.spend_time(duration: 2, user_id: user.id, spent_at: Time.now)
issue.save issue.save
expect(Gitlab::HookData::IssuableBuilder) expect(Gitlab::HookData::IssuableBuilder)
.to receive(:new).with(issue).and_return(builder) .to receive(:new).with(issue).and_return(builder)
@ -485,7 +485,7 @@ describe Issuable do
let(:issue) { create(:issue) } let(:issue) { create(:issue) }
def spend_time(seconds) def spend_time(seconds)
issue.spend_time(duration: seconds, user: user) issue.spend_time(duration: seconds, user_id: user.id)
issue.save! issue.save!
end end

View File

@ -189,9 +189,9 @@ describe Milestone, 'Milestoneish' do
describe '#total_issue_time_spent' do describe '#total_issue_time_spent' do
it 'calculates total issue time spent' do it 'calculates total issue time spent' do
closed_issue_1.spend_time(duration: 300, user: author) closed_issue_1.spend_time(duration: 300, user_id: author.id)
closed_issue_1.save! closed_issue_1.save!
closed_issue_2.spend_time(duration: 600, user: assignee) closed_issue_2.spend_time(duration: 600, user_id: assignee.id)
closed_issue_2.save! closed_issue_2.save!
expect(milestone.total_issue_time_spent).to eq(900) expect(milestone.total_issue_time_spent).to eq(900)

View File

@ -12,6 +12,7 @@ describe User do
it { is_expected.to include_module(Referable) } it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Sortable) } it { is_expected.to include_module(Sortable) }
it { is_expected.to include_module(TokenAuthenticatable) } it { is_expected.to include_module(TokenAuthenticatable) }
it { is_expected.to include_module(BlocksJsonSerialization) }
end end
describe 'delegations' do describe 'delegations' do

View File

@ -209,7 +209,7 @@ describe QuickActions::InterpretService do
expect(updates).to eq(spend_time: { expect(updates).to eq(spend_time: {
duration: 3600, duration: 3600,
user: developer, user_id: developer.id,
spent_at: DateTime.now.to_date spent_at: DateTime.now.to_date
}) })
end end
@ -221,7 +221,7 @@ describe QuickActions::InterpretService do
expect(updates).to eq(spend_time: { expect(updates).to eq(spend_time: {
duration: -1800, duration: -1800,
user: developer, user_id: developer.id,
spent_at: DateTime.now.to_date spent_at: DateTime.now.to_date
}) })
end end
@ -233,7 +233,7 @@ describe QuickActions::InterpretService do
expect(updates).to eq(spend_time: { expect(updates).to eq(spend_time: {
duration: 1800, duration: 1800,
user: developer, user_id: developer.id,
spent_at: Date.parse(date) spent_at: Date.parse(date)
}) })
end end
@ -267,7 +267,7 @@ describe QuickActions::InterpretService do
it 'populates spend_time: :reset if content contains /remove_time_spent' do it 'populates spend_time: :reset if content contains /remove_time_spent' do
_, updates = service.execute(content, issuable) _, updates = service.execute(content, issuable)
expect(updates).to eq(spend_time: { duration: :reset, user: developer }) expect(updates).to eq(spend_time: { duration: :reset, user_id: developer.id })
end end
end end

View File

@ -927,7 +927,7 @@ describe SystemNoteService do
# We need a custom noteable in order to the shared examples to be green. # We need a custom noteable in order to the shared examples to be green.
let(:noteable) do let(:noteable) do
mr = create(:merge_request, source_project: project) mr = create(:merge_request, source_project: project)
mr.spend_time(duration: 360000, user: author) mr.spend_time(duration: 360000, user_id: author.id)
mr.save! mr.save!
mr mr
end end
@ -965,7 +965,7 @@ describe SystemNoteService do
end end
def spend_time!(seconds) def spend_time!(seconds)
noteable.spend_time(duration: seconds, user: author) noteable.spend_time(duration: seconds, user_id: author.id)
noteable.save! noteable.save!
end end
end end

View File

@ -79,7 +79,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
context 'when subtracting time' do context 'when subtracting time' do
it 'subtracts time of the total spent time' do it 'subtracts time of the total spent time' do
issuable.update_attributes!(spend_time: { duration: 7200, user: user }) issuable.update_attributes!(spend_time: { duration: 7200, user_id: user.id })
post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user),
duration: '-1h' duration: '-1h'
@ -91,7 +91,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
context 'when time to subtract is greater than the total spent time' do context 'when time to subtract is greater than the total spent time' do
it 'does not modify the total time spent' do it 'does not modify the total time spent' do
issuable.update_attributes!(spend_time: { duration: 7200, user: user }) issuable.update_attributes!(spend_time: { duration: 7200, user_id: user.id })
post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user),
duration: '-1w' duration: '-1w'
@ -119,7 +119,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do
it "returns the time stats for #{issuable_name}" do it "returns the time stats for #{issuable_name}" do
issuable.update_attributes!(spend_time: { duration: 1800, user: user }, issuable.update_attributes!(spend_time: { duration: 1800, user_id: user.id },
time_estimate: 3600) time_estimate: 3600)
get api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_stats", user) get api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_stats", user)

View File

@ -75,7 +75,7 @@ shared_examples 'V3 time tracking endpoints' do |issuable_name|
context 'when subtracting time' do context 'when subtracting time' do
it 'subtracts time of the total spent time' do it 'subtracts time of the total spent time' do
issuable.update_attributes!(spend_time: { duration: 7200, user: user }) issuable.update_attributes!(spend_time: { duration: 7200, user_id: user.id })
post v3_api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), post v3_api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user),
duration: '-1h' duration: '-1h'
@ -87,7 +87,7 @@ shared_examples 'V3 time tracking endpoints' do |issuable_name|
context 'when time to subtract is greater than the total spent time' do context 'when time to subtract is greater than the total spent time' do
it 'does not modify the total time spent' do it 'does not modify the total time spent' do
issuable.update_attributes!(spend_time: { duration: 7200, user: user }) issuable.update_attributes!(spend_time: { duration: 7200, user_id: user.id })
post v3_api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), post v3_api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user),
duration: '-1w' duration: '-1w'
@ -115,7 +115,7 @@ shared_examples 'V3 time tracking endpoints' do |issuable_name|
describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do
it "returns the time stats for #{issuable_name}" do it "returns the time stats for #{issuable_name}" do
issuable.update_attributes!(spend_time: { duration: 1800, user: user }, issuable.update_attributes!(spend_time: { duration: 1800, user_id: user.id },
time_estimate: 3600) time_estimate: 3600)
get v3_api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_stats", user) get v3_api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_stats", user)