panda_pal 5.11.0 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75028dd065a6203af07a828ad23b78340b2b98c467ddc4def4b3935b6af31f15
4
- data.tar.gz: dda65af42c0372f49c029508f9701093b99b81ca76c3cefa5448a35ba776031a
3
+ metadata.gz: ab899936461dc59208ae6afef28264feda7a75927798e158ca1ee8381b2ea463
4
+ data.tar.gz: 20424ac6bef9bede8af9e58e8a1393267b0966f96cf56dd8ae8ed0e5b486420a
5
5
  SHA512:
6
- metadata.gz: 911ca0334b047224f269121dd0a65e363c6239d763b73ef7ada18c439a66f29a11c51eae57ca1edfa8ffe18aa6b88bd7677aa41a5239c3517a2bc286668d30be
7
- data.tar.gz: 25e362c44747b95d1316bec3c50ed508d6bf125a4b62328d1bc0c1a5bc1a498013d67db896422ff2e526ce111a29338f02481972b0a2fbe28d743baa4015ac07
6
+ metadata.gz: 85041955aabe8255fcf0a4e3cbcfce3c55c690e0d66d74ac511d6b4d70825d796a62a18fe3ac3e0b5dc66e9ddc865c5b45f672940d92c15a1cc38a7ac350ad91
7
+ data.tar.gz: bcbe2513a4b4916af671f5a913036e0154dd474d510351f6325a2f264d03c1dac10adc4c48bc060c40faafdc798268664c48e2c32943dd4ed3d0dcda076b7ff3
data/README.md CHANGED
@@ -179,6 +179,18 @@ Rails.application.config.middleware.use 'Apartment::Elevators::Generic', lambda
179
179
  It is also possible to switch tenants by implementing `around_action :switch_tenant` in the controller.
180
180
  However, it should be noted that calling `switch_tenant` must be used in an `around_action` hook (or given a block), and is only intended to be used for LTI launches, and not subsequent requests.
181
181
 
182
+ ### Sharding
183
+ PandaPal 5.12 added support for multi-DB sharding. If you wish to use this, add a `shard` column to the `PandaPal::Organization` model. The implementation should be fairly transparent and should behave as normal PandaPal/Apartment - the only difference is that tenants can be created on different DB shards.
184
+
185
+ The list of available shards is computed from the Environment variables. On startup, the application looks for variables with the following formats:
186
+ - `SHARD_DB_XYZ_URL`
187
+ - `HEROKU_POSTGRESQL_XYZ_URL`
188
+ (where `XYZ` is the shard identifier)
189
+
190
+ When an `Organization` is created, it is assigned to a random shard (or if no shards were discovered, it is placed in the default database as normal). Alternatively, a specific shard can be specified: `PandaPal::Organization.new(shard: "shard_a")`. An `Organization` can be added to the primary shard with `shard: "default"`
191
+
192
+ The `PandaPal::Organization` record is still created in the `public` schema of the default database, as per usual.
193
+
182
194
  ### Rake tasks and jobs
183
195
  **Delayed Job Support has been removed. This allows each project to assess it's need to handle background jobs.**
184
196
 
@@ -41,6 +41,9 @@ module PandaPal
41
41
  include OrganizationConcerns::OrganizationBuilder if $stdin&.tty?
42
42
  include OrganizationConcerns::TaskScheduling if defined?(Sidekiq.schedule)
43
43
 
44
+ include OrganizationConcerns::TenantHandling
45
+ include OrganizationConcerns::MultiDatabaseSharding if (column_names rescue []).include?('shard')
46
+
44
47
  attr_encrypted :settings, marshal: true, key: :encryption_key, marshaler: SettingsMarshaler
45
48
  before_save {|a| a.settings = a.settings} # this is a hacky work-around to a bug where attr_encrypted is not saving settings in place
46
49
 
@@ -56,9 +59,6 @@ module PandaPal
56
59
  validates :canvas_account_id, presence: true
57
60
  validates :salesforce_id, presence: true, uniqueness: true
58
61
 
