spree_cm_commissioner 2.1.6 → 2.1.8

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -1
  3. data/app/controllers/spree/admin/product_completion_steps_controller.rb +3 -2
  4. data/app/controllers/spree/admin/user_security_controller.rb +25 -0
  5. data/app/controllers/spree/api/v2/tenant/line_items_controller.rb +28 -0
  6. data/app/interactors/spree_cm_commissioner/pin_code_creator.rb +11 -1
  7. data/app/interactors/spree_cm_commissioner/pin_code_sender.rb +1 -0
  8. data/app/interactors/spree_cm_commissioner/sms.rb +1 -1
  9. data/app/jobs/spree_cm_commissioner/sms_pin_code_job.rb +1 -1
  10. data/app/models/spree_cm_commissioner/block.rb +4 -0
  11. data/app/models/spree_cm_commissioner/line_item_decorator.rb +13 -3
  12. data/app/models/spree_cm_commissioner/oauth_application_decorator.rb +4 -0
  13. data/app/models/spree_cm_commissioner/pin_code.rb +2 -0
  14. data/app/models/spree_cm_commissioner/product_completion_step.rb +37 -0
  15. data/app/models/spree_cm_commissioner/product_completion_steps/social_entry_url.rb +17 -0
  16. data/app/models/spree_cm_commissioner/seat_layout.rb +5 -0
  17. data/app/models/spree_cm_commissioner/user_decorator.rb +16 -0
  18. data/app/overrides/spree/admin/oauth_applications/_form/tenant_fields.html.erb.deface +6 -0
  19. data/app/overrides/spree/admin/users/_tabs/tabs.html.erb.deface +6 -0
  20. data/app/views/spree/admin/product_completion_steps/_form.html.erb +1 -1
  21. data/app/views/spree/admin/user_security/show.html.erb +25 -0
  22. data/config/locales/en.yml +5 -0
  23. data/config/locales/km.yml +9 -1
  24. data/config/routes.rb +11 -1
  25. data/db/migrate/20250930094228_add_application_id_to_cm_pin_codes.rb +10 -0
  26. data/db/migrate/20250930100657_add_settings_to_spree_oauth_applications.rb +7 -0
  27. data/lib/spree_cm_commissioner/test_helper/factories/pin_code_factory.rb +4 -0
  28. data/lib/spree_cm_commissioner/version.rb +1 -1
  29. data/lib/spree_cm_commissioner.rb +1 -0
  30. data/spree_cm_commissioner.gemspec +1 -0
  31. metadata +21 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a95912c38ef5e186747ac34d70d48d7f08db4fc4f4c69412f32706f3d72fd678
4
- data.tar.gz: ca0e0437c30f7ecf6a0fb6a91aa8186126c02e8e671c9b98249261bd2c61ffea
3
+ metadata.gz: 36165e2d7e9f037f00a0590045ae9c6171825a79f0499ec4cb70af91a246b0d5
4
+ data.tar.gz: b6d46f79ab01845de456585f50881dbca8b0b28d208e2db386a1833a9dfe1b30
5
5
  SHA512:
6
- metadata.gz: c4fcf779134f8a8a8e5e94d7da2796899f1c32efe9e588e7fe314ddda4584b5c9c2c22766c7e3860d5a2b1ace1989ee6077f2e50b43fe9d879b2885b32033e00
7
- data.tar.gz: 255a2d1f41917634ef14529eaa5e35d648dcbe748b87191f3c4457d8ab544dac50cef02b6e68f58000aae2c8b71dbb65a91e46a71576b3416ff1dc334085427a
6
+ metadata.gz: bd7ac99403f71109009b3d06dff1fc5a72b61b833d00e27f2a7513c552f7005782ff819a5e69ca67d64160865af6fabf4dd9554f7253b3cbd85ea4ba283b555a
7
+ data.tar.gz: f7d227c43eb5ecfc72eeebbf715e651f576f998a769106a1303e647680a9b4e82820b1e31e3c3b10299a1ee79fa6da9fde4fce5ea9ec62074b62d5b6e937d560
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.1.6)
37
+ spree_cm_commissioner (2.1.8)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -44,6 +44,7 @@ PATH
44
44
  byebug
45
45
  connection_pool
46
46
  counter_culture (~> 3.2)
