Commit 2f70f5d9 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'kassio/fix-missing-author-notes-on-importers' into 'master'

Use the original author id to find it on the members mapper

See merge request gitlab-org/gitlab!42648
parents 95790522 153bca12
---
title: Fixed a bug causing 'Missing author note' to be added to notes for mapped users when importing project using GitLab Import.
merge_request: 42648
author:
type: fixed
...@@ -5,16 +5,19 @@ require 'spec_helper' ...@@ -5,16 +5,19 @@ require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Group::RelationFactory do RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:members_mapper) { double('members_mapper').as_null_object } let(:members_mapper) { double('members_mapper').as_null_object }
let(:user) { create(:admin) } let(:admin) { create(:admin) }
let(:importer_user) { admin }
let(:excluded_keys) { [] } let(:excluded_keys) { [] }
let(:created_object) do let(:created_object) do
described_class.create(relation_sym: relation_sym, described_class.create(
relation_hash: relation_hash, relation_sym: relation_sym,
members_mapper: members_mapper, relation_hash: relation_hash,
object_builder: Gitlab::ImportExport::Group::ObjectBuilder, members_mapper: members_mapper,
user: user, object_builder: Gitlab::ImportExport::Group::ObjectBuilder,
importable: group, user: importer_user,
excluded_keys: excluded_keys) importable: group,
excluded_keys: excluded_keys
)
end end
context 'epic object' do context 'epic object' do
...@@ -24,15 +27,15 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do ...@@ -24,15 +27,15 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
let(:relation_hash) do let(:relation_hash) do
{ {
'id' => id, 'id' => id,
'milestone_id' => nil, 'milestone_id' => nil,
'group_id' => original_group_id, 'group_id' => original_group_id,
'assignee_id' => nil, 'assignee_id' => nil,
'created_at' => 'Wed, 20 Nov 2019 11:02:24 UTC +00:00', 'created_at' => 'Wed, 20 Nov 2019 11:02:24 UTC +00:00',
'updated_at' => 'Wed, 20 Nov 2019 11:02:24 UTC +00:00', 'updated_at' => 'Wed, 20 Nov 2019 11:02:24 UTC +00:00',
'title' => 'Title', 'title' => 'Title',
'description' => 'Description', 'description' => 'Description',
'state_id' => 'opened' 'state_id' => 'opened'
} }
end end
...@@ -65,58 +68,28 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do ...@@ -65,58 +68,28 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
end end
end end
context 'Notes user references' do it_behaves_like 'Notes user references' do
let(:relation_sym) { :notes } let(:importable) { group }
let(:new_user) { create(:user) }
let(:exported_member) do
{
'id' => 111,
'access_level' => 30,
'source_id' => 1,
'source_type' => 'Namespace',
'user_id' => 3,
'notification_level' => 3,
'created_at' => '2016-11-18T09:29:42.634Z',
'updated_at' => '2016-11-18T09:29:42.634Z',
'user' => {
'id' => 999,
'email' => new_user.email,
'username' => new_user.username
}
}
end
let(:relation_hash) do let(:relation_hash) do
{ {
'id' => 4947, 'id' => 4947,
'note' => 'note', 'note' => 'note',
'noteable_type' => 'Epic', 'noteable_type' => 'Epic',
'author_id' => 999, 'author_id' => 999,
'created_at' => '2016-11-18T09:29:42.634Z', 'created_at' => '2016-11-18T09:29:42.634Z',
'updated_at' => '2016-11-18T09:29:42.634Z', 'updated_at' => '2016-11-18T09:29:42.634Z',
'project_id' => 1, 'project_id' => 1,
'attachment' => { 'attachment' => {
'url' => nil 'url' => nil
}, },
'noteable_id' => 377, 'noteable_id' => 377,
'system' => true, 'system' => true,
'author' => { 'author' => {
'name' => 'Administrator' 'name' => 'Administrator'
}, },
'events' => [] 'events' => []
} }
end end
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(
exported_members: [exported_member],
user: user,
importable: group)
end
it 'maps the right author to the imported note' do
expect(created_object.author).to eq(new_user)
end
end end
def random_id def random_id
......
...@@ -53,6 +53,7 @@ module Gitlab ...@@ -53,6 +53,7 @@ module Gitlab
@importable = importable @importable = importable
@imported_object_retries = 0 @imported_object_retries = 0
@relation_hash[importable_column_name] = @importable.id @relation_hash[importable_column_name] = @importable.id
@original_user = {}
# Remove excluded keys from relation_hash # Remove excluded keys from relation_hash
# We don't do this in the parsed_relation_hash because of the 'transformed attributes' # We don't do this in the parsed_relation_hash because of the 'transformed attributes'
...@@ -112,6 +113,7 @@ module Gitlab ...@@ -112,6 +113,7 @@ module Gitlab
def update_user_references def update_user_references
self.class::USER_REFERENCES.each do |reference| self.class::USER_REFERENCES.each do |reference|
if @relation_hash[reference] if @relation_hash[reference]
@original_user[reference] = @relation_hash[reference]
@relation_hash[reference] = @members_mapper.map[@relation_hash[reference]] @relation_hash[reference] = @members_mapper.map[@relation_hash[reference]]
end end
end end
...@@ -243,7 +245,7 @@ module Gitlab ...@@ -243,7 +245,7 @@ module Gitlab
# will be used. Otherwise, a note stating the original author name # will be used. Otherwise, a note stating the original author name
# is left. # is left.
def set_note_author def set_note_author
old_author_id = @relation_hash['author_id'] old_author_id = @original_user['author_id']
author = @relation_hash.delete('author') author = @relation_hash.delete('author')
update_note_for_missing_author(author['name']) unless has_author?(old_author_id) update_note_for_missing_author(author['name']) unless has_author?(old_author_id)
......
...@@ -34,8 +34,8 @@ module Gitlab ...@@ -34,8 +34,8 @@ module Gitlab
@user.id @user.id
end end
def include?(old_author_id) def include?(old_user_id)
map.has_key?(old_author_id) && map[old_author_id] != default_user_id map.has_key?(old_user_id) && map[old_user_id] != default_user_id
end end
private private
......
...@@ -5,16 +5,19 @@ require 'spec_helper' ...@@ -5,16 +5,19 @@ require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Group::RelationFactory do RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:members_mapper) { double('members_mapper').as_null_object } let(:members_mapper) { double('members_mapper').as_null_object }
let(:user) { create(:admin) } let(:admin) { create(:admin) }
let(:importer_user) { admin }
let(:excluded_keys) { [] } let(:excluded_keys) { [] }
let(:created_object) do let(:created_object) do
described_class.create(relation_sym: relation_sym, described_class.create(
relation_hash: relation_hash, relation_sym: relation_sym,
members_mapper: members_mapper, relation_hash: relation_hash,
object_builder: Gitlab::ImportExport::Group::ObjectBuilder, members_mapper: members_mapper,
user: user, object_builder: Gitlab::ImportExport::Group::ObjectBuilder,
importable: group, user: importer_user,
excluded_keys: excluded_keys) importable: group,
excluded_keys: excluded_keys
)
end end
context 'label object' do context 'label object' do
...@@ -24,18 +27,18 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do ...@@ -24,18 +27,18 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
let(:relation_hash) do let(:relation_hash) do
{ {
'id' => 123456, 'id' => 123456,
'title' => 'Bruffefunc', 'title' => 'Bruffefunc',
'color' => '#1d2da4', 'color' => '#1d2da4',
'project_id' => nil, 'project_id' => nil,
'created_at' => '2019-11-20T17:02:20.546Z', 'created_at' => '2019-11-20T17:02:20.546Z',
'updated_at' => '2019-11-20T17:02:20.546Z', 'updated_at' => '2019-11-20T17:02:20.546Z',
'template' => false, 'template' => false,
'description' => 'Description', 'description' => 'Description',
'group_id' => original_group_id, 'group_id' => original_group_id,
'type' => 'GroupLabel', 'type' => 'GroupLabel',
'priorities' => [], 'priorities' => [],
'textColor' => '#FFFFFF' 'textColor' => '#FFFFFF'
} }
end end
...@@ -60,58 +63,28 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do ...@@ -60,58 +63,28 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
end end
end end
context 'Notes user references' do it_behaves_like 'Notes user references' do
let(:relation_sym) { :notes } let(:importable) { group }
let(:new_user) { create(:user) }
let(:exported_member) do
{
'id' => 111,
'access_level' => 30,
'source_id' => 1,
'source_type' => 'Namespace',
'user_id' => 3,
'notification_level' => 3,
'created_at' => '2016-11-18T09:29:42.634Z',
'updated_at' => '2016-11-18T09:29:42.634Z',
'user' => {
'id' => 999,
'email' => new_user.email,
'username' => new_user.username
}
}
end
let(:relation_hash) do let(:relation_hash) do
{ {
'id' => 4947, 'id' => 4947,
'note' => 'note', 'note' => 'note',
'noteable_type' => 'Epic', 'noteable_type' => 'Epic',
'author_id' => 999, 'author_id' => 999,
'created_at' => '2016-11-18T09:29:42.634Z', 'created_at' => '2016-11-18T09:29:42.634Z',
'updated_at' => '2016-11-18T09:29:42.634Z', 'updated_at' => '2016-11-18T09:29:42.634Z',
'project_id' => 1, 'project_id' => 1,
'attachment' => { 'attachment' => {
'url' => nil 'url' => nil
}, },
'noteable_id' => 377, 'noteable_id' => 377,
'system' => true, 'system' => true,
'author' => { 'author' => {
'name' => 'Administrator' 'name' => 'Administrator'
}, },
'events' => [] 'events' => []
} }
end end
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(
exported_members: [exported_member],
user: user,
importable: group)
end
it 'maps the right author to the imported note' do
expect(created_object.author).to eq(new_user)
end
end end
def random_id def random_id
......
...@@ -3,19 +3,22 @@ ...@@ -3,19 +3,22 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Project::RelationFactory do RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project) { create(:project, :repository, group: group) } let(:project) { create(:project, :repository, group: group) }
let(:members_mapper) { double('members_mapper').as_null_object } let(:members_mapper) { double('members_mapper').as_null_object }
let(:user) { create(:admin) } let(:admin) { create(:admin) }
let(:importer_user) { admin }
let(:excluded_keys) { [] } let(:excluded_keys) { [] }
let(:created_object) do let(:created_object) do
described_class.create(relation_sym: relation_sym, described_class.create(
relation_hash: relation_hash, relation_sym: relation_sym,
object_builder: Gitlab::ImportExport::Project::ObjectBuilder, relation_hash: relation_hash,
members_mapper: members_mapper, object_builder: Gitlab::ImportExport::Project::ObjectBuilder,
user: user, members_mapper: members_mapper,
importable: project, user: importer_user,
excluded_keys: excluded_keys) importable: project,
excluded_keys: excluded_keys
)
end end
before do before do
...@@ -113,9 +116,9 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do ...@@ -113,9 +116,9 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
"created_at" => "2016-11-18T09:29:42.634Z", "created_at" => "2016-11-18T09:29:42.634Z",
"updated_at" => "2016-11-18T09:29:42.634Z", "updated_at" => "2016-11-18T09:29:42.634Z",
"user" => { "user" => {
"id" => user.id, "id" => admin.id,
"email" => user.email, "email" => admin.email,
"username" => user.username "username" => admin.username
} }
} }
end end
...@@ -123,7 +126,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do ...@@ -123,7 +126,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
let(:members_mapper) do let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new( Gitlab::ImportExport::MembersMapper.new(
exported_members: [exported_member], exported_members: [exported_member],
user: user, user: importer_user,
importable: project) importable: project)
end end
...@@ -134,9 +137,9 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do ...@@ -134,9 +137,9 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
'source_branch' => "feature_conflict", 'source_branch' => "feature_conflict",
'source_project_id' => project.id, 'source_project_id' => project.id,
'target_project_id' => project.id, 'target_project_id' => project.id,
'author_id' => user.id, 'author_id' => admin.id,
'assignee_id' => user.id, 'assignee_id' => admin.id,
'updated_by_id' => user.id, 'updated_by_id' => admin.id,
'title' => "MR1", 'title' => "MR1",
'created_at' => "2016-06-14T15:02:36.568Z", 'created_at' => "2016-06-14T15:02:36.568Z",
'updated_at' => "2016-06-14T15:02:56.815Z", 'updated_at' => "2016-06-14T15:02:56.815Z",
...@@ -151,11 +154,11 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do ...@@ -151,11 +154,11 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
end end
it 'has preloaded author' do it 'has preloaded author' do
expect(created_object.author).to equal(user) expect(created_object.author).to equal(admin)
end end
it 'has preloaded updated_by' do it 'has preloaded updated_by' do
expect(created_object.updated_by).to equal(user) expect(created_object.updated_by).to equal(admin)
end end
it 'has preloaded source project' do it 'has preloaded source project' do
...@@ -264,27 +267,8 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do ...@@ -264,27 +267,8 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
end end
end end
context 'Notes user references' do it_behaves_like 'Notes user references' do
let(:relation_sym) { :notes } let(:importable) { project }
let(:new_user) { create(:user) }
let(:exported_member) do
{
"id" => 111,
"access_level" => 30,
"source_id" => 1,
"source_type" => "Project",
"user_id" => 3,
"notification_level" => 3,
"created_at" => "2016-11-18T09:29:42.634Z",
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => 999,
"email" => new_user.email,
"username" => new_user.username
}
}
end
let(:relation_hash) do let(:relation_hash) do
{ {
"id" => 4947, "id" => 4947,
...@@ -305,17 +289,6 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do ...@@ -305,17 +289,6 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
"events" => [] "events" => []
} }
end end
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(
exported_members: [exported_member],
user: user,
importable: project)
end
it 'maps the right author to the imported note' do
expect(created_object.author).to eq(new_user)
end
end end
context 'encrypted attributes' do context 'encrypted attributes' do
......
# frozen_string_literal: true
# required context:
# - importable: group or project
# - relation_hash: a note relation that's being imported
# - created_object: the object created with the relation factory
RSpec.shared_examples 'Notes user references' do
let(:relation_sym) { :notes }
let(:mapped_user) { create(:user) }
let(:exported_member) do
{
'id' => 111,
'access_level' => 30,
'source_id' => 1,
'source_type' => importable.class.name == 'Project' ? 'Project' : 'Namespace',
'user_id' => 3,
'notification_level' => 3,
'created_at' => '2016-11-18T09:29:42.634Z',
'updated_at' => '2016-11-18T09:29:42.634Z',
'user' => {
'id' => 999,
'email' => mapped_user.email,
'username' => mapped_user.username
}
}
end
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(
exported_members: [exported_member].compact,
user: importer_user,
importable: importable
)
end
shared_examples 'sets the note author to the importer user' do
it { expect(created_object.author).to eq(importer_user) }
end
shared_examples 'sets the note author to the mapped user' do
it { expect(created_object.author).to eq(mapped_user) }
end
shared_examples 'does not add original autor note' do
it { expect(created_object.note).not_to include('*By Administrator') }
end
shared_examples 'adds original autor note' do
it { expect(created_object.note).to include('*By Administrator') }
end
context 'when the importer is admin' do
let(:importer_user) { create(:admin) }
context 'and the note author is not mapped' do
let(:exported_member) { nil }
include_examples 'sets the note author to the importer user'
include_examples 'adds original autor note'
end
context 'and the note author is the importer user' do
let(:mapped_user) { importer_user }
include_examples 'sets the note author to the mapped user'
include_examples 'adds original autor note'
end
context 'and the note author exists in the target instance' do
let(:mapped_user) { create(:user) }
include_examples 'sets the note author to the mapped user'
include_examples 'does not add original autor note'
end
end
context 'when the importer is not admin' do
let(:importer_user) { create(:user) }
context 'and the note author is not mapped' do
let(:exported_member) { nil }
include_examples 'sets the note author to the importer user'
include_examples 'adds original autor note'
end
context 'and the note author is the importer user' do
let(:mapped_user) { importer_user }
include_examples 'sets the note author to the importer user'
include_examples 'adds original autor note'
end
context 'and the note author exists in the target instance' do
let(:mapped_user) { create(:user) }
include_examples 'sets the note author to the importer user'
include_examples 'adds original autor note'
end
end
end
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