From 36c0c8ae5e1723cfc5f49322f0502cbe5878a5a0 Mon Sep 17 00:00:00 2001 From: Pavel Balashou Date: Thu, 11 Jun 2026 11:13:31 +0200 Subject: [PATCH] [JIM-112] Capital letters in user email or login break import with error. https://community.openproject.org/wp/JIM-112 --- app/models/import/jira_user.rb | 4 +- .../import/jira_import_projects_job.rb | 12 +++- spec/models/import/jira_user_spec.rb | 63 +++++++++++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/app/models/import/jira_user.rb b/app/models/import/jira_user.rb index 258b70fa2b6..fc657c4d4eb 100644 --- a/app/models/import/jira_user.rb +++ b/app/models/import/jira_user.rb @@ -51,8 +51,8 @@ module Import def try_to_find_existing_op_users op_attributes = to_op_attributes - User.where(login: op_attributes[:login]).or( - User.where(mail: op_attributes[:mail]) + User.by_login(op_attributes[:login]).or( + User.where("LOWER(mail) = ?", op_attributes[:mail]&.downcase) ) end diff --git a/app/workers/import/jira_import_projects_job.rb b/app/workers/import/jira_import_projects_job.rb index ee7b0a71ee3..2d1f6b5a4aa 100644 --- a/app/workers/import/jira_import_projects_job.rb +++ b/app/workers/import/jira_import_projects_job.rb @@ -384,10 +384,16 @@ module Import jira_user = Import::JiraUser.find_by(jira_user_key:, jira_import: @jira_import) if jira_user - JiraOpenProjectReference.find_by!( - jira_entity_class: "Import::JiraUser", + reference = JiraOpenProjectReference.find_by( + jira_entity_class: jira_user.class.to_s, jira_entity_id: jira_user.id - ).op_leg + ) + if reference + reference.op_leg + else + raise "Import::JiraOpenProjectReference with jira_entity_class #{jira_user.class} " \ + "and jira_entity_id #{jira_user.id} not found!" + end else raise "Import::JiraUser with jira_user_key #{jira_user_key} not found!" end diff --git a/spec/models/import/jira_user_spec.rb b/spec/models/import/jira_user_spec.rb index e0f2b00acec..8130c12a0a9 100644 --- a/spec/models/import/jira_user_spec.rb +++ b/spec/models/import/jira_user_spec.rb @@ -110,6 +110,69 @@ RSpec.describe Import::JiraUser do end end + describe "#try_to_find_existing_op_users" do + subject(:result) { jira_user.try_to_find_existing_op_users } + + let(:payload) { { "displayName" => "Test User", "name" => "testuser", "emailAddress" => "test@example.com" } } + + context "when no matching user exists" do + it "returns an empty relation" do + expect(result).to be_empty + end + end + + context "when a user with matching login exists (case-insensitive)" do + let!(:existing_user) { create(:user, login: "TestUser", mail: "other@example.com") } + + it "finds the user" do + expect(result).to contain_exactly(existing_user) + end + end + + context "when a user with matching email exists (case-insensitive)" do + let!(:existing_user) { create(:user, login: "otherlogin", mail: "TEST@EXAMPLE.COM") } + + it "finds the user" do + expect(result).to contain_exactly(existing_user) + end + end + + context "when a user matches both login and email" do + let!(:existing_user) { create(:user, login: "TESTUSER", mail: "TEST@example.com") } + + it "finds the user once" do + expect(result).to contain_exactly(existing_user) + end + end + + context "when different users match login and email respectively" do + let!(:user_by_login) { create(:user, login: "TESTUSER", mail: "different@example.com") } + let!(:user_by_email) { create(:user, login: "differentlogin", mail: "TEST@EXAMPLE.COM") } + + it "finds both users" do + expect(result).to contain_exactly(user_by_login, user_by_email) + end + end + + context "when email is nil in payload" do + let(:payload) { { "displayName" => "Test User", "name" => "testuser", "emailAddress" => nil } } + let!(:existing_user) { create(:user, login: "TESTUSER", mail: "any@example.com") } + + it "still finds users by login" do + expect(result).to contain_exactly(existing_user) + end + end + + context "when email separator is used" do + let(:payload) { { "displayName" => "Test User", "name" => "othername", "emailAddress" => "any@example.com" } } + let!(:existing_user) { create(:user, login: "testname", mail: "any+test@example.com") } + + it "considers the email to be different and does not find it this user account" do + expect(result).to be_empty + end + end + end + describe "#sanitize_name (private)" do subject(:jira_user) { described_class.new(payload: {}) }