47
+ devise-two-factor
47
48
  dry-validation (~> 1.10)
48
49
  elasticsearch (~> 8.5)
49
50
  exception_notification
@@ -291,6 +292,11 @@ GEM
291
292
  warden (~> 1.2.3)
292
293
  devise-encryptable (0.2.0)
293
294
  devise (>= 2.1.0)
295
+ devise-two-factor (6.1.0)
296
+ activesupport (>= 7.0, < 8.1)
297
+ devise (~> 4.0)
298
+ railties (>= 7.0, < 8.1)
299
+ rotp (~> 6.0)
294
300
  diff-lcs (1.5.0)
295
301
  docile (1.4.0)
296
302
  domain_name (0.5.20190701)
@@ -701,6 +707,7 @@ GEM
701
707
  railties (>= 5.2)
702
708
  retriable (3.1.2)
703
709
  rexml (3.2.6)
710
+ rotp (6.3.0)
704
711
  rqrcode (2.2.0)
705
712
  chunky_png (~> 1.0)
706
713
  rqrcode_core (~> 1.0)
@@ -7,7 +7,8 @@ module Spree
7
7
 
8
8
  def load_step_types
9
9
  @step_types = [
10
- 'SpreeCmCommissioner::ProductCompletionSteps::ChatraceTelegram'
10
+ 'SpreeCmCommissioner::ProductCompletionSteps::ChatraceTelegram',
11
+ 'SpreeCmCommissioner::ProductCompletionSteps::SocialEntryUrl'
11
12
  ]
12
13
  end
13
14
 
@@ -21,7 +22,7 @@ module Spree
21
22
 
22
23
  # @overrided
23
24
  def collection
24
- parent.product_completion_steps
25
+ parent.product_completion_steps.order(:position)
25
26
  end
26
27
 
27
28
  # @overrided
@@ -0,0 +1,25 @@
1
+ module Spree
2
+ module Admin
3
+ class UserSecurityController < Spree::Admin::BaseController
4
+ before_action :load_user
5
+
6
+ def disable_authenticator
7
+ @user.otp_secret = nil
8
+ @user.otp_required_for_login = false
9
+ begin
10
+ @user.save!
11
+ flash[:success] = I18n.t('authenticator.success_disabled_2fa')
12
+ rescue StandardError => e
13
+ flash[:error] = "Failed to disable 2FA: #{e.message}"
14
+ end
15
+ redirect_to admin_user_security_path(@user)
16
+ end
17
+
18
+ private
19
+
20
+ def load_user
21
+ @user = Spree::User.find(params[:user_id])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -18,6 +18,34 @@ module Spree
18
18
  render_serialized_payload { serialize_resource(line_item) }
19
19
  end
20
20
 
21
+ def mark_as_completed # rubocop:disable Metrics/PerceivedComplexity
22
+ line_item = Spree::LineItem.find(params[:id])
23
+
24
+ metadata = (line_item.public_metadata || {}).deep_transform_keys(&:to_s)
25
+ steps = metadata['completion_steps']
26
+
27
+ if steps.present? && steps.is_a?(Array)
28
+ step = steps.find { |s| s['position'] == 1 } || steps[0]
29
+
30
+ if step
31
+ if step['action_url'].present?
32
+ step['completed'] = true
33
+ metadata['completion_steps'] = steps
34
+ line_item.public_metadata = metadata
35
+ line_item.save!
36
+
37
+ render_serialized_payload { serialize_resource(line_item) }
38
+ else
39
+ render_error_payload('Action url is nil, cannot update to completed')
40
+ end
41
+ else
42
+ render_error_payload('Step with position 1 not found')
43
+ end
44
+ else
45
+ render_error_payload('completion_steps does not exist for this line_item')
46
+ end
47
+ end
48
+
21
49
  private
22
50
 
23
51
  def allowed_sort_attributes
@@ -2,8 +2,9 @@ module SpreeCmCommissioner
2
2
  class PinCodeCreator < BaseInteractor
3
3
  def call
4
4
  set_contact
5
+ set_application
5
6
 
6
- attrs = { contact: context.contact, contact_type: context.contact_type, type: context.type }
7
+ attrs = { contact: context.contact, contact_type: context.contact_type, type: context.type, application: context.application }
7
8
  new_pin_code = SpreeCmCommissioner::PinCode.new(attrs)
