diff --git a/app/assets/images/agentconnect-btn-principal-hover.svg b/app/assets/images/agentconnect-btn-principal-hover.svg
new file mode 100644
index 000000000..19dbeb74e
--- /dev/null
+++ b/app/assets/images/agentconnect-btn-principal-hover.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/agentconnect-btn-principal.svg b/app/assets/images/agentconnect-btn-principal.svg
new file mode 100644
index 000000000..d842f6818
--- /dev/null
+++ b/app/assets/images/agentconnect-btn-principal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/franceconnect-btn-hover.svg b/app/assets/images/franceconnect-btn-hover.svg
new file mode 100644
index 000000000..f1a24a139
--- /dev/null
+++ b/app/assets/images/franceconnect-btn-hover.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/franceconnect-btn.svg b/app/assets/images/franceconnect-btn.svg
new file mode 100644
index 000000000..d70581b70
--- /dev/null
+++ b/app/assets/images/franceconnect-btn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/login-with-fc-hover.svg b/app/assets/images/login-with-fc-hover.svg
deleted file mode 100644
index 5a2d16909..000000000
--- a/app/assets/images/login-with-fc-hover.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/app/assets/images/login-with-fc.svg b/app/assets/images/login-with-fc.svg
deleted file mode 100644
index 3a95ff212..000000000
--- a/app/assets/images/login-with-fc.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/app/assets/images/logo-agent-connect.png b/app/assets/images/logo-agent-connect.png
deleted file mode 100644
index 6ad68703c..000000000
Binary files a/app/assets/images/logo-agent-connect.png and /dev/null differ
diff --git a/app/assets/stylesheets/auth.scss b/app/assets/stylesheets/auth.scss
index 410771461..835b8c86f 100644
--- a/app/assets/stylesheets/auth.scss
+++ b/app/assets/stylesheets/auth.scss
@@ -18,7 +18,15 @@
}
.column {
- padding-top: 2 * $default-spacer;
+ padding-top: $default-spacer;
+ }
+
+ h1 {
+ margin-bottom: $default-spacer;
+ }
+
+ .form label {
+ margin-bottom: $default-spacer / 2;
}
}
@@ -26,7 +34,7 @@
.auth-options {
display: flex;
justify-content: space-between;
- margin-bottom: 4 * $default-spacer;
+ margin-bottom: 2 * $default-spacer;
}
.remember-me {
@@ -60,7 +68,7 @@
.sign-in-form .form {
input[type="email"] {
- margin-bottom: $default-padding;
+ margin-bottom: $default-spacer;
}
input[type="password"] {
diff --git a/app/assets/stylesheets/france-connect-agent-login.scss b/app/assets/stylesheets/france-connect-agent-login.scss
index 1d1139385..8b9bf4c6e 100644
--- a/app/assets/stylesheets/france-connect-agent-login.scss
+++ b/app/assets/stylesheets/france-connect-agent-login.scss
@@ -2,10 +2,14 @@
@import "constants";
.france-connect-agent-login-button {
- background-image: image-url("logo-agent-connect.png");
+ background-image: image-url("agentconnect-btn-principal.svg"), image-url("agentconnect-btn-principal-hover.svg");
display: block;
height: 60px;
- width: 230px;
+ width: 206px;
margin: 20px auto;
font-size: 0;
+
+ &:hover {
+ background-image: image-url("agentconnect-btn-principal-hover.svg");
+ }
}
diff --git a/app/assets/stylesheets/france-connect-login.scss b/app/assets/stylesheets/france-connect-login.scss
index 20c66f404..72c5edf87 100644
--- a/app/assets/stylesheets/france-connect-login.scss
+++ b/app/assets/stylesheets/france-connect-login.scss
@@ -19,14 +19,14 @@
width: 230px;
margin: auto;
margin-bottom: 8px;
- background-image: image-url("login-with-fc.svg"), image-url("login-with-fc-hover.svg");
+ background-image: image-url("franceconnect-btn.svg"), image-url("franceconnect-btn-hover.svg");
background-repeat: no-repeat;
background-size: cover;
cursor: pointer;
font-size: 0;
&:hover {
- background-image: image-url("login-with-fc-hover.svg");
+ background-image: image-url("franceconnect-btn-hover.svg");
}
}
@@ -36,8 +36,8 @@
align-items: center;
color: $black;
text-transform: uppercase;
- padding-bottom: $default-padding;
- padding-top: $default-padding;
+ padding-bottom: $default-spacer;
+ padding-top: $default-spacer;
&::before,
&::after {
diff --git a/app/lib/database/migration_helpers.rb b/app/lib/database/migration_helpers.rb
index 07061d888..e0a224d83 100644
--- a/app/lib/database/migration_helpers.rb
+++ b/app/lib/database/migration_helpers.rb
@@ -1,4 +1,4 @@
-# Some of this file is lifted from Gitlab's `lib/gitlab/database/migration_helpers.rb``
+# Some of this file is lifted from Gitlab's `lib/gitlab/database/migration_helpers.rb`
# Copyright (c) 2011-present GitLab B.V.
#
@@ -103,6 +103,34 @@ module Database::MigrationHelpers
end
end
+ # Delete records from `from_table` having a reference to a missing record in `to_table`.
+ # This is useful to rectify data before adding a proper foreign_key.
+ #
+ # Example:
+ #
+ # delete_orphans :appointments, :physicians
+ #
+ def delete_orphans(from_table, to_table)
+ say_with_time "Deleting records from #{from_table} where the associated #{to_table.to_s.singularize} no longer exists" do
+ from_table = Arel::Table.new(from_table)
+ to_table = Arel::Table.new(to_table)
+ foreign_key_column = foreign_key_column_for(to_table.name)
+
+ # Select the ids of orphan records
+ arel_select = from_table
+ .join(to_table, Arel::Nodes::OuterJoin).on(to_table[:id].eq(from_table[foreign_key_column]))
+ .where(to_table[:id].eq(nil))
+ .project(from_table[foreign_key_column])
+ missing_record_ids = query_values(arel_select.to_sql)
+
+ # Delete the records having ids referencing missing data
+ arel_delete = Arel::DeleteManager.new()
+ .from(from_table)
+ .where(from_table[foreign_key_column].in(missing_record_ids.uniq))
+ exec_delete(arel_delete.to_sql)
+ end
+ end
+
private
def statement_timeout_disabled?
diff --git a/app/models/procedure.rb b/app/models/procedure.rb
index d3be28e47..a7cc0e1a9 100644
--- a/app/models/procedure.rb
+++ b/app/models/procedure.rb
@@ -176,7 +176,7 @@ class Procedure < ApplicationRecord
end
end
- has_many :administrateurs_procedures
+ has_many :administrateurs_procedures, dependent: :delete_all
has_many :administrateurs, through: :administrateurs_procedures, after_remove: -> (procedure, _admin) { procedure.validate! }
has_many :groupe_instructeurs, dependent: :destroy
has_many :instructeurs, through: :groupe_instructeurs
diff --git a/app/views/administrateurs/dossier_submitted_messages/_informations.html.haml b/app/views/administrateurs/dossier_submitted_messages/_informations.html.haml
index f5ae76910..fa06d1c84 100644
--- a/app/views/administrateurs/dossier_submitted_messages/_informations.html.haml
+++ b/app/views/administrateurs/dossier_submitted_messages/_informations.html.haml
@@ -1,3 +1,3 @@
= f.label :message_on_submit_by_usager do
- Message affiché après l'envoie du dossier
-= f.text_area :message_on_submit_by_usager, placeholder: "Merci votre dossier sera traité dans les plus bref delais"
+ Message affiché après l'envoi du dossier
+= f.text_area :message_on_submit_by_usager, placeholder: "Merci, votre dossier sera traité dans les plus bref delais"
diff --git a/app/views/administrateurs/procedures/show.html.haml b/app/views/administrateurs/procedures/show.html.haml
index 05b43bcbe..6dd302899 100644
--- a/app/views/administrateurs/procedures/show.html.haml
+++ b/app/views/administrateurs/procedures/show.html.haml
@@ -246,6 +246,6 @@
%p.card-admin-status-todo À configurer
%div
%p.card-admin-title Fin de dépot
- %p.card-admin-subtitle Orienter l'usager suite à l'envoie de son dossier
+ %p.card-admin-subtitle Orienter l'usager suite à l'envoi de son dossier
%p.button Modifier
diff --git a/app/views/users/sessions/new.html.haml b/app/views/users/sessions/new.html.haml
index 42811868a..bfebfda9f 100644
--- a/app/views/users/sessions/new.html.haml
+++ b/app/views/users/sessions/new.html.haml
@@ -27,6 +27,5 @@
.france-connect-login-separator
= t('views.shared.france_connect_login.separator')
.center
- %h2.important-header= t('views.users.sessions.new.state_civil_servant')
- %br
+ %h2.important-header.mb-1= t('views.users.sessions.new.state_civil_servant')
= link_to t('views.users.sessions.new.connect_with_agent_connect'), agent_connect_path, class: "button expend secondary"
diff --git a/config/locales/views/agent_connect/agent/en.yml b/config/locales/views/agent_connect/agent/en.yml
index a7b89e3ae..c58228f81 100644
--- a/config/locales/views/agent_connect/agent/en.yml
+++ b/config/locales/views/agent_connect/agent/en.yml
@@ -11,7 +11,7 @@ en:
The ministries and operators that can currently benefit from it are :
-
the Ministry of Ecological Transition
+
the Insee
you_are_a_citizen: You are an individual ?
citizen_page: Go to our dedicated page
diff --git a/config/locales/views/agent_connect/agent/fr.yml b/config/locales/views/agent_connect/agent/fr.yml
index a81ac0c1e..67d8a5c35 100644
--- a/config/locales/views/agent_connect/agent/fr.yml
+++ b/config/locales/views/agent_connect/agent/fr.yml
@@ -8,10 +8,10 @@ fr:
AgentConnect est en cours de déploiement.
- Les ministères et opérateurs qui peuvent l'utiliser à ce jour sont :
+ Les ministères et opérateurs qui peuvent lʼutiliser à ce jour sont :
-
le ministère de la Transition écologique
+
lʼInsee
you_are_a_citizen: Vous êtes un particulier ?
citizen_page: Accéder à notre page dédiée
diff --git a/config/locales/views/shared/en.yml b/config/locales/views/shared/en.yml
index a6788d90b..5770dd40f 100644
--- a/config/locales/views/shared/en.yml
+++ b/config/locales/views/shared/en.yml
@@ -11,7 +11,7 @@ en:
en_attente: "Waiting for response"
france_connect_login:
title: "With FranceConnect"
- description: "France connect is a solution proposed by the government to secure and simplify the connection to web services."
+ description: "FranceConnect is a solution proposed by the government to secure and simplify the connection to web services."
login_button: "Sign in with FranceConnect"
help_link: What is FranceConnect?
separator: or
diff --git a/config/locales/views/shared/fr.yml b/config/locales/views/shared/fr.yml
index 5ee3f4ecd..8325949e8 100644
--- a/config/locales/views/shared/fr.yml
+++ b/config/locales/views/shared/fr.yml
@@ -11,7 +11,7 @@ fr:
en_attente: "En attente de réponse"
france_connect_login:
title: 'Avec FranceConnect'
- description: "France connect est la solution proposée par l’État pour sécuriser et simplifier la connexion aux services en ligne."
+ description: "FranceConnect est la solution proposée par l’État pour sécuriser et simplifier la connexion aux services en ligne."
login_button: "S’identifier avec FranceConnect"
help_link: "Qu’est-ce que FranceConnect ?"
separator: 'ou'
diff --git a/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb b/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb
index d8d0bbb0a..944940df1 100644
--- a/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb
+++ b/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb
@@ -1,12 +1,9 @@
class AddAdministrateurForeignKeyToAdministrateursProcedure < ActiveRecord::Migration[6.1]
- def up
- # Sanity check
- say_with_time 'Removing AdministrateursProcedures where the associated Administrateur no longer exists ' do
- deleted_administrateur_ids = AdministrateursProcedure.where.missing(:administrateur).pluck(:administrateur_id)
- AdministrateursProcedure.where(administrateur_id: deleted_administrateur_ids).delete_all
- end
+ include Database::MigrationHelpers
- add_foreign_key :administrateurs_procedures, :administrateurs
+ def up
+ delete_orphans :administrateurs_procedures, :administrateurs_procedures
+ add_foreign_key :administrateurs_procedures, :administrateurs_procedures
end
def down
diff --git a/db/migrate/20220302101337_add_foreign_keys_to_administrateurs_instructeurs.rb b/db/migrate/20220302101337_add_foreign_keys_to_administrateurs_instructeurs.rb
index fc524565f..ae863654d 100644
--- a/db/migrate/20220302101337_add_foreign_keys_to_administrateurs_instructeurs.rb
+++ b/db/migrate/20220302101337_add_foreign_keys_to_administrateurs_instructeurs.rb
@@ -1,17 +1,11 @@
class AddForeignKeysToAdministrateursInstructeurs < ActiveRecord::Migration[6.1]
+ include Database::MigrationHelpers
+
def up
- # Sanity check
- say_with_time 'Removing AdministrateursInstructeur where the associated Administrateur no longer exists ' do
- deleted_administrateurs_ids = AdministrateursInstructeur.where.missing(:administrateur).pluck(:administrateur_id)
- AdministrateursInstructeur.where(administrateur_id: deleted_administrateurs_ids).delete_all
- end
-
- say_with_time 'Removing AdministrateursInstructeur where the associated Instructeur no longer exists ' do
- deleted_instructeurs_ids = AdministrateursInstructeur.where.missing(:instructeur).pluck(:instructeur_id)
- AdministrateursInstructeur.where(instructeur_id: deleted_instructeurs_ids).delete_all
- end
-
+ delete_orphans :administrateurs_instructeurs, :administrateurs
add_foreign_key :administrateurs_instructeurs, :administrateurs
+
+ delete_orphans :administrateurs_instructeurs, :instructeurs
add_foreign_key :administrateurs_instructeurs, :instructeurs
end
diff --git a/db/migrate/20220308110720_add_procedure_foreign_key_to_administrateurs_procedure.rb b/db/migrate/20220308110720_add_procedure_foreign_key_to_administrateurs_procedure.rb
new file mode 100644
index 000000000..2b6fc5304
--- /dev/null
+++ b/db/migrate/20220308110720_add_procedure_foreign_key_to_administrateurs_procedure.rb
@@ -0,0 +1,12 @@
+class AddProcedureForeignKeyToAdministrateursProcedure < ActiveRecord::Migration[6.1]
+ include Database::MigrationHelpers
+
+ def up
+ delete_orphans :administrateurs_procedures, :procedures
+ add_foreign_key :administrateurs_procedures, :procedures
+ end
+
+ def down
+ remove_foreign_key :administrateurs_procedures, :procedures
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 16c13c8d7..3e2d4a1f7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2022_03_02_101337) do
+ActiveRecord::Schema.define(version: 2022_03_08_110720) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -855,6 +855,7 @@ ActiveRecord::Schema.define(version: 2022_03_02_101337) do
add_foreign_key "administrateurs_instructeurs", "administrateurs"
add_foreign_key "administrateurs_instructeurs", "instructeurs"
add_foreign_key "administrateurs_procedures", "administrateurs"
+ add_foreign_key "administrateurs_procedures", "procedures"
add_foreign_key "archives_groupe_instructeurs", "archives"
add_foreign_key "archives_groupe_instructeurs", "groupe_instructeurs"
add_foreign_key "assign_tos", "groupe_instructeurs"
diff --git a/spec/lib/database/migration_helpers_spec.rb b/spec/lib/database/migration_helpers_spec.rb
index 4fab02099..1ca896cfb 100644
--- a/spec/lib/database/migration_helpers_spec.rb
+++ b/spec/lib/database/migration_helpers_spec.rb
@@ -1,90 +1,194 @@
describe Database::MigrationHelpers do
- class TestLabel < ApplicationRecord
- end
+ describe 'handling duplicates' do
+ class TestLabel < ApplicationRecord
+ end
- before(:all) do
- ActiveRecord::Migration.suppress_messages do
- ActiveRecord::Migration.create_table "test_labels", force: true do |t|
- t.string :label
- t.integer :user_id
+ before(:all) do
+ ActiveRecord::Migration.suppress_messages do
+ ActiveRecord::Migration.create_table "test_labels", force: true do |t|
+ t.string :label
+ t.integer :user_id
+ end
+ ActiveRecord::Migration.create_table "test_labels", force: true do |t|
+ t.string :label
+ t.integer :user_id
+ end
end
end
- end
- before(:each) do
- # User 1 labels
- TestLabel.create({ id: 1, label: 'Important', user_id: 1 })
- TestLabel.create({ id: 2, label: 'Urgent', user_id: 1 })
- TestLabel.create({ id: 3, label: 'Done', user_id: 1 })
- TestLabel.create({ id: 4, label: 'Bug', user_id: 1 })
+ before(:each) do
+ # User 1 labels
+ TestLabel.create({ id: 1, label: 'Important', user_id: 1 })
+ TestLabel.create({ id: 2, label: 'Urgent', user_id: 1 })
+ TestLabel.create({ id: 3, label: 'Done', user_id: 1 })
+ TestLabel.create({ id: 4, label: 'Bug', user_id: 1 })
- # User 2 labels
- TestLabel.create({ id: 5, label: 'Important', user_id: 2 })
- TestLabel.create({ id: 6, label: 'Critical', user_id: 2 })
+ # User 2 labels
+ TestLabel.create({ id: 5, label: 'Important', user_id: 2 })
+ TestLabel.create({ id: 6, label: 'Critical', user_id: 2 })
- # Duplicates
- TestLabel.create({ id: 7, label: 'Urgent', user_id: 1 })
- TestLabel.create({ id: 8, label: 'Important', user_id: 2 })
- end
-
- after(:all) do
- ActiveRecord::Migration.suppress_messages do
- ActiveRecord::Migration.drop_table :test_labels, force: true
+ # Duplicates
+ TestLabel.create({ id: 7, label: 'Urgent', user_id: 1 })
+ TestLabel.create({ id: 8, label: 'Important', user_id: 2 })
end
- end
- let(:model) { ActiveRecord::Migration.new.extend(Database::MigrationHelpers) }
+ after(:all) do
+ ActiveRecord::Migration.suppress_messages do
+ ActiveRecord::Migration.drop_table :test_labels, force: true
+ end
+ end
- describe '.find_duplicates' do
- context 'using a single column for uniqueness' do
+ let(:model) { ActiveRecord::Migration.new.extend(Database::MigrationHelpers) }
+
+ describe '.find_duplicates' do
+ context 'using a single column for uniqueness' do
+ subject do
+ model.find_duplicates(:test_labels, [:label])
+ end
+
+ it 'finds duplicates' do
+ expect(subject.length).to eq 2
+ end
+
+ it 'finds three labels with "Important"' do
+ expect(subject).to include [1, 5, 8]
+ end
+
+ it 'finds two labels with "Urgent"' do
+ expect(subject).to include [2, 7]
+ end
+ end
+
+ context 'using multiple columns for uniqueness' do
+ subject do
+ model.find_duplicates(:test_labels, [:label, :user_id])
+ end
+
+ it 'finds duplicates' do
+ expect(subject.length).to eq 2
+ end
+
+ it 'finds two labels with "Important" for user 2' do
+ expect(subject).to include [5, 8]
+ end
+
+ it 'finds two labels with "Urgent" for user 1' do
+ expect(subject).to include [2, 7]
+ end
+ end
+ end
+
+ describe '.delete_duplicates' do
subject do
- model.find_duplicates(:test_labels, [:label])
+ model.delete_duplicates(:test_labels, [:label])
end
- it 'finds duplicates' do
- expect(subject.length).to eq 2
- end
-
- it 'finds three labels with "Important"' do
- expect(subject).to include [1, 5, 8]
- end
-
- it 'finds two labels with "Urgent"' do
- expect(subject).to include [2, 7]
- end
- end
-
- context 'using multiple columns for uniqueness' do
- subject do
- model.find_duplicates(:test_labels, [:label, :user_id])
- end
-
- it 'finds duplicates' do
- expect(subject.length).to eq 2
- end
-
- it 'finds two labels with "Important" for user 2' do
- expect(subject).to include [5, 8]
- end
-
- it 'finds two labels with "Urgent" for user 1' do
- expect(subject).to include [2, 7]
+ it 'keeps the first item, and delete the others' do
+ expect { subject }.to change(TestLabel, :count).by(-3)
+ expect(TestLabel.where(label: 'Critical').count).to eq(1)
+ expect(TestLabel.where(label: 'Important').count).to eq(1)
+ expect(TestLabel.where(label: 'Urgent').count).to eq(1)
+ expect(TestLabel.where(label: 'Bug').count).to eq(1)
+ expect(TestLabel.where(label: 'Done').count).to eq(1)
end
end
end
- describe '.delete_duplicates' do
+ describe '.delete_orphans' do
+ class TestPhysician < ApplicationRecord; end
+
+ class TestPatient < ApplicationRecord; end
+
+ class TestAppointment < ApplicationRecord; end
+
+ before(:all) do
+ ActiveRecord::Migration.suppress_messages do
+ ActiveRecord::Migration.create_table "test_physicians", force: true do |t|
+ t.string :name
+ end
+ ActiveRecord::Migration.create_table "test_patients", force: true do |t|
+ t.string :name
+ end
+ ActiveRecord::Migration.create_table "test_appointments", id: false, force: true do |t|
+ t.integer :test_physician_id
+ t.integer :test_patient_id
+ t.datetime :datetime
+ end
+ end
+ end
+
+ after(:all) do
+ ActiveRecord::Migration.suppress_messages do
+ ActiveRecord::Migration.drop_table :test_physicians, force: true
+ ActiveRecord::Migration.drop_table :test_patients, force: true
+ ActiveRecord::Migration.drop_table :test_appointments, force: true
+ end
+ end
+
+ let(:model) { ActiveRecord::Migration.new.extend(Database::MigrationHelpers) }
+
subject do
- model.delete_duplicates(:test_labels, [:label])
+ model.delete_orphans(:test_appointments, :test_patients)
end
- it 'keeps the first item, and delete the others' do
- expect { subject }.to change(TestLabel, :count).by(-3)
- expect(TestLabel.where(label: 'Critical').count).to eq(1)
- expect(TestLabel.where(label: 'Important').count).to eq(1)
- expect(TestLabel.where(label: 'Urgent').count).to eq(1)
- expect(TestLabel.where(label: 'Bug').count).to eq(1)
- expect(TestLabel.where(label: 'Done').count).to eq(1)
+ context 'when there are orphan records' do
+ before(:each) do
+ phy1 = TestPhysician.create({ name: 'Ibn Sina' })
+ phy2 = TestPhysician.create({ name: 'Louis Pasteur' })
+ pa1 = TestPatient.create({ name: 'Chams ad-Dawla' })
+ pa2 = TestPatient.create({ name: 'Joseph Meister' })
+ ap1 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: pa1.id, datetime: 2.months.ago })
+ ap2 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: pa1.id, datetime: 1.month.ago })
+ ap3 = TestAppointment.create({ test_physician_id: phy2.id, test_patient_id: pa2.id, datetime: 2.days.ago })
+ ap4 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: pa2.id, datetime: 1.day.ago })
+ ap5 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: pa1.id, datetime: Time.zone.today })
+
+ # Appointments missing the associated patient
+ ap6 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: 9999, datetime: 3.months.ago })
+ ap7 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: 8888, datetime: 2.months.ago })
+ ap8 = TestAppointment.create({ test_physician_id: phy2.id, test_patient_id: 8888, datetime: 1.month.ago })
+
+ # Appointments missing the associated physician
+ ap9 = TestAppointment.create({ test_physician_id: 7777, test_patient_id: pa1.id, datetime: 3.months.ago })
+ end
+
+ it 'deletes orphaned records on the specified key' do
+ expect { subject }.to change { TestAppointment.count }.by(-3)
+
+ # rubocop:disable Rails/WhereEquals
+ appointments_with_missing_patients = TestAppointment
+ .joins('LEFT OUTER JOIN test_patients ON test_patients.id = test_appointments.test_patient_id')
+ .where('test_patients.id IS NULL')
+ # rubocop:enable Rails/WhereEquals
+ expect(appointments_with_missing_patients.count).to eq(0)
+ end
+
+ it 'keeps orphaned records on another key' do
+ subject
+
+ # rubocop:disable Rails/WhereEquals
+ appointments_with_missing_physicians = TestAppointment
+ .joins('LEFT OUTER JOIN test_physicians ON test_physicians.id = test_appointments.test_physician_id')
+ .where('test_physicians.id IS NULL')
+ # rubocop:enable Rails/WhereEquals
+ expect(appointments_with_missing_physicians.count).not_to eq(0)
+ end
+
+ it 'keeps valid associated records' do
+ expect { subject }.not_to change { [TestPhysician.count, TestPatient.count] }
+ end
+ end
+
+ context 'when there are no orphaned records' do
+ before(:each) do
+ phy1 = TestPhysician.create({ name: 'Ibn Sina' })
+ pa1 = TestPatient.create({ name: 'Chams ad-Dawla' })
+ ap1 = TestAppointment.create({ test_physician_id: phy1.id, test_patient_id: pa1.id, datetime: 2.months.ago })
+ end
+
+ it 'doesn’t remove any records' do
+ expect { subject }.not_to change { [TestPhysician.count, TestPatient.count, TestAppointment.count] }
+ end
end
end