Merge branch 'main' into US/doc/privacy-policy-constraints
This commit is contained in:
commit
e60c515e9b
9 changed files with 295 additions and 142 deletions
108
Gemfile.lock
108
Gemfile.lock
|
@ -4,40 +4,40 @@ GEM
|
|||
aasm (5.2.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
acsv (0.0.1)
|
||||
actioncable (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
actioncable (6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activestorage (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
actionmailbox (6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
activejob (= 6.1.4.7)
|
||||
activerecord (= 6.1.4.7)
|
||||
activestorage (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
actionview (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
actionmailer (6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
actionview (= 6.1.4.7)
|
||||
activejob (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.1.4.6)
|
||||
actionview (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
actionpack (6.1.4.7)
|
||||
actionview (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activestorage (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
actiontext (6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
activerecord (= 6.1.4.7)
|
||||
activestorage (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
actionview (6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
|
@ -55,26 +55,26 @@ GEM
|
|||
activemodel (>= 5.2.0)
|
||||
activestorage (>= 5.2.0)
|
||||
activesupport (>= 5.2.0)
|
||||
activejob (6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
activejob (6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
activerecord (6.1.4.6)
|
||||
activemodel (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
activestorage (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
activemodel (6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
activerecord (6.1.4.7)
|
||||
activemodel (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
activestorage (6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
activejob (= 6.1.4.7)
|
||||
activerecord (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
marcel (~> 1.0.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activestorage-openstack (1.5.1)
|
||||
fog-openstack (~> 1.0)
|
||||
marcel
|
||||
rails (>= 5.2.2)
|
||||
activesupport (6.1.4.6)
|
||||
activesupport (6.1.4.7)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
|
@ -502,20 +502,20 @@ GEM
|
|||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (6.1.4.6)
|
||||
actioncable (= 6.1.4.6)
|
||||
actionmailbox (= 6.1.4.6)
|
||||
actionmailer (= 6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
actiontext (= 6.1.4.6)
|
||||
actionview (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activemodel (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activestorage (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
rails (6.1.4.7)
|
||||
actioncable (= 6.1.4.7)
|
||||
actionmailbox (= 6.1.4.7)
|
||||
actionmailer (= 6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
actiontext (= 6.1.4.7)
|
||||
actionview (= 6.1.4.7)
|
||||
activejob (= 6.1.4.7)
|
||||
activemodel (= 6.1.4.7)
|
||||
activerecord (= 6.1.4.7)
|
||||
activestorage (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 6.1.4.6)
|
||||
railties (= 6.1.4.7)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
|
@ -534,9 +534,9 @@ GEM
|
|||
rails-i18n (6.0.0)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 7)
|
||||
railties (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
railties (6.1.4.7)
|
||||
actionpack (= 6.1.4.7)
|
||||
activesupport (= 6.1.4.7)
|
||||
method_source
|
||||
rake (>= 0.13)
|
||||
thor (~> 1.0)
|
||||
|
@ -684,7 +684,7 @@ GEM
|
|||
spring (2.1.1)
|
||||
spring-commands-rspec (1.0.4)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (4.0.2)
|
||||
sprockets (4.0.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.4.2)
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: seed_hidden_at_dossiers'
|
||||
task seed_hidden_at_dossiers: :environment do
|
||||
puts "Running deploy task 'seed_hidden_at_dossiers'"
|
||||
|
||||
Dossier
|
||||
.with_discarded
|
||||
.where.not(hidden_at: nil)
|
||||
.where(hidden_by_user_at: nil, hidden_by_administration_at: nil)
|
||||
.update_all('hidden_by_user_at = hidden_at, hidden_by_administration_at = hidden_at')
|
||||
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
describe Database::MigrationHelpers do
|
||||
describe 'handling duplicates' do
|
||||
class TestLabel < ApplicationRecord
|
||||
end
|
||||
|
||||
|
@ -8,6 +9,10 @@ describe Database::MigrationHelpers do
|
|||
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
|
||||
|
||||
|
@ -87,6 +92,105 @@ describe Database::MigrationHelpers do
|
|||
expect(TestLabel.where(label: 'Done').count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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_orphans(:test_appointments, :test_patients)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
describe '.add_concurrent_index' do
|
||||
let(:model) { ActiveRecord::Migration.new.extend(Database::MigrationHelpers) }
|
||||
|
|
Loading…
Reference in a new issue