8
9
 
9
10
  if new_pin_code.save
@@ -29,5 +30,14 @@ module SpreeCmCommissioner
29
30
  context.contact_type = :phone_number
30
31
  end
31
32
  end
33
+
34
+ def set_application
35
+ return nil if context.tenant.blank?
36
+
37
+ context.application = Spree::OauthApplication.find_by(tenant_id: context.tenant.id)
38
+ context.fail!(message: I18n.t('pincode_creator.application_not_found')) if context.application.nil?
39
+
40
+ context.application
41
+ end
32
42
  end
33
43
  end
@@ -18,6 +18,7 @@ module SpreeCmCommissioner
18
18
 
19
19
  def send_sms
20
20
  options = {
21
+ from: context.pin_code&.application&.sms_sender_id,
21
22
  to: context.pin_code.contact,
22
23
  body: I18n.t('pincode_sender.sms.body', code: context.pin_code.code, readable_type: context.pin_code.readable_type)
23
24
  }
@@ -48,7 +48,7 @@ module SpreeCmCommissioner
48
48
  end
49
49
 
50
50
  def from_number
51
- context.from || ENV['SMS_SENDER_ID'].presence || 'SMS Info'
51
+ context.from.presence || ENV['SMS_SENDER_ID'].presence || 'SMS Info'
52
52
  end
53
53
 
54
54
  def sanitize(number)
@@ -1,6 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  class SmsPinCodeJob < SpreeCmCommissioner::SmsJob
3
- # options = { to: xxxx, body: xxxx }
3
+ # options = { from: xxxx, to: xxxx, body: xxxx }
4
4
  def perform(options)
5
5
  SpreeCmCommissioner::Sms.call(options)
6
6
  end
@@ -13,6 +13,10 @@ module SpreeCmCommissioner
13
13
  belongs_to :seat_layout, class_name: 'SpreeCmCommissioner::SeatLayout', optional: false
14
14
  belongs_to :variant, class_name: 'Spree::Variant', optional: true
15
15
 
16
+ has_many :all_reserved_blocks, class_name: 'SpreeCmCommissioner::ReservedBlock', dependent: :destroy
17
+ has_many :reserved_blocks, -> { reserved }, class_name: 'SpreeCmCommissioner::ReservedBlock', dependent: :destroy
18
+ has_many :active_on_hold_reserved_blocks, -> { reserved_or_on_hold }, class_name: 'SpreeCmCommissioner::ReservedBlock', dependent: :destroy
19
+
16
20
  validates :label, presence: true, if: :label_required?
17
21
  validates :width, presence: true, numericality: { greater_than: 0 }
18
22
  validates :height, presence: true, numericality: { greater_than: 0 }
@@ -26,6 +26,8 @@ module SpreeCmCommissioner
26
26
 
27
27
  base.before_save :update_vendor_id
28
28
 
29
+ base.after_commit :persist_completion_steps_to_public_metadata, on: :create
30
+
29
31
  base.before_create :add_due_date, if: :subscription?
30
32
 
31
33
  base.validate :ensure_not_exceed_max_quantity_per_order, if: -> { variant&.max_quantity_per_order.present? }
@@ -196,9 +198,7 @@ module SpreeCmCommissioner
196
198
  end
197
199
 
198
200
  def completion_steps
199
- @completion_steps ||= product_completion_steps.map do |completion_step|
200
- completion_step.construct_hash(line_item: self)
201
- end
201
+ public_metadata[:completion_steps] || []
202
202
  end
203
203
 
204
204
  # override
@@ -217,6 +217,16 @@ module SpreeCmCommissioner
217
217
 
218
218
  private
219
219
 
220
+ def persist_completion_steps_to_public_metadata
221
+ steps = product_completion_steps.order(:position).map do |pcs|
222
+ pcs.construct_hash(line_item: self).except(:completed).merge(
223
+ id: pcs.id,
224
+ completed: false
225
+ )
226
+ end
227
+ update_column(:public_metadata, (public_metadata || {}).merge(completion_steps: steps)) # rubocop:disable Rails/SkipsModelValidations
228
+ end
229
+
220
230
  def ensure_not_exceed_max_quantity_per_order
221
231
  errors.add(:quantity, I18n.t('line_item.validation.exceeded_max_quantity_per_order')) if quantity > variant.max_quantity_per_order
