devise_invitable 2.0.0 → 2.0.5
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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.rdoc +27 -33
- data/app/controllers/devise/invitations_controller.rb +31 -30
- data/app/controllers/devise_invitable/registrations_controller.rb +11 -11
- data/app/views/devise/invitations/edit.html.erb +1 -1
- data/app/views/devise/mailer/invitation_instructions.html.erb +1 -1
- data/app/views/devise/mailer/invitation_instructions.text.erb +1 -1
- data/config/locales/ar.yml +23 -0
- data/config/locales/da.yml +41 -0
- data/config/locales/de.yml +31 -0
- data/config/locales/es.yml +31 -0
- data/config/locales/et.yml +23 -0
- data/config/locales/fa.yml +31 -0
- data/config/locales/fr.yml +34 -0
- data/config/locales/it.yml +31 -0
- data/config/locales/ja.yml +31 -0
- data/config/locales/ko.yml +24 -0
- data/config/locales/nl.yml +32 -0
- data/config/locales/no.yml +17 -0
- data/config/locales/pl.yml +31 -0
- data/config/locales/pt-BR.yml +23 -0
- data/config/locales/pt.yml +23 -0
- data/config/locales/ru.yml +23 -0
- data/config/locales/tr.yml +24 -0
- data/config/locales/ua.yml +31 -0
- data/config/locales/vi.yml +25 -0
- data/config/locales/zh-HK.yml +31 -0
- data/config/locales/zh-TW.yml +31 -0
- data/lib/devise_invitable.rb +2 -1
- data/lib/devise_invitable/controllers/helpers.rb +3 -4
- data/lib/devise_invitable/inviter.rb +4 -3
- data/lib/devise_invitable/mapping.rb +6 -5
- data/lib/devise_invitable/models.rb +13 -11
- data/lib/devise_invitable/models/authenticatable.rb +7 -1
- data/lib/devise_invitable/parameter_sanitizer.rb +18 -18
- data/lib/devise_invitable/routes.rb +1 -1
- data/lib/devise_invitable/version.rb +1 -1
- data/lib/generators/active_record/templates/migration.rb +0 -1
- data/lib/generators/devise_invitable/install_generator.rb +4 -3
- data/test/generators/views_generator_test.rb +7 -6
- data/test/generators_test.rb +3 -2
- data/test/integration_tests_helper.rb +0 -1
- data/test/models/invitable_test.rb +16 -0
- data/test/rails_app/app/controllers/admins_controller.rb +4 -3
- data/test/rails_app/app/controllers/application_controller.rb +10 -9
- data/test/rails_app/app/controllers/free_invitations_controller.rb +12 -9
- data/test/rails_app/config/initializers/devise.rb +4 -3
- data/test/rails_app/config/initializers/secret_token.rb +9 -0
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -2
- data/test/test_helper.rb +4 -17
- metadata +31 -9
data/lib/devise_invitable.rb
CHANGED
|
@@ -22,7 +22,8 @@ module Devise
|
|
|
22
22
|
mattr_accessor :invite_for
|
|
23
23
|
@@invite_for = 0
|
|
24
24
|
|
|
25
|
-
# Public:
|
|
25
|
+
# Public: Ensure that invited record is valid.
|
|
26
|
+
# The invitation won't be sent if this check fails.
|
|
26
27
|
# (default: false).
|
|
27
28
|
#
|
|
28
29
|
# Examples (in config/initializers/devise.rb)
|
|
@@ -14,9 +14,8 @@ module DeviseInvitable::Controllers::Helpers
|
|
|
14
14
|
|
|
15
15
|
protected
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
def authenticate_inviter!
|
|
18
|
+
send(:"authenticate_#{resource_name}!", force: true)
|
|
19
|
+
end
|
|
21
20
|
end
|
|
22
21
|
|
|
@@ -25,6 +25,7 @@ module DeviseInvitable
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
protected
|
|
28
|
+
|
|
28
29
|
def decrement_invitation_limit!
|
|
29
30
|
if self.class.invitation_limit.present?
|
|
30
31
|
self.invitation_limit ||= self.class.invitation_limit
|
|
@@ -32,8 +33,8 @@ module DeviseInvitable
|
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
module ClassMethods
|
|
37
|
+
Devise::Models.config(self, :invitation_limit)
|
|
38
|
+
end
|
|
38
39
|
end
|
|
39
40
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module DeviseInvitable
|
|
2
2
|
module Mapping
|
|
3
3
|
private
|
|
4
|
-
|
|
5
|
-
options
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
|
|
5
|
+
def default_controllers(options)
|
|
6
|
+
options[:controllers] ||= {}
|
|
7
|
+
options[:controllers][:registrations] ||= 'devise_invitable/registrations'
|
|
8
|
+
super
|
|
9
|
+
end
|
|
9
10
|
end
|
|
10
11
|
end
|
|
@@ -10,8 +10,8 @@ module Devise
|
|
|
10
10
|
#
|
|
11
11
|
# Configuration:
|
|
12
12
|
#
|
|
13
|
-
# invite_for: The period the generated invitation token is valid
|
|
14
|
-
# this period, the invited resource won't be able to accept the invitation.
|
|
13
|
+
# invite_for: The period the generated invitation token is valid.
|
|
14
|
+
# After this period, the invited resource won't be able to accept the invitation.
|
|
15
15
|
# When invite_for is 0 (the default), the invitation won't expire.
|
|
16
16
|
#
|
|
17
17
|
# Examples:
|
|
@@ -45,7 +45,7 @@ module Devise
|
|
|
45
45
|
elsif defined?(Mongoid) && defined?(Mongoid::Document) && self < Mongoid::Document && Mongoid::VERSION >= '6.0.0'
|
|
46
46
|
belongs_to_options.merge! optional: true
|
|
47
47
|
end
|
|
48
|
-
belongs_to :invited_by, belongs_to_options
|
|
48
|
+
belongs_to :invited_by, **belongs_to_options
|
|
49
49
|
|
|
50
50
|
extend ActiveModel::Callbacks
|
|
51
51
|
define_model_callbacks :invitation_created
|
|
@@ -391,15 +391,17 @@ module Devise
|
|
|
391
391
|
|
|
392
392
|
private
|
|
393
393
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
end
|
|
394
|
+
# The random password, as set after an invitation, must conform
|
|
395
|
+
# to any password format validation rules of the application.
|
|
396
|
+
# This default fixes the most common scenarios: Passwords must contain
|
|
397
|
+
# lower + upper case, a digit and a symbol.
|
|
398
|
+
# For more unusual rules, this method can be overridden.
|
|
399
|
+
def random_password
|
|
400
|
+
length = respond_to?(:password_length) ? password_length : Devise.password_length
|
|
402
401
|
|
|
402
|
+
prefix = 'aA1!'
|
|
403
|
+
prefix + Devise.friendly_token(length.last - prefix.length)
|
|
404
|
+
end
|
|
403
405
|
end
|
|
404
406
|
end
|
|
405
407
|
end
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
module Devise
|
|
2
2
|
module Models
|
|
3
3
|
module Authenticatable
|
|
4
|
-
|
|
4
|
+
list = %i[
|
|
5
5
|
invitation_token invitation_created_at invitation_sent_at
|
|
6
6
|
invitation_accepted_at invitation_limit invited_by_type
|
|
7
7
|
invited_by_id invitations_count
|
|
8
8
|
]
|
|
9
|
+
|
|
10
|
+
if defined?(UNSAFE_ATTRIBUTES_FOR_SERIALIZATION)
|
|
11
|
+
UNSAFE_ATTRIBUTES_FOR_SERIALIZATION.concat(list)
|
|
12
|
+
else
|
|
13
|
+
BLACKLIST_FOR_SERIALIZATION.concat(list)
|
|
14
|
+
end
|
|
9
15
|
end
|
|
10
16
|
end
|
|
11
17
|
end
|
|
@@ -12,27 +12,27 @@ module DeviseInvitable
|
|
|
12
12
|
|
|
13
13
|
private
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
if defined?(Devise::BaseSanitizer)
|
|
16
|
+
def permit(keys)
|
|
17
|
+
default_params.permit(*Array(keys))
|
|
18
|
+
end
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
def attributes_for(kind)
|
|
21
|
+
case kind
|
|
22
|
+
when :invite
|
|
23
|
+
resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []
|
|
24
|
+
when :accept_invitation
|
|
25
|
+
[:password, :password_confirmation, :invitation_token]
|
|
26
|
+
else
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
def initialize(resource_class, resource_name, params)
|
|
27
32
|
super
|
|
33
|
+
permit(:invite, keys: (resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []) )
|
|
34
|
+
permit(:accept_invitation, keys: [:password, :password_confirmation, :invitation_token] )
|
|
28
35
|
end
|
|
29
36
|
end
|
|
30
|
-
else
|
|
31
|
-
def initialize(resource_class, resource_name, params)
|
|
32
|
-
super
|
|
33
|
-
permit(:invite, keys: (resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []) )
|
|
34
|
-
permit(:accept_invitation, keys: [:password, :password_confirmation, :invitation_token] )
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -2,6 +2,7 @@ module ActionDispatch::Routing
|
|
|
2
2
|
class Mapper
|
|
3
3
|
|
|
4
4
|
protected
|
|
5
|
+
|
|
5
6
|
def devise_invitation(mapping, controllers)
|
|
6
7
|
resource :invitation, only: [:new, :create, :update],
|
|
7
8
|
path: mapping.path_names[:invitation], controller: controllers[:invitations] do
|
|
@@ -9,6 +10,5 @@ module ActionDispatch::Routing
|
|
|
9
10
|
get :destroy, path: mapping.path_names[:remove], as: :remove
|
|
10
11
|
end
|
|
11
12
|
end
|
|
12
|
-
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -8,7 +8,6 @@ class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration<%
|
|
|
8
8
|
t.integer :invitation_limit
|
|
9
9
|
t.references :invited_by, polymorphic: true
|
|
10
10
|
t.integer :invitations_count, default: 0
|
|
11
|
-
t.index :invitations_count
|
|
12
11
|
t.index :invitation_token, unique: true # for invitable
|
|
13
12
|
t.index :invited_by_id
|
|
14
13
|
end
|
|
@@ -15,8 +15,8 @@ module DeviseInvitable
|
|
|
15
15
|
inject_into_file(devise_initializer_path, before: " # ==> Configuration for :confirmable\n") do
|
|
16
16
|
<<-CONTENT
|
|
17
17
|
# ==> Configuration for :invitable
|
|
18
|
-
# The period the generated invitation token is valid
|
|
19
|
-
# this period, the invited resource won't be able to accept the invitation.
|
|
18
|
+
# The period the generated invitation token is valid.
|
|
19
|
+
# After this period, the invited resource won't be able to accept the invitation.
|
|
20
20
|
# When invite_for is 0 (the default), the invitation won't expire.
|
|
21
21
|
# config.invite_for = 2.weeks
|
|
22
22
|
|
|
@@ -35,7 +35,8 @@ module DeviseInvitable
|
|
|
35
35
|
# config.invite_key = { email: /\\A[^@]+@[^@]+\\z/ }
|
|
36
36
|
# config.invite_key = { email: /\\A[^@]+@[^@]+\\z/, username: nil }
|
|
37
37
|
|
|
38
|
-
#
|
|
38
|
+
# Ensure that invited record is valid.
|
|
39
|
+
# The invitation won't be sent if this check fails.
|
|
39
40
|
# Default: false
|
|
40
41
|
# config.validate_on_invite = true
|
|
41
42
|
|
|
@@ -28,13 +28,14 @@ class ViewsGeneratorTest < ::Rails::Generators::TestCase
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
private
|
|
31
|
-
def assert_files
|
|
32
|
-
assert views = { @invitations_path => %w/edit.html.erb new.html.erb/, @mailer_path => %w/invitation_instructions.html.erb/ }
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
def assert_files
|
|
33
|
+
assert views = { @invitations_path => %w/edit.html.erb new.html.erb/, @mailer_path => %w/invitation_instructions.html.erb/ }
|
|
34
|
+
|
|
35
|
+
views.each do |path, files|
|
|
36
|
+
files.each do |file|
|
|
37
|
+
assert_file File.join path, file
|
|
38
|
+
end
|
|
37
39
|
end
|
|
38
40
|
end
|
|
39
|
-
end
|
|
40
41
|
end
|
data/test/generators_test.rb
CHANGED
|
@@ -17,13 +17,14 @@ class GeneratorsTest < ActiveSupport::TestCase
|
|
|
17
17
|
|
|
18
18
|
test "rails g devise_invitable:install" do
|
|
19
19
|
@output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:install -p`
|
|
20
|
-
|
|
20
|
+
puts @output
|
|
21
|
+
assert @output.match(%r{(inject|insert|File unchanged! The supplied flag value not found!).* config/initializers/devise\.rb\n})
|
|
21
22
|
assert @output.match(%r|create.* config/locales/devise_invitable\.en\.yml\n|)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
test "rails g devise_invitable Octopussy" do
|
|
25
26
|
@output = `cd #{RAILS_APP_PATH} && rails g devise_invitable Octopussy -p`
|
|
26
|
-
assert @output.match(%r{(inject|insert).* app/models/octopussy\.rb\n})
|
|
27
|
+
assert @output.match(%r{(inject|insert|File unchanged! The supplied flag value not found!).* app/models/octopussy\.rb\n})
|
|
27
28
|
assert @output.match(%r|invoke.* #{DEVISE_ORM}\n|)
|
|
28
29
|
if DEVISE_ORM == :active_record
|
|
29
30
|
assert @output.match(%r|create.* db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
|
|
@@ -29,7 +29,6 @@ class ActionDispatch::IntegrationTest
|
|
|
29
29
|
|
|
30
30
|
# Fix assert_redirect_to in integration sessions because they don't take into
|
|
31
31
|
# account Middleware redirects.
|
|
32
|
-
#
|
|
33
32
|
def assert_redirected_to(url)
|
|
34
33
|
assert [301, 302].include?(@integration_session.status),
|
|
35
34
|
"Expected status to be 301 or 302, got #{@integration_session.status}"
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
require 'model_tests_helper'
|
|
3
3
|
|
|
4
|
+
class Validatable < User
|
|
5
|
+
devise :validatable, password_length: 10..20
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
class InvitableTest < ActiveSupport::TestCase
|
|
5
9
|
|
|
6
10
|
def setup
|
|
@@ -760,4 +764,16 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
760
764
|
assert user.persisted?
|
|
761
765
|
assert user.errors.empty?
|
|
762
766
|
end
|
|
767
|
+
|
|
768
|
+
test 'should set initial password following Devise.password_length' do
|
|
769
|
+
user = User.invite!(email: 'valid@email.com')
|
|
770
|
+
assert_empty user.errors
|
|
771
|
+
assert_equal Devise.password_length.last, user.password.length
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
test 'should set initial passsword using :validatable with custom password_length' do
|
|
775
|
+
user = Validatable.invite!(email: 'valid@email.com')
|
|
776
|
+
assert_empty user.errors
|
|
777
|
+
assert_equal Validatable.password_length.last, user.password.length
|
|
778
|
+
end
|
|
763
779
|
end
|
|
@@ -3,15 +3,16 @@ class ApplicationController < ActionController::Base
|
|
|
3
3
|
before_action :configure_permitted_parameters, if: :devise_controller?
|
|
4
4
|
|
|
5
5
|
protected
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
|
|
7
|
+
def after_sign_in_path_for(resource)
|
|
8
|
+
if resource.is_a? Admin
|
|
9
|
+
edit_admin_registration_path(resource)
|
|
10
|
+
else
|
|
11
|
+
super
|
|
12
|
+
end
|
|
11
13
|
end
|
|
12
|
-
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
def configure_permitted_parameters
|
|
16
|
+
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :bio])
|
|
17
|
+
end
|
|
17
18
|
end
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
class FreeInvitationsController < Devise::InvitationsController
|
|
2
2
|
protected
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
|
|
4
|
+
def authenticate_inviter!
|
|
5
|
+
# everyone can invite
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def current_inviter
|
|
9
|
+
current_admin || current_user
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def after_invite_path_for(resource)
|
|
13
|
+
resource ? super : root_path
|
|
14
|
+
end
|
|
12
15
|
end
|
|
@@ -91,8 +91,8 @@ Devise.setup do |config|
|
|
|
91
91
|
# config.pepper = "e31589192aeea8807cb7d8686b0f8484d6cbfaaa65443d45144519ed1d4ffbc6ccb73b21a69ece276d94f2cac95d83990d824f36f301d6f585ededd1bf90d67d"
|
|
92
92
|
|
|
93
93
|
# ==> Configuration for :invitable
|
|
94
|
-
# The period the generated invitation token is valid
|
|
95
|
-
# this period, the invited resource won't be able to accept the invitation.
|
|
94
|
+
# The period the generated invitation token is valid.
|
|
95
|
+
# After this period, the invited resource won't be able to accept the invitation.
|
|
96
96
|
# When invite_for is 0 (the default), the invitation won't expire.
|
|
97
97
|
# config.invite_for = 2.weeks
|
|
98
98
|
|
|
@@ -111,7 +111,8 @@ Devise.setup do |config|
|
|
|
111
111
|
# config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/}
|
|
112
112
|
# config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/, :username => nil}
|
|
113
113
|
|
|
114
|
-
#
|
|
114
|
+
# Ensure that invited record is valid.
|
|
115
|
+
# The invitation won't be sent if this check fails.
|
|
115
116
|
# Default: false
|
|
116
117
|
# config.validate_on_invite = true
|
|
117
118
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
|
2
|
+
|
|
3
|
+
# Your secret key for verifying the integrity of signed cookies.
|
|
4
|
+
# If you change this key, all old signed cookies will become invalid!
|
|
5
|
+
# Make sure the secret is at least 30 characters and all random,
|
|
6
|
+
# no regular words or you'll be exposed to dictionary attacks.
|
|
7
|
+
if Rails.version < '5.2.0'
|
|
8
|
+
RailsApp::Application.config.secret_token = 'e997edf9d7eba5cf89a76a046fa53f5d66261d22cfcf29e3f538c75ad2d175b106bd5d099f44f6ce34ad3b3162d71cfaa37d2d4f4b38645288331427b4c2a607'
|
|
9
|
+
end
|
|
@@ -32,7 +32,6 @@ class CreateTables < (Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRe
|
|
|
32
32
|
t.timestamps :null => false
|
|
33
33
|
end
|
|
34
34
|
add_index :users, :invitation_token, :unique => true
|
|
35
|
-
add_index :users, :invitations_count
|
|
36
35
|
|
|
37
36
|
create_table :admins do |t|
|
|
38
37
|
## Database authenticatable
|
|
@@ -41,6 +40,5 @@ class CreateTables < (Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRe
|
|
|
41
40
|
|
|
42
41
|
t.integer :invitations_count, :default => 0
|
|
43
42
|
end
|
|
44
|
-
add_index :admins, :invitations_count
|
|
45
43
|
end
|
|
46
44
|
end
|
data/test/test_helper.rb
CHANGED
|
@@ -11,7 +11,7 @@ require 'mocha/setup'
|
|
|
11
11
|
|
|
12
12
|
ActionMailer::Base.delivery_method = :test
|
|
13
13
|
ActionMailer::Base.perform_deliveries = true
|
|
14
|
-
ActionMailer::Base.default_url_options[:host] = '
|
|
14
|
+
ActionMailer::Base.default_url_options[:host] = 'example.com'
|
|
15
15
|
|
|
16
16
|
ActiveSupport::Deprecation.silenced = true
|
|
17
17
|
$VERBOSE = false
|
|
@@ -19,28 +19,15 @@ $VERBOSE = false
|
|
|
19
19
|
class ActionDispatch::IntegrationTest
|
|
20
20
|
include Capybara::DSL
|
|
21
21
|
end
|
|
22
|
+
|
|
22
23
|
class ActionController::TestCase
|
|
23
24
|
if defined? Devise::Test
|
|
24
25
|
include Devise::Test::ControllerHelpers
|
|
25
26
|
else
|
|
26
27
|
include Devise::TestHelpers
|
|
27
28
|
end
|
|
29
|
+
|
|
28
30
|
if defined? ActiveRecord
|
|
29
|
-
|
|
30
|
-
self.use_transactional_tests = true
|
|
31
|
-
else
|
|
32
|
-
begin
|
|
33
|
-
require 'test_after_commit'
|
|
34
|
-
self.use_transactional_fixtures = true
|
|
35
|
-
rescue LoadError
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
if Rails.version < '5.0.0'
|
|
41
|
-
def post(action, *args)
|
|
42
|
-
hash = args[0] || {}
|
|
43
|
-
super action, hash[:params], hash[:session], hash[:flash]
|
|
44
|
-
end
|
|
31
|
+
self.use_transactional_tests = true
|
|
45
32
|
end
|
|
46
33
|
end
|