59
- after_create :create_schema
60
- after_commit :destroy_schema, on: :destroy
61
-
62
62
  define_setting("lti", {
63
63
  type: 'Hash',
64
64
  required: false,
@@ -71,10 +71,6 @@ module PandaPal
71
71
  end
72
72
  end
73
73
 
74
- before_validation on: [:update] do
75
- errors.add(:name, 'should not be changed after creation') if name_changed?
76
- end
77
-
78
74
  def encryption_key
79
75
  # production environment might not have loaded secret_key_base yet.
80
76
  # In that case, just read it from env.
@@ -85,18 +81,6 @@ module PandaPal
85
81
  end
86
82
  end
87
83
 
88
- def switch_tenant(&block)
89
- if block_given?
90
- Apartment::Tenant.switch(name, &block)
91
- else
92
- Apartment::Tenant.switch!(name)
93
- end
94
- end
95
-
96
- def self.current
97
- find_by_name(Apartment::Tenant.current)
98
- end
99
-
100
84
  def create_api(logic, expiration: nil, uses: nil, host: nil)
101
85
  switch_tenant do
102
86
  logic = "current_organization.#{logic}" if logic.is_a?(Symbol)
@@ -109,16 +93,6 @@ module PandaPal
109
93
  end
110
94
  end
111
95
 
112
- def rename!(new_name)
113
- do_switch = Apartment::Tenant.current == name
114
- ActiveRecord::Base.connection.execute(
115
- "ALTER SCHEMA \"#{name}\" RENAME TO \"#{new_name}\";"
116
- )
117
- self.class.where(id: id).update_all(name: new_name)
118
- reload
119
- switch_tenant if do_switch
120
- end
121
-
122
96
  if !PandaPal.lti_options[:platform].present? || PandaPal.lti_options[:platform].is_a?(String)
123
97
  CONST_PLATFORM_TYPE = Platform.resolve_platform_class(nil) rescue nil
124
98
  else
@@ -192,16 +166,6 @@ module PandaPal
192
166
  CONST_PLATFORM_TYPE
193
167
  end
194
168
 
195
- private
196
-
197
- def create_schema
198
- Apartment::Tenant.create name
199
- end
200
-
201
- def destroy_schema
202
- Apartment::Tenant.drop name
203
- end
204
-
205
169
  public
206
170
 
207
171
  PandaPal.resolved_extensions_for(self).each do |ext|
@@ -0,0 +1,22 @@
1
+ module PandaPal
2
+ module OrganizationConcerns
3
+ module MultiDatabaseSharding
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ if column_names.include?('shard')
8
+ validates :shard, format: { with: /\A[a-z0-9_]+\z/i }, allow_blank: true
9
+
10
+ before_validation on: [:update] do
11
+ errors.add(:shard, 'should not be changed after creation') if shard_changed?
12
+ end
13
+ end
14
+ end
15
+
16
+ def tenant_name
17
+ return "#{shard}:#{name}" if shard.present?
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,54 @@
1
+ module PandaPal
2
+ module OrganizationConcerns
3
+ module TenantHandling
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ def current
8
+ find_by_name(Apartment::Tenant.current)
9
+ end
10
+ end
11
+
12
+ included do
13
+ after_create :create_schema
14
+ after_commit :destroy_schema, on: :destroy
15
+
16
+ before_validation on: [:update] do
17
+ errors.add(:name, 'should not be changed after creation') if name_changed?
18
+ end
19
+ end
20
+
21
+ def tenant_name
22
+ name
23
+ end
24
+
25
+ def switch_tenant(&block)
26
+ if block_given?
27
+ Apartment::Tenant.switch(tenant_name, &block)
28
+ else
29
+ Apartment::Tenant.switch!(tenant_name)
30
+ end
31
+ end
32
+
33
+ def rename!(new_name)
34
+ do_switch = Apartment::Tenant.current == name
35
+ ActiveRecord::Base.connection.execute(
36
+ "ALTER SCHEMA \"#{name}\" RENAME TO \"#{new_name}\";"
37
+ )
38
+ self.class.where(id: id).update_all(name: new_name)
39
+ reload
40
+ switch_tenant if do_switch
41
+ end
42
+
43
+ private
44
+
45
+ def create_schema
46
+ Apartment::Tenant.create tenant_name
47
+ end
48
+
49
+ def destroy_schema
50
+ Apartment::Tenant.drop tenant_name
51
+ end
52
+ end
53
+ end
54
+ end
@@ -5,13 +5,212 @@ begin
5
5
  rescue LoadError
6
6
  end
7
7
 
8
+ require "apartment/adapters/postgresql_adapter"
9
+
10
+ module Apartment
11
+ SHARD_PREFIXES = ["SHARD_DB", "HEROKU_POSTGRESQL"]
12
+
13
+ def self.shard_configurations
14
+ $shard_configurations ||= begin
15
+ shard_to_env = {}
16
+
17
+ ENV.keys.each do |k|
18
+ m = /^(#{SHARD_PREFIXES.join("|")})_(\w+)_URL$/.match(k)
19
+ next unless m
20
+
21
+ url = ENV[k]
22
+ shard_to_env[m[2].downcase] = ActiveRecord::Base.configurations.resolve(url).configuration_hash
23
+ end
24
+
25
+ shard_to_env.freeze unless Rails.env.test?
26
+
27
+ shard_to_env
28
+ end
29
+ end
30
+
31
+ module Tenant
32
+ self.singleton_class.send(:alias_method, :original_postgresql_adapter, :postgresql_adapter)
33
+
34
+ def self.postgresql_adapter(config)
35
+ if Apartment.with_multi_server_setup
36
+ adapter = Adapters::PostgresMultiDBSchemaAdapter
37
+ adapter.new(config)
38
+ else
39
+ original_postgresql_adapter(config)
40
+ end
41
+ end
42
+
43
+ def self.split_tenant(tenant)
44
+ bits = tenant.split(":", 2)
45
+ bits.unshift(nil) if bits.length == 1
46
+ bits[0] = "default" if bits[0].nil? || bits[0].empty?
47
+ bits
48
+ end
49
+ end
50
+
51
+ module Adapters
52
+ class PostgresMultiDBSchemaAdapter < Apartment::Adapters::PostgresqlSchemaAdapter
53
+ def initialize(*args, **kwargs)
54
+ super
55
+ @excluded_model_set = Set.new(Apartment.excluded_models)
56
+ end
57
+
58
+ def process_excluded_model(excluded_model)
59
+ @excluded_model_set << excluded_model
60
+ super
61
+ end
62
+
63
+ def is_excluded_model?(model)
64
+ @excluded_model_set.include?(model.to_s)
65
+ end
66
+
67
+ def db_connection_config(tenant)
68
+ shard, schema = Tenant.split_tenant(tenant)
69
+ if shard == "default"
70
+ @config
71
+ else
72
+ Apartment.shard_configurations[shard.downcase]
73
+ end
74
+ end
75
+
76
+ def drop_command(conn, tenant)
77
+ shard, schema = Tenant.split_tenant(tenant)
78
+ conn.execute(%(DROP SCHEMA "#{schema}" CASCADE))
79
+ end
80
+
81
+ def tenant_exists?(tenant)
82
+ return true unless Apartment.tenant_presence_check
83
+ shard, schema = Tenant.split_tenant(tenant)
84
+
85
+ Apartment.connection.schema_exists?(schema)
86
+ end
87
+
88
+ def create_tenant_command(conn, tenant)
89
+ shard, schema = Tenant.split_tenant(tenant)
90
+ # NOTE: This was causing some tests to fail because of the database strategy for rspec
91
+ if conn.open_transactions.positive?
92
+ conn.execute(%(CREATE SCHEMA "#{schema}")).inspect
93
+ else
94
+ schema = %(BEGIN;
95
+ CREATE SCHEMA "#{schema}";
96
+ COMMIT;)
97
+
98
+ conn.execute(schema)
99
+ end
100
+ rescue *rescuable_exceptions => e
101
+ rollback_transaction(conn)
102
+ raise e
103
+ end
104
+
105
+ def connect_to_new(tenant = nil)
106
+ return reset if tenant.nil?
107
+
108
+ current_tenant = @current
109
+ tenants_array = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s
110
+ tenant_schemas = map_to_schemas(Array(tenants_array))
111
+ query_cache_enabled = ActiveRecord::Base.connection.query_cache_enabled
112
+
113
+ @current = tenants_array
114
+
115
+ raise ActiveRecord::StatementInvalid, "PandaPal/Apartment Mutli-DB support does not currently support DB roles" if ActiveRecord::Base.current_role != ActiveRecord::Base.default_role
116
+
117
+ unless ActiveRecord::Base.connected?
118
+ Apartment.establish_connection multi_tenantify(tenant, false)
119
+ Apartment.connection.verify!
120
+ end
121
+
122
+ Apartment.connection.enable_query_cache! if query_cache_enabled
123
+
124
+ raise ActiveRecord::StatementInvalid, "Could not find schema for tenant #{tenant} (#{tenant_schemas.inspect})" unless schema_exists?(tenant_schemas)
125
+
126
+ Apartment.connection.schema_search_path = full_search_path
127
+ rescue *rescuable_exceptions => e
128
+ @current = current_tenant
129
+ raise_schema_connect_to_new(tenant, e)
130
+ end
131
+
132
+ protected
133
+
134
+ def persistent_schemas
135
+ map_to_schemas(super)
136
+ end
137
+
138
+ def map_to_schemas(tenants)
139
+ all_shard = nil
140
+ tenants.map do |schema|
141
+ shard, schema = Tenant.split_tenant(schema)
142
+ all_shard ||= shard
143
+ raise "Cannot mix shards in persistent_schemas" if shard != all_shard
144
+ schema
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ module CorePatches
151
+ module ActiveRecord
152
+ module FutureResult
153
+ # called in the original thread that knows the tenant
154
+ def initialize(_pool, *_args, **_kwargs)
155
+ @tenant = Apartment::Tenant.current
156
+ super
157
+ end
158
+
159
+ # called in the new thread with a connection that needs switching
160
+ def exec_query(_conn, *_args, **_kwargs)
161
+ Apartment::Tenant.switch!(@tenant) unless Apartment::Tenant.current == @tenant
162
+ super
163
+ end
164
+ end
165
+
166
+ module Base
167
+ extend ActiveSupport::Concern
168
+
169
+ included do
170
+ self.singleton_class.send(:alias_method, :pre_apartment_current_shard, :current_shard)
171
+
172
+ def self.current_shard
173
+ # This implementation is definitely a hack, but it should be fairly compatible. If you need to leverage
174
+ # Rails' sharding natively - you should just need to add models to the excluded_models list in Apartment
175
+ # to effectively disable this patch for that model.
176
+ if (adapter = Thread.current[:apartment_adapter]) && adapter.is_a?(Apartment::Adapters::PostgresMultiDBSchemaAdapter) && !adapter.is_excluded_model?(self)
177
+ shard, schema = Apartment::Tenant.split_tenant(adapter.current)
178
+ return "apt:#{shard}" unless shard == "default"
179
+ end
180
+
181
+ pre_apartment_current_shard
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
187
+
188
+ # Fix Apartment's lack of support for load_async
189
+ ::ActiveRecord::FutureResult.prepend CorePatches::ActiveRecord::FutureResult
190
+
191
+ # Hack ActiveRecord shards/connection_pooling to support our multi-DB approach
192
+ ::ActiveRecord::Base.include CorePatches::ActiveRecord::Base
193
+ end
194
+
8
195
  Apartment.configure do |config|
9
196
  config.excluded_models ||= []
10
197
  config.excluded_models |= ['PandaPal::Organization', 'PandaPal::Session']
11
198
 
12
- config.tenant_names = lambda {
13
- PandaPal::Organization.pluck(:name)
14
- }
199
+ config.with_multi_server_setup = true unless Rails.env.test?
200
+
201
+ config.tenant_names = lambda do
202
+ if PandaPal::Organization < PandaPal::OrganizationConcerns::MultiDatabaseSharding
203
+ base_config = Apartment.connection_config
204
+ shard_configurations = Apartment.shard_configurations
205
+
206
+ PandaPal::Organization.all.to_a.each_with_object({}) do |org, hash|
207
+ shard = org.shard || "default"
208
+ hash[org.tenant_name] = shard == "default" ? base_config : shard_configurations[shard.downcase]
209
+ end
210
+ else
211
+ PandaPal::Organization.pluck(:name)
212
+ end
213
+ end
15
214
  end
16
215
 
17
216
  Rails.application.config.middleware.use Apartment::Elevators::Generic, lambda { |request|
@@ -7,8 +7,6 @@ require_relative './helpers/console_helpers'
7
7
 
8
8
  module PandaPal
9
9
  class Engine < ::Rails::Engine
10
- config.autoload_once_paths += Dir["#{config.root}/lib/**/"]
11
-
12
10
  isolate_namespace PandaPal
13
11
 
14
12
  config.generators do |g|
@@ -0,0 +1,82 @@
1
+ module PandaPal::SpecHelper
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def with_multiple_shards(shards:, preclean_schemas: [], determine_shard: nil, transactional: true)
6
+ self.use_transactional_tests = transactional
7
+
8
+ original_settings = {}
9
+
10
+ before :all do
11
+ if defined?(DatabaseCleaner)
12
+ original_settings[:cleaner_strategy] = DatabaseCleaner.strategy
13
+ DatabaseCleaner.strategy = :truncation
14
+ end
15
+
16
+ Apartment.configure do |config|
17
+ original_settings[:with_multi_server_setup] = config.with_multi_server_setup
18
+ config.with_multi_server_setup = true
19
+ end
20
+
21
+ shards.each do |k, v|
22
+ Apartment.shard_configurations[k.to_s] = Apartment.connection_config.merge(database: v)
23
+ end
24
+
25
+ @existing_org_ids = PandaPal::Organization.pluck(:id)
26
+
27
+ Apartment::Tenant.reload!
28
+
29
+ clean_schemas(preclean_schemas)
30
+ end
31
+
32
+ after :all do
33
+ Apartment::Tenant.reset
34
+
35
+ Apartment.configure do |config|
36
+ config.with_multi_server_setup = false
37
+ end
38
+
39
+ shards.each do |k, _|
40
+ Apartment.shard_configurations.delete(k.to_s)
41
+ end
42
+
43
+ PandaPal::Organization.where.not(id: @existing_org_ids).delete_all
44
+
45
+ if defined?(DatabaseCleaner)
46
+ DatabaseCleaner.strategy = original_settings[:cleaner_strategy]
47
+ end
48
+ end
49
+
50
+ before :each do
51
+ clean_schemas(preclean_schemas) unless transactional
52
+
53
+ @each_existing_org_ids = PandaPal::Organization.pluck(:id)
54
+
55
+ if determine_shard
56
+ allow_any_instance_of(PandaPal::Organization).to receive(:tenant_name) do |org|
57
+ shard = determine_shard.call(org)
58
+ tenant = org.name
59
+ tenant = "#{shard}:#{tenant}" if shard.present?
60
+ tenant
61
+ end
62
+ end
63
+ end
64
+
65
+ after :each do
66
+ Apartment::Tenant.reset
67
+ PandaPal::Organization.where.not(id: @each_existing_org_ids).destroy_all
68
+ end
69
+
70
+ define_method :clean_schemas do |schemas|
71
+ PandaPal::Organization.where(name: schemas).delete_all
72
+
73
+ schemas.each do |schema|
74
+ Apartment::Tenant.drop(schema) rescue nil
75
+ shards.each do |k, v|
76
+ Apartment::Tenant.drop("#{k}:#{schema}") rescue nil
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,3 +1,3 @@
1
1
  module PandaPal
2
- VERSION = "5.11.0"
2
+ VERSION = "5.12.0"
3
3
  end
data/panda_pal.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.test_files = Dir["spec/**/*"].reject{|f| f =~ /\/log\//}
22
22
 
23
23
  s.add_dependency "rails", ">= 4.2"
24
- s.add_dependency 'ros-apartment', '~> 2.2'
24
+ s.add_dependency 'ros-apartment', '~> 3.0'
25
25
  s.add_dependency 'ims-lti', '~> 1.2.4'
26
26
  s.add_dependency 'browser', '2.5.0'
27
27
  s.add_dependency 'attr_encrypted', '~> 4.0.0'
@@ -30,11 +30,11 @@ Gem::Specification.new do |s|
30
30
  s.add_dependency 'jwt'
31
31
  s.add_dependency 'httparty'
32
32
 
33
- s.add_development_dependency "rails", "~> 5.2"
33
+ s.add_development_dependency "rails", "~> 7.0"
34
34
  s.add_development_dependency 'pg'
35
35
  s.add_development_dependency 'sidekiq', "< 7.0"
36
36
  s.add_development_dependency 'sidekiq-scheduler'
37
- s.add_development_dependency 'ros-apartment', '~> 2.11'
37
+ s.add_development_dependency 'ros-apartment', '~> 3.0'
38
38
  s.add_development_dependency 'ros-apartment-sidekiq', '~> 1.2'
39
39
  s.add_development_dependency 'rspec-rails'
40
40
  s.add_development_dependency 'factory_girl_rails'
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe PandaPal::Organization, type: :model do
6
+ context "across multiple DBs" do
7
+ with_multiple_shards(
8
+ shards: { alt: "panda_pal_test2" },
9
+ preclean_schemas: %w[on_primary on_alt],
10
+ transactional: false,
11
+ determine_shard: ->(org) { org.name.include?("alt") ? "alt" : nil }
12
+ )
13
+
14
+ let!(:org1) { create(:panda_pal_organization, name: "on_primary") }
15
+ let!(:org2) { create(:panda_pal_organization, name: "on_alt") }
16
+
17
+ it "successfully creates tenants on multiple shards" do
18
+ expect(1).to eql(1)
19
+ end
20
+
21
+ it "only creates schemas on the target shard" do
22
+ org1.switch_tenant do
23
+ schemas = PandaPal::ApiCall.connection.exec_query("SELECT schema_name FROM information_schema.schemata").pluck("schema_name")
24
+ expect(schemas).to include("on_primary")
25
+ expect(schemas).to_not include("on_alt")
26
+ end
27
+ org2.switch_tenant do
28
+ schemas = PandaPal::ApiCall.connection.exec_query("SELECT schema_name FROM information_schema.schemata").pluck("schema_name")
29
+ expect(schemas).to include("on_alt")
30
+ expect(schemas).to_not include("on_primary")
31
+ end
32
+ end
33
+
34
+ context "load_async" do
35
+ it "works across shards" do
36
+ qs = []
37
+ PandaPal::Organization.all.each do |org|
38
+ org.switch_tenant do
39
+ PandaPal::ApiCall.create!(logic: org.name)
40
+ qs << PandaPal::ApiCall.select("logic, pg_sleep(0.5)").load_async
41
+ end
42
+ end
43
+ calls = qs.map(&:to_a).flatten
44
+ expect(calls.pluck(:logic)).to match_array(["on_primary", "on_alt"])
45
+ end
46
+ end
47
+ end
48
+ end
@@ -14,8 +14,12 @@ development:
14
14
  database: panda_pal_development
15
15
 
16
16
  test:
17
- <<: *default
18
- database: panda_pal_test
17
+ test1:
18
+ <<: *default
19
+ database: panda_pal_test1
20
+ test2:
21
+ <<: *default
22
+ database: panda_pal_test2
19
23
 
20
24
  production:
21
25
  <<: *default
@@ -37,6 +37,11 @@ Rails.application.configure do
37
37
  # Print deprecation notices to the stderr.
38
38
  config.active_support.deprecation = :stderr
39
39
 
40
+ config.log_level = :debug
41
+ config.active_record.verbose_query_logs = true
42
+ config.active_record.async_query_executor = :multi_thread_pool
43
+ # config.active_record.global_executor_concurrency = 4
44
+
40
45
  # Raises error for missing translations
41
46
  # config.action_view.raise_on_missing_translations = true
42
47
  end
@@ -0,0 +1,18 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your
6
+ # database schema. If you need to create the application database on another
7
+ # system, you should be using db:schema:load, not running all the migrations
8
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
12
+
13
+ ActiveRecord::Schema.define(version: 2022_07_21_095653) do
14
+
15
+ # These are extensions that must be enabled in order to support this database
16
+ enable_extension "plpgsql"
17
+
18
+ end
@@ -17,7 +17,7 @@ module PandaPal
17
17
 
18
18
  describe "#call" do
19
19
  it "calls the function with parameters" do
20
- expect(subject.call(foo: 'FOO')).to eq 'FOO_bar'
20
+ expect(subject.call({ foo: 'FOO' })).to eq 'FOO_bar'
21
21
  end
22
22
  end
23
23
 
@@ -5,6 +5,10 @@ module PandaPal
5
5
  RSpec.describe OrganizationConcerns::SettingsValidation, type: :model do
6
6
  let!(:org) { create :panda_pal_organization }
7
7
 
8
+ after :all do
9
+ PandaPal.lti_options[:settings_structure] = nil
10
+ end
11
+
8
12
  def set_test_settings_structure
9
13
  PandaPal.lti_options = {
10
14
  title: 'Test App',
data/spec/rails_helper.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  ActiveRecord::Migration.maintain_test_schema!
2
2
 
3
+ require "panda_pal/spec_helper"
4
+
3
5
  RSpec.configure do |config|
6
+ config.include PandaPal::SpecHelper
7
+
4
8
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
5
9
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
6
10
 
data/spec/spec_helper.rb CHANGED
@@ -11,7 +11,6 @@ require 'factory_girl_rails'
11
11
 
12
12
  ActiveRecord::Migration.maintain_test_schema!
13
13
  ActiveRecord::Schema.verbose = false
14
- load 'dummy/db/schema.rb' # db agnostic
15
14
 
16
15
  RSpec.configure do |config|
17
16
  config.include FactoryGirl::Syntax::Methods
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda_pal
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.11.0
4
+ version: 5.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure CustomDev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-25 00:00:00.000000000 Z
11
+ date: 2024-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.2'
33
+ version: '3.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.2'
40
+ version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ims-lti
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '5.2'
145
+ version: '7.0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '5.2'
152
+ version: '7.0'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: pg
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: '2.11'
201
+ version: '3.0'
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: '2.11'
208
+ version: '3.0'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: ros-apartment-sidekiq
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -282,7 +282,7 @@ dependencies:
282
282
  - - '='
283
283
  - !ruby/object:Gem::Version
284
284
  version: 2.7.1
285
- description:
285
+ description:
286
286
  email:
287
287
  - pseng@instructure.com
288
288
  executables: []
@@ -311,9 +311,11 @@ files:
311
311
  - app/lib/panda_pal/lti_jwt_validator.rb
312
312
  - app/models/panda_pal/api_call.rb
313
313
  - app/models/panda_pal/organization.rb
314
+ - app/models/panda_pal/organization_concerns/multi_database_sharding.rb
314
315
  - app/models/panda_pal/organization_concerns/organization_builder.rb
315
316
  - app/models/panda_pal/organization_concerns/settings_validation.rb
316
317
  - app/models/panda_pal/organization_concerns/task_scheduling.rb
318
+ - app/models/panda_pal/organization_concerns/tenant_handling.rb
317
319
  - app/models/panda_pal/panda_pal_record.rb
318
320
  - app/models/panda_pal/platform.rb
319
321
  - app/models/panda_pal/platform/canvas.rb
@@ -343,21 +345,23 @@ files:
343
345
  - lib/panda_pal/helpers/secure_headers.rb
344
346
  - lib/panda_pal/helpers/session_replacement.rb
345
347
  - lib/panda_pal/plugins.rb
348
+ - lib/panda_pal/spec_helper.rb
346
349
  - lib/panda_pal/version.rb
347
350
  - lib/tasks/panda_pal_tasks.rake
348
351
  - panda_pal.gemspec
349
352
  - spec/controllers/panda_pal/api_call_controller_spec.rb
353
+ - spec/core/apartment_multidb_spec.rb
350
354
  - spec/dummy/README.rdoc
351
355
  - spec/dummy/Rakefile
352
356
  - spec/dummy/app/assets/javascripts/application.js
353
357
  - spec/dummy/app/assets/stylesheets/application.css
358
+ - spec/dummy/app/bin/bundle
359
+ - spec/dummy/app/bin/rails
360
+ - spec/dummy/app/bin/rake
361
+ - spec/dummy/app/bin/setup
354
362
  - spec/dummy/app/controllers/application_controller.rb
355
363
  - spec/dummy/app/helpers/application_helper.rb
356
364
  - spec/dummy/app/views/layouts/application.html.erb
357
- - spec/dummy/bin/bundle
358
- - spec/dummy/bin/rails
359
- - spec/dummy/bin/rake
360
- - spec/dummy/bin/setup
361
365
  - spec/dummy/config.ru
362
366
  - spec/dummy/config/application.rb
363
367
  - spec/dummy/config/boot.rb
@@ -377,6 +381,7 @@ files:
377
381
  - spec/dummy/config/routes.rb
378
382
  - spec/dummy/config/secrets.yml
379
383
  - spec/dummy/db/schema.rb
384
+ - spec/dummy/db/test2_schema.rb
380
385
  - spec/dummy/public/404.html
381
386
  - spec/dummy/public/422.html
382
387
  - spec/dummy/public/500.html
@@ -394,7 +399,7 @@ homepage: http://instructure.com
394
399
  licenses:
395
400
  - MIT
396
401
  metadata: {}
397
- post_install_message:
402
+ post_install_message:
398
403
  rdoc_options: []
399
404
  require_paths:
400
405
  - lib
@@ -409,52 +414,54 @@ required_rubygems_version: !ruby/object:Gem::Requirement
409
414
  - !ruby/object:Gem::Version
410
415
  version: '0'
411
416
  requirements: []
412
- rubygems_version: 3.0.3.1
413
- signing_key:
417
+ rubygems_version: 3.5.16
418
+ signing_key:
414
419
  specification_version: 4
415
420
  summary: LTI mountable engine
416
421
  test_files:
417
- - spec/spec_helper.rb
418
- - spec/dummy/app/controllers/application_controller.rb
419
- - spec/dummy/app/views/layouts/application.html.erb
422
+ - spec/controllers/panda_pal/api_call_controller_spec.rb
423
+ - spec/core/apartment_multidb_spec.rb
424
+ - spec/dummy/README.rdoc
425
+ - spec/dummy/Rakefile
420
426
  - spec/dummy/app/assets/javascripts/application.js
421
427
  - spec/dummy/app/assets/stylesheets/application.css
428
+ - spec/dummy/app/bin/bundle
429
+ - spec/dummy/app/bin/rails
430
+ - spec/dummy/app/bin/rake
431
+ - spec/dummy/app/bin/setup
432
+ - spec/dummy/app/controllers/application_controller.rb
422
433
  - spec/dummy/app/helpers/application_helper.rb
423
- - spec/dummy/bin/rake
424
- - spec/dummy/bin/setup
425
- - spec/dummy/bin/bundle
426
- - spec/dummy/bin/rails
427
- - spec/dummy/config/secrets.yml
428
- - spec/dummy/config/routes.rb
429
- - spec/dummy/config/locales/en.yml
430
- - spec/dummy/config/environments/production.rb
431
- - spec/dummy/config/environments/development.rb
432
- - spec/dummy/config/environments/test.rb
433
- - spec/dummy/config/environment.rb
434
+ - spec/dummy/app/views/layouts/application.html.erb
434
435
  - spec/dummy/config/application.rb
435
- - spec/dummy/config/database.yml
436
436
  - spec/dummy/config/boot.rb
437
+ - spec/dummy/config/database.yml
438
+ - spec/dummy/config/environment.rb
439
+ - spec/dummy/config/environments/development.rb
440
+ - spec/dummy/config/environments/production.rb
441
+ - spec/dummy/config/environments/test.rb
437
442
  - spec/dummy/config/initializers/backtrace_silencers.rb
438
- - spec/dummy/config/initializers/mime_types.rb
443
+ - spec/dummy/config/initializers/cookies_serializer.rb
439
444
  - spec/dummy/config/initializers/filter_parameter_logging.rb
445
+ - spec/dummy/config/initializers/inflections.rb
446
+ - spec/dummy/config/initializers/mime_types.rb
440
447
  - spec/dummy/config/initializers/session_store.rb
441
448
  - spec/dummy/config/initializers/wrap_parameters.rb
442
- - spec/dummy/config/initializers/cookies_serializer.rb
443
- - spec/dummy/config/initializers/inflections.rb
449
+ - spec/dummy/config/locales/en.yml
450
+ - spec/dummy/config/routes.rb
451
+ - spec/dummy/config/secrets.yml
444
452
  - spec/dummy/config.ru
445
- - spec/dummy/Rakefile
446
- - spec/dummy/public/favicon.ico
453
+ - spec/dummy/db/schema.rb
454
+ - spec/dummy/db/test2_schema.rb
455
+ - spec/dummy/public/404.html
447
456
  - spec/dummy/public/422.html
448
457
  - spec/dummy/public/500.html
449
- - spec/dummy/public/404.html
450
- - spec/dummy/db/schema.rb
451
- - spec/dummy/README.rdoc
458
+ - spec/dummy/public/favicon.ico
459
+ - spec/factories/panda_pal_organizations.rb
460
+ - spec/factories/panda_pal_sessions.rb
461
+ - spec/models/panda_pal/api_call_spec.rb
452
462
  - spec/models/panda_pal/organization/settings_validation_spec.rb
453
463
  - spec/models/panda_pal/organization/task_scheduling_spec.rb
454
- - spec/models/panda_pal/session_spec.rb
455
- - spec/models/panda_pal/api_call_spec.rb
456
464
  - spec/models/panda_pal/organization_spec.rb
457
- - spec/factories/panda_pal_sessions.rb
458
- - spec/factories/panda_pal_organizations.rb
459
- - spec/controllers/panda_pal/api_call_controller_spec.rb
465
+ - spec/models/panda_pal/session_spec.rb
460
466
  - spec/rails_helper.rb
467
+ - spec/spec_helper.rb
File without changes
File without changes
File without changes
File without changes