222
232
  end
@@ -2,6 +2,10 @@ module SpreeCmCommissioner
2
2
  module OauthApplicationDecorator
3
3
  def self.prepended(base)
4
4
  base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant'
5
+
6
+ # treat a key inside a JSONB column like a normal Rails attribute,
7
+ # with getter/setter methods
8
+ base.store_accessor :settings, :sms_sender_id
5
9
  end
6
10
  end
7
11
  end
@@ -18,6 +18,8 @@ module SpreeCmCommissioner
18
18
  PIN_CODE_MISMATCHED = 'not_match'.freeze
19
19
  PIN_CODE_OK = 'ok'.freeze
20
20
 
21
+ belongs_to :application, class_name: 'Spree::OauthApplication', optional: true
22
+
21
23
  def check?(code)
22
24
  return PIN_CODE_EXPIRED if expired?
23
25
  return PIN_CODE_ATTEMPT_REACHED if number_of_attempt_reached?
@@ -4,6 +4,10 @@ module SpreeCmCommissioner
4
4
 
5
5
  belongs_to :product, class_name: '::Spree::Product', optional: false
6
6
 
7
+ after_save :propagate_completion_steps_to_line_items
8
+
9
+ after_destroy_commit :propagate_completion_steps_to_line_items
10
+
7
11
  def action_url_for(_line_item)
8
12
  nil
9
13
  end
@@ -23,5 +27,38 @@ module SpreeCmCommissioner
23
27
  completed: completed?(line_item)
24
28
  }
25
29
  end
30
+
31
+ private
32
+
33
+ def propagate_completion_steps_to_line_items
34
+ product.line_items.find_each do |line_item|
35
+ propagate_to_line_item(line_item)
36
+ end
37
+ end
38
+
39
+ def propagate_to_line_item(line_item)
40
+ current_metadata = line_item.reload.public_metadata || {}
41
+ stored_steps = Array(current_metadata[:completion_steps])
42
+
43
+ fresh_steps = product.product_completion_steps.order(:position).map do |pcs|
44
+ base_attrs = pcs.construct_hash(line_item: line_item).except(:completed)
45
+
46
+ previous =
47
+ stored_steps.find { |s| s[:id] == pcs.id } ||
48
+ stored_steps.find { |s| s[:type] == pcs.type&.underscore && s[:position] == pcs.position }
49
+
50
+ completed_flag = previous&.dig(:completed) ? true : false
51
+
52
+ base_attrs.merge(
53
+ id: pcs.id,
54
+ completed: completed_flag
55
+ )
56
+ end
57
+
58
+ line_item.update_column( # rubocop:disable Rails/SkipsModelValidations
59
+ :public_metadata,
60
+ current_metadata.merge(completion_steps: fresh_steps)
61
+ )
62
+ end
26
63
  end
27
64
  end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module ProductCompletionSteps
3
+ class SocialEntryUrl < ProductCompletionStep
4
+ # eg. https://t.me/ThePlatformKHBot?start=bookmeplus
5
+ preference :entry_point_link, :string
6
+
7
+ # override
8
+ def action_url_for(_line_item)
9
+ preferred_entry_point_link.presence
10
+ end
11
+
12
+ def completed?(_line_item)
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -6,6 +6,11 @@ module SpreeCmCommissioner
6
6
  has_many :top_level_blocks, -> { where(seat_section_id: nil) }, class_name: 'SpreeCmCommissioner::Block', dependent: :destroy
7
7
  has_many :section_blocks, -> { where.not(seat_section_id: nil) }, class_name: 'SpreeCmCommissioner::Block' # destroy is handled by seat_section
8
8
 
9
+ has_many :reserved_blocks, class_name: 'SpreeCmCommissioner::ReservedBlock', through: :blocks, source: :all_reserved_blocks
10
+ has_many :active_on_hold_reserved_blocks, class_name: 'SpreeCmCommissioner::ReservedBlock',
11
+ through: :blocks,
12
+ source: :active_on_hold_reserved_blocks
13
+
9
14
  belongs_to :layoutable, polymorphic: true
10
15
 
