Commit 298a580e authored by Douwe Maan's avatar Douwe Maan

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

[EE] Add BlocksJsonSerialization model concern and include it in User

See merge request gitlab-org/gitlab-ee!3835
parents ba8d3532 7911daf0
...@@ -8,7 +8,7 @@ class AutocompleteController < ApplicationController ...@@ -8,7 +8,7 @@ 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 project_groups def project_groups
...@@ -17,7 +17,7 @@ class AutocompleteController < ApplicationController ...@@ -17,7 +17,7 @@ class AutocompleteController < ApplicationController
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
......
...@@ -37,7 +37,7 @@ module FormHelper ...@@ -37,7 +37,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
......
...@@ -365,7 +365,7 @@ module IssuablesHelper ...@@ -365,7 +365,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,
weightOptions: Issue.weight_options, weightOptions: Issue.weight_options,
......
...@@ -149,7 +149,7 @@ module SearchHelper ...@@ -149,7 +149,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'
} }
......
# 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
...@@ -24,7 +24,7 @@ module TimeTrackable ...@@ -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
......
...@@ -18,6 +18,7 @@ class User < ActiveRecord::Base ...@@ -18,6 +18,7 @@ class User < ActiveRecord::Base
include CreatedAtFilterable include CreatedAtFilterable
include IgnorableColumn include IgnorableColumn
include BulkMemberAccessLoad include BulkMemberAccessLoad
include BlocksJsonSerialization
prepend EE::GeoAwareAvatar prepend EE::GeoAwareAvatar
prepend EE::User prepend EE::User
......
...@@ -406,7 +406,7 @@ module QuickActions ...@@ -406,7 +406,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
...@@ -429,7 +429,7 @@ module QuickActions ...@@ -429,7 +429,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}"
......
%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
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
- content_for :breadcrumbs_extra do - content_for :breadcrumbs_extra do
= render "projects/issues/nav_btns", show_export_button: false, show_rss_button: false = render "projects/issues/nav_btns", show_export_button: false, show_rss_button: false
- support_bot_attrs = User.support_bot.to_json(only: [:id, :name, :username, :avatar_url]) - support_bot_attrs = UserSerializer.new.represent(User.support_bot).to_json
%div{ class: "#{container_class} js-service-desk-issues service-desk-issues", data: { support_bot: support_bot_attrs } } %div{ class: "#{container_class} js-service-desk-issues service-desk-issues", data: { support_bot: support_bot_attrs } }
.top-area .top-area
......
...@@ -85,7 +85,7 @@ module API ...@@ -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 ...@@ -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}"
......
...@@ -86,7 +86,7 @@ module API ...@@ -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 ...@@ -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}"
......
...@@ -7,7 +7,6 @@ describe Gitlab::Geo::OauthSession do ...@@ -7,7 +7,6 @@ describe Gitlab::Geo::OauthSession do
let(:dummy_state) { 'salt:hmac:return_to' } let(:dummy_state) { 'salt:hmac:return_to' }
let(:valid_state) { described_class.new(return_to: oauth_return_to).generate_oauth_state } let(:valid_state) { described_class.new(return_to: oauth_return_to).generate_oauth_state }
let(:access_token) { FactoryBot.create(:doorkeeper_access_token).token } let(:access_token) { FactoryBot.create(:doorkeeper_access_token).token }
let(:user) { FactoryBot.build(:user) }
before do before do
allow(subject).to receive(:oauth_app) { oauth_app } allow(subject).to receive(:oauth_app) { oauth_app }
...@@ -122,7 +121,7 @@ describe Gitlab::Geo::OauthSession do ...@@ -122,7 +121,7 @@ describe Gitlab::Geo::OauthSession do
context 'on success' do context 'on success' do
it 'returns hashed user data' do it 'returns hashed user data' do
allow(response).to receive(:status) { 200 } allow(response).to receive(:status) { 200 }
allow(response).to receive(:parsed) { user.to_json } allow(response).to receive(:parsed) { attributes_for(:user) }
subject.authenticate_with_gitlab(access_token) subject.authenticate_with_gitlab(access_token)
end end
......
...@@ -82,9 +82,9 @@ feature 'Milestone' do ...@@ -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)
......
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
...@@ -308,7 +308,7 @@ describe Issuable do ...@@ -308,7 +308,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)
...@@ -519,7 +519,7 @@ describe Issuable do ...@@ -519,7 +519,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
......
...@@ -189,9 +189,9 @@ describe Milestone, 'Milestoneish' do ...@@ -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)
......
...@@ -12,6 +12,7 @@ describe User do ...@@ -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
......
...@@ -211,7 +211,7 @@ describe QuickActions::InterpretService do ...@@ -211,7 +211,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
...@@ -223,7 +223,7 @@ describe QuickActions::InterpretService do ...@@ -223,7 +223,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
...@@ -235,7 +235,7 @@ describe QuickActions::InterpretService do ...@@ -235,7 +235,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
...@@ -269,7 +269,7 @@ describe QuickActions::InterpretService do ...@@ -269,7 +269,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
......
...@@ -961,53 +961,6 @@ describe SystemNoteService do ...@@ -961,53 +961,6 @@ describe SystemNoteService do
end end
end end
describe '.change_time_spent' do
# We need a custom noteable in order to the shared examples to be green.
let(:noteable) do
mr = create(:merge_request, source_project: project)
mr.spend_time(duration: 360000, user: author)
mr.save!
mr
end
subject do
described_class.change_time_spent(noteable, project, author)
end
it_behaves_like 'a system note' do
let(:action) { 'time_tracking' }
end
context 'when time was added' do
it 'sets the note text' do
spend_time!(277200)
expect(subject.note).to eq "added 1w 4d 5h of time spent"
end
end
context 'when time was subtracted' do
it 'sets the note text' do
spend_time!(-277200)
expect(subject.note).to eq "subtracted 1w 4d 5h of time spent"
end
end
context 'when time was removed' do
it 'sets the note text' do
spend_time!(:reset)
expect(subject.note).to eq "removed time spent"
end
end
def spend_time!(seconds)
noteable.spend_time(duration: seconds, user: author)
noteable.save!
end
end
describe '.discussion_continued_in_issue' do describe '.discussion_continued_in_issue' do
let(:discussion) { create(:diff_note_on_merge_request, project: project).to_discussion } let(:discussion) { create(:diff_note_on_merge_request, project: project).to_discussion }
let(:merge_request) { discussion.noteable } let(:merge_request) { discussion.noteable }
...@@ -1060,7 +1013,7 @@ describe SystemNoteService do ...@@ -1060,7 +1013,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
...@@ -1098,7 +1051,7 @@ describe SystemNoteService do ...@@ -1098,7 +1051,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
......
...@@ -79,7 +79,7 @@ shared_examples 'time tracking endpoints' do |issuable_name| ...@@ -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| ...@@ -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| ...@@ -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)
......
...@@ -75,7 +75,7 @@ shared_examples 'V3 time tracking endpoints' do |issuable_name| ...@@ -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| ...@@ -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| ...@@ -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)
......
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