11
16
  enum status: {
@@ -46,6 +46,10 @@ module SpreeCmCommissioner
46
46
  # Store has_incomplete_guest_info in public_metadata for easy frontend access
47
47
  base.store :public_metadata, accessors: [:has_incomplete_guest_info], coder: JSON
48
48
 
49
+ base.devise :two_factor_authenticatable
50
+
51
+ base.store :private_metadata, accessors: %i[otp_secret otp_required_for_login consumed_timestep], coder: JSON
52
+
49
53
  define_user_places(base)
50
54
 
51
55
  def base.end_users
@@ -63,6 +67,18 @@ module SpreeCmCommissioner
63
67
  end
64
68
  end
65
69
 
70
+ def otp_secret
71
+ private_metadata['otp_secret']
72
+ end
73
+
74
+ def otp_required_for_login
75
+ private_metadata['otp_required_for_login']
76
+ end
77
+
78
+ def consumed_timestep
79
+ private_metadata['consumed_timestep']
80
+ end
81
+
66
82
  def self.define_user_places(base)
67
83
  base.has_many :user_places, class_name: 'SpreeCmCommissioner::UserPlace'
68
84
  base.has_many :places, through: :user_places, class_name: 'SpreeCmCommissioner::Place'
@@ -5,3 +5,9 @@
5
5
  <%= f.collection_select :tenant_id, SpreeCmCommissioner::Tenant.all, :id, :name, { prompt: Spree.t(:select_tenant) }, { class: 'form-control select2' } %>
6
6
  <%= f.error_message_on :tenant_id %>
7
7
  <% end %>
8
+
9
+ <%= f.field_container :sms_sender_id, 'data-hook' => "oauth_application_settings_sms_sender_id" do %>
10
+ <%= f.label :sms_sender_id, raw('SMS Sender ID (optional)') %>
11
+ <%= f.text_field :sms_sender_id, class: 'form-control' %>
12
+ <%= f.error_message_on :sms_sender_id %>
13
+ <% end %>
@@ -49,4 +49,10 @@
49
49
  admin_user_events_path(user_id: @user.id),
50
50
  class: "nav-link #{'active' if current == :user_events }" %>
51
51
  </li>
52
+ <li class="nav-item">
53
+ <%= link_to_with_icon 'shield-check.svg',
54
+ Spree.t(:security),
55
+ admin_user_security_path(@user),
56
+ class: "nav-link #{'active' if current == :security }" %>
57
+ </li>
52
58
  <% end %>
@@ -8,7 +8,7 @@
8
8
  <div class="card-body">
9
9
  <%= f.field_container :type, 'data-hook' => 'type' do %>
10
10
  <%= f.label :type, Spree.t(:type) %>
11
- <%= f.select(:type, SpreeCmCommissioner::ProductCompletionStep.descendants.map { |v| [v.to_s.demodulize, v.to_s] }, {}, { class: 'select2' }) %>
11
+ <%= f.select(:type, @step_types.map { |t| [t.demodulize, t] }, {}, { class: 'select2' }) %>
12
12
  <% end %>
13
13
 
14
14
  <%= f.field_container :title, 'data-hook' => 'title' do %>
@@ -0,0 +1,25 @@
1
+ <%= render partial: 'spree/admin/users/tabs', locals: { current: :security } %>
2
+
3
+ <div class="card shadow-sm">
4
+ <div class="card-header bg-light">
5
+ <h5 class="card-title mb-0 h6">
6
+ <%= Spree.t(:two_factor_authentication) %>
7
+ </h5>
8
+ </div>
9
+
10
+ <div class="card-body text-center">
11
+ <% if @user.otp_secret.present? && @user.otp_required_for_login == true %>
12
+ <p class="text-muted mb-3">
13
+ Two-factor authentication is currently active for this user.
14
+ </p>
15
+ <%= button_to disable_authenticator_admin_user_security_path, method: :delete, class: "btn btn-danger btn-md",
16
+ data: { confirm: "Are you sure?" } do %>
17
+ Disable 2FA
18
+ <% end %>
19
+ <% else %>
20
+ <p class="text-muted mb-0">
21
+ Two-factor authentication is <strong>not enabled</strong> for this user.
22
+ </p>
23
+ <% end %>
24
+ </div>
25
+ </div>
@@ -11,9 +11,12 @@ en:
11
11
  body:
12
12
  blank: "sms content can not be blank"
13
13
  already_exist: "%{login} already exist"
14
+
14
15
  pincode_creator:
15
16
  invalid_phone_number: "Invalid phone number"
16
17
  invalid_email_address: "Invalid email address"
18
+ application_not_found: "Application not found"
19
+
17
20
  pincode_checker:
18
21
  error_type:
19
22
  not_found: "Verification Code not found!"
@@ -21,11 +24,13 @@ en:
21
24
  reached_max_attempt: "Verification Code already reach max attempt!"
22
25
  not_match: "Verification code is not valid"
23
26
  ok: "Verification code is valid"
27
+
24
28
  authenticator:
25
29
  incorrect_login: "Incorrect login"
26
30
  incorrect_password: "Incorrect password"
27
31
  invalid_or_missing_params: "Invalid or missing params"
28
32
  invalid_client_credentials: "Invalid client credentials"
33
+ success_disabled_2fa: "Successfully disabled 2FA"
29
34
 
30
35
  hello: "Hello world"
31
36
 
@@ -22,12 +22,20 @@ km:
22
22
  blank: "recipient can not be blank"
23
23
  body:
24
24
  blank: "sms content can not be blank"
25
-
26
25
  already_exist: "%{login} already exist"
27
26
 
28
27
  pincode_creator:
29
28
  invalid_phone_number: "លេខទូរសព្ទមិនត្រឹមត្រូវ"
30
29
  invalid_email_address: "អ៊ីមែលមិនត្រឹមត្រូវ"
30
+ application_not_found: "រកមិនឃើញកម្មវិធី"
31
+
32
+ pincode_checker:
33
+ error_type:
34
+ not_found: "រកមិនឃើញលេខសម្ងាត់"
35
+ expired: "លេខសម្ងាត់បានផុតកំណត់"
36
+ reached_max_attempt: "បានដល់កម្រិតអតិបរមា"
37
+ not_match: "លេខសម្ងាត់មិនត្រឹមត្រូវ"
38
+ ok: "លេខសម្ងាត់ត្រឹមត្រូវ"
31
39
 
32
40
  authenticator:
33
41
  incorrect_login: "ពត៌មានមិនត្រឹមត្រូវ"
data/config/routes.rb CHANGED
@@ -91,6 +91,11 @@ Spree::Core::Engine.add_routes do
91
91
  resources :users do
92
92
  resources :device_tokens
93
93
  resources :user_identity_providers
94
+ resource :security, controller: :user_security, only: %i[show] do
95
+ member do
96
+ delete :disable_authenticator
97
+ end
98
+ end
94
99
  end
95
100
 
96
101
  resources :s3_presigned_urls, only: %i[create new]
@@ -531,7 +536,12 @@ Spree::Core::Engine.add_routes do
531
536
  resources :cart_payment_method_groups, only: %i[index]
532
537
  resource :s3_signed_urls
533
538
  resource :profile_images, only: %i[update destroy]
534
- resources :line_items, only: %i[index show]
539
+ resources :line_items, only: %i[index show update] do
540
+ member do
541
+ patch :mark_as_completed
542
+ end
543
+ end
544
+
535
545
  resources :guest_card_classes
536
546
  resources :tickets, only: :index
537
547
 
@@ -0,0 +1,10 @@
1
+ class AddApplicationIdToCmPinCodes < ActiveRecord::Migration[7.0]
2
+ def change
3
+ unless column_exists?(:cm_pin_codes, :application_id)
4
+ add_reference :cm_pin_codes,
5
+ :application,
6
+ foreign_key: { to_table: :spree_oauth_applications },
7
+ index: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ class AddSettingsToSpreeOauthApplications < ActiveRecord::Migration[7.0]
2
+ def change
3
+ unless column_exists?(:spree_oauth_applications, :settings, :jsonb)
4
+ add_column :spree_oauth_applications, :settings, :jsonb, default: {}, null: false
5
+ end
6
+ end
7
+ end
@@ -18,5 +18,9 @@ FactoryBot.define do
18
18
  contact_type { :phone_number }
19
19
  sequence(:contact) { |n| "087420441#{n}" }
20
20
  end
21
+
22
+ trait :with_application do
23
+ association :application, factory: :oauth_application
24
+ end
21
25
  end
22
26
  end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.1.6'.freeze
2
+ VERSION = '2.1.8'.freeze
3
3
 
4
4
  module_function
5
5
 
@@ -46,6 +46,7 @@ require 'premailer/rails'
46
46
  require 'cm_app_logger'
47
47
  require 'counter_culture'
48
48
  require 'paper_trail'
49
+ require 'devise-two-factor'
49
50
 
50
51
  require 'byebug' if Rails.env.development? || Rails.env.test?
51
52
 
@@ -55,6 +55,7 @@ Gem::Specification.new do |s|
55
55
  s.add_dependency "premailer-rails"
56
56
  s.add_dependency 'counter_culture', '~> 3.2'
57
57
  s.add_dependency 'paper_trail', '~> 16.0'
58
+ s.add_dependency 'devise-two-factor'
58
59
 
59
60
  # Redis
60
61
  s.add_dependency 'redis'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_cm_commissioner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.6
4
+ version: 2.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-29 00:00:00.000000000 Z
11
+ date: 2025-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -478,6 +478,20 @@ dependencies:
478
478
  - - "~>"
479
479
  - !ruby/object:Gem::Version
480
480
  version: '16.0'
481
+ - !ruby/object:Gem::Dependency
482
+ name: devise-two-factor
483
+ requirement: !ruby/object:Gem::Requirement
484
+ requirements:
485
+ - - ">="
486
+ - !ruby/object:Gem::Version
487
+ version: '0'
488
+ type: :runtime
489
+ prerelease: false
490
+ version_requirements: !ruby/object:Gem::Requirement
491
+ requirements:
492
+ - - ">="
493
+ - !ruby/object:Gem::Version
494
+ version: '0'
481
495
  - !ruby/object:Gem::Dependency
482
496
  name: redis
483
497
  requirement: !ruby/object:Gem::Requirement
@@ -851,6 +865,7 @@ files:
851
865
  - app/controllers/spree/admin/trip_blazer_queries_controller.rb
852
866
  - app/controllers/spree/admin/user_events_controller.rb
853
867
  - app/controllers/spree/admin/user_identity_providers_controller.rb
868
+ - app/controllers/spree/admin/user_security_controller.rb
854
869
  - app/controllers/spree/admin/users_controller_decorator.rb
855
870
  - app/controllers/spree/admin/variant_guest_card_classes_controller.rb
856
871
  - app/controllers/spree/admin/vectors/icons_controller.rb
@@ -1423,6 +1438,7 @@ files:
1423
1438
  - app/models/spree_cm_commissioner/price_decorator.rb
1424
1439
  - app/models/spree_cm_commissioner/product_completion_step.rb
1425
1440
  - app/models/spree_cm_commissioner/product_completion_steps/chatrace_telegram.rb
1441
+ - app/models/spree_cm_commissioner/product_completion_steps/social_entry_url.rb
1426
1442
  - app/models/spree_cm_commissioner/product_decorator.rb
1427
1443
  - app/models/spree_cm_commissioner/product_dynamic_field.rb
1428
1444
  - app/models/spree_cm_commissioner/product_google_wallet.rb
@@ -2084,6 +2100,7 @@ files:
2084
2100
  - app/views/spree/admin/user_identity_providers/edit.html.erb
2085
2101
  - app/views/spree/admin/user_identity_providers/index.html.erb
2086
2102
  - app/views/spree/admin/user_identity_providers/new.html.erb
2103
+ - app/views/spree/admin/user_security/show.html.erb
2087
2104
  - app/views/spree/admin/variant_guest_card_classes/_variant_guest_card_class.html.erb
2088
2105
  - app/views/spree/admin/variant_guest_card_classes/index.html.erb
2089
2106
  - app/views/spree/admin/variants/_date_field.html.erb
@@ -2753,6 +2770,8 @@ files:
2753
2770
  - db/migrate/20250911174607_add_metadata_columns_to_cm_vehicles.rb
2754
2771
  - db/migrate/20250911174653_add_metadata_columns_to_cm_trips.rb
2755
2772
  - db/migrate/20250912084944_add_send_type_to_sms_log.rb
2773
+ - db/migrate/20250930094228_add_application_id_to_cm_pin_codes.rb
2774
+ - db/migrate/20250930100657_add_settings_to_spree_oauth_applications.rb
2756
2775
  - docker-compose.yml
2757
2776
  - docs/option_types/attr_types.md
2758
2777
  - docs/private_key.pem