spree_cm_commissioner 1.8.10 → 1.9.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 +4 -4
- data/.env.example +4 -0
- data/Gemfile.lock +25 -1
- data/app/controllers/spree/admin/user_events_controller.rb +9 -7
- data/app/controllers/spree/api/v2/storefront/vattanac_banks_controller.rb +25 -0
- data/app/controllers/spree/api/v2/tenant/change_passwords_controller.rb +32 -0
- data/app/controllers/spree/api/v2/tenant/id_cards_controller.rb +63 -0
- data/app/controllers/spree/api/v2/tenant/reset_passwords_controller.rb +35 -0
- data/app/controllers/spree/api/v2/tenant/tickets_controller.rb +25 -0
- data/app/controllers/spree/api/v2/tenant/user_contacts_controller.rb +33 -0
- data/app/controllers/spree_cm_commissioner/admin/roles_controller_decorator.rb +13 -0
- data/app/interactors/spree_cm_commissioner/firebase_email_fetcher.rb +25 -0
- data/app/interactors/spree_cm_commissioner/firebase_id_token_provider.rb +12 -1
- data/app/interactors/spree_cm_commissioner/user_id_token_authenticator.rb +11 -0
- data/app/interactors/spree_cm_commissioner/user_registration_with_id_token.rb +3 -3
- data/app/interactors/spree_cm_commissioner/user_vattanac_bank_web_app_authenticator.rb +30 -0
- data/app/interactors/spree_cm_commissioner/vattanac_bank_initiator.rb +116 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +1 -1
- data/app/models/spree_cm_commissioner/role_decorator.rb +9 -3
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +0 -1
- data/app/models/spree_cm_commissioner/trip.rb +7 -0
- data/app/models/spree_cm_commissioner/trip_connection.rb +10 -5
- data/app/models/spree_cm_commissioner/user_identity_provider.rb +1 -1
- data/app/models/spree_cm_commissioner/variant_decorator.rb +19 -2
- data/app/models/spree_cm_commissioner/variant_options.rb +14 -0
- data/app/overrides/spree/admin/users/_form/roles_fields.html.erb.deface +2 -0
- data/app/queries/spree_cm_commissioner/tickets_searcher_query.rb +21 -0
- data/app/queries/spree_cm_commissioner/trip_query.rb +145 -0
- data/app/serializers/spree/v2/tenant/id_card_serializer.rb +12 -0
- data/app/serializers/spree/v2/tenant/reset_password_serializer.rb +8 -0
- data/app/serializers/spree/v2/tenant/ticket_serializer.rb +27 -0
- data/app/serializers/spree/v2/tenant/user_contact_serializer.rb +11 -0
- data/app/services/spree_cm_commissioner/aes_encryption_service.rb +52 -0
- data/app/services/spree_cm_commissioner/role_permissions_constructor.rb +42 -0
- data/app/services/spree_cm_commissioner/role_permissions_loader.rb +57 -0
- data/app/services/spree_cm_commissioner/rsa_service.rb +27 -0
- data/app/services/spree_cm_commissioner/user_authenticator.rb +4 -0
- data/app/views/spree/admin/user_events/_events.html.erb +1 -1
- data/app/views/spree/admin/user_events/index.html.erb +7 -3
- data/config/routes.rb +9 -2
- data/db/migrate/20250328072717_add_description_to_spree_roles.rb +1 -1
- data/db/migrate/20250328072841_add_vendor_id_to_spree_roles.rb +1 -1
- data/db/migrate/20250403025619_add_presentation_to_spree_role.rb +5 -0
- data/db/migrate/20250403042255_add_unique_constraint_to_name_in_spree_roles.rb +7 -0
- data/db/migrate/20250407092556_add_variant_id_to_cm_trips.rb +7 -0
- data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +9 -0
- data/lib/spree_cm_commissioner/test_helper/factories/role_permission_factory.rb +11 -0
- data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +6 -0
- data/lib/spree_cm_commissioner/test_helper/factories/user_identity_provider_factory.rb +4 -0
- data/lib/spree_cm_commissioner/trip_query_result.rb +14 -0
- data/lib/spree_cm_commissioner/user_session_jwt_token.rb +5 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +2 -0
- data/spree_cm_commissioner.gemspec +1 -0
- metadata +44 -2
@@ -1,7 +1,5 @@
|
|
1
1
|
module SpreeCmCommissioner
|
2
2
|
class TripConnection < ApplicationRecord
|
3
|
-
attr_accessor :hours, :minutes
|
4
|
-
|
5
3
|
belongs_to :from_trip, class_name: 'Spree::Variant'
|
6
4
|
belongs_to :to_trip, class_name: 'Spree::Variant'
|
7
5
|
|
@@ -13,11 +11,18 @@ module SpreeCmCommissioner
|
|
13
11
|
def calculate_connection_time_minutes
|
14
12
|
return if from_trip.nil? || to_trip.nil?
|
15
13
|
|
16
|
-
|
14
|
+
arrival_seconds = from_trip.trip.arrival_time.seconds_since_midnight
|
15
|
+
departure_seconds = to_trip.trip.departure_time.seconds_since_midnight
|
16
|
+
|
17
|
+
layover_seconds = departure_seconds - arrival_seconds
|
18
|
+
layover_seconds += 86_400 if layover_seconds.negative?
|
19
|
+
|
20
|
+
connection_time_in_minutes = layover_seconds / 60
|
21
|
+
|
17
22
|
if connection_time_in_minutes.between?(0, 180)
|
18
|
-
self.connection_time_minutes = connection_time_in_minutes
|
23
|
+
self.connection_time_minutes = connection_time_in_minutes.to_i
|
19
24
|
else
|
20
|
-
errors.add(:base, 'Connection time
|
25
|
+
errors.add(:base, 'Connection time must be less than 3 hours')
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SpreeCmCommissioner
|
2
2
|
class UserIdentityProvider < Base
|
3
|
-
enum identity_type: { :google => 0, :apple => 1, :facebook => 2, :telegram => 3 }
|
3
|
+
enum identity_type: { :google => 0, :apple => 1, :facebook => 2, :telegram => 3, :vattanac_bank => 4 }
|
4
4
|
|
5
5
|
belongs_to :user, class_name: Spree.user_class.to_s, optional: false
|
6
6
|
|
@@ -21,10 +21,11 @@ module SpreeCmCommissioner
|
|
21
21
|
base.has_many :variant_guest_card_class, class_name: 'SpreeCmCommissioner::VariantGuestCardClass'
|
22
22
|
base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variant_guest_card_class
|
23
23
|
|
24
|
-
base.has_many :trip_stops, class_name: 'SpreeCmCommissioner::TripStop', dependent: :destroy, foreign_key: :trip_id
|
25
24
|
base.scope :subscribable, -> { active.joins(:product).where(product: { subscribable: true, status: :active }) }
|
26
|
-
|
25
|
+
base.has_one :trip,
|
26
|
+
class_name: 'SpreeCmCommissioner::Trip'
|
27
27
|
base.accepts_nested_attributes_for :option_values
|
28
|
+
base.after_commit :sync_trip, if: -> { product.product_type == 'transit' }
|
28
29
|
end
|
29
30
|
|
30
31
|
def delivery_required?
|
@@ -110,6 +111,22 @@ module SpreeCmCommissioner
|
|
110
111
|
end
|
111
112
|
end
|
112
113
|
end
|
114
|
+
|
115
|
+
def sync_trip
|
116
|
+
return unless product.product_type == 'transit'
|
117
|
+
|
118
|
+
trip = SpreeCmCommissioner::Trip.find_or_initialize_by(variant_id: id)
|
119
|
+
|
120
|
+
trip.assign_attributes(
|
121
|
+
product_id: product_id,
|
122
|
+
origin_id: options.origin,
|
123
|
+
destination_id: options.destination,
|
124
|
+
departure_time: options.departure_time,
|
125
|
+
duration: options.total_duration_in_seconds,
|
126
|
+
vehicle_id: options.vehicle
|
127
|
+
)
|
128
|
+
trip.save
|
129
|
+
end
|
113
130
|
end
|
114
131
|
end
|
115
132
|
|
@@ -166,5 +166,19 @@ module SpreeCmCommissioner
|
|
166
166
|
Time.zone.parse(time) if time.present?
|
167
167
|
end
|
168
168
|
end
|
169
|
+
|
170
|
+
def arrival_time
|
171
|
+
@arrival_time ||= departure_time + total_duration_in_minutes.minutes
|
172
|
+
end
|
173
|
+
|
174
|
+
def total_duration_in_minutes
|
175
|
+
total_duration_in_minutes = 0
|
176
|
+
|
177
|
+
total_duration_in_minutes += duration_in_hours * 60 if duration_in_hours.present?
|
178
|
+
total_duration_in_minutes += duration_in_minutes if duration_in_minutes.present?
|
179
|
+
total_duration_in_minutes += duration_in_seconds / 60 if duration_in_seconds.present?
|
180
|
+
|
181
|
+
total_duration_in_minutes
|
182
|
+
end
|
169
183
|
end
|
170
184
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class TicketsSearcherQuery
|
3
|
+
attr_reader :params, :tenant_id
|
4
|
+
|
5
|
+
def initialize(params, tenant_id)
|
6
|
+
@params = params
|
7
|
+
@tenant_id = tenant_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
return Spree::Product.none if tenant_id.blank?
|
12
|
+
|
13
|
+
search = Spree::Product.ransack(
|
14
|
+
tenant_id_eq: tenant_id,
|
15
|
+
name_i_cont_all: params[:term]&.split
|
16
|
+
)
|
17
|
+
|
18
|
+
search.result.distinct
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class TripQuery
|
3
|
+
attr_reader :origin_id, :destination_id, :travel_date
|
4
|
+
|
5
|
+
def initialize(origin_id:, destination_id:, travel_date: Time.zone.now)
|
6
|
+
@origin_id = origin_id
|
7
|
+
@destination_id = destination_id
|
8
|
+
@travel_date = travel_date
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
trips = direct_trips
|
13
|
+
connections = connected_trips if trips.size < 3
|
14
|
+
|
15
|
+
trip_results = trips.map { |trip| SpreeCmCommissioner::TripQueryResult.new([trip]) }
|
16
|
+
|
17
|
+
trip_results += connections if connections
|
18
|
+
trip_results
|
19
|
+
end
|
20
|
+
|
21
|
+
def direct_trips
|
22
|
+
result = Spree::Variant
|
23
|
+
.select('spree_variants.id AS variant_id,
|
24
|
+
vendors.id AS vendor_id,
|
25
|
+
vendors.name AS vendor_name,
|
26
|
+
routes.name AS route_name,
|
27
|
+
routes.short_name AS short_name,
|
28
|
+
boarding.stop_id AS origin_id,
|
29
|
+
drop_off.stop_id AS destination_id,
|
30
|
+
boarding.stop_name AS origin,
|
31
|
+
drop_off.stop_name AS destination,
|
32
|
+
trips.departure_time AS departure_time,
|
33
|
+
trips.duration AS duration,
|
34
|
+
trips.vehicle_id AS vehicle_id'
|
35
|
+
)
|
36
|
+
.joins('INNER JOIN cm_trips AS trips ON trips.variant_id = spree_variants.id')
|
37
|
+
.joins('INNER JOIN cm_trip_stops AS boarding ON boarding.trip_id = trips.id AND boarding.stop_type = 0')
|
38
|
+
.joins('INNER JOIN cm_trip_stops AS drop_off ON drop_off.trip_id = trips.id AND drop_off.stop_type = 1')
|
39
|
+
.joins('INNER JOIN spree_vendors AS vendors ON vendors.id = spree_variants.vendor_id')
|
40
|
+
.joins('INNER JOIN spree_products AS routes ON routes.id = spree_variants.product_id')
|
41
|
+
.where('trips.origin_id = ? AND trips.destination_id = ?', origin_id, destination_id)
|
42
|
+
|
43
|
+
result.map do |trip|
|
44
|
+
trip_result_options = {
|
45
|
+
trip_id: trip[:variant_id],
|
46
|
+
vendor_id: trip[:vendor_id],
|
47
|
+
vendor_name: trip[:vendor_name],
|
48
|
+
route_name: trip[:route_name],
|
49
|
+
short_name: trip[:short_name],
|
50
|
+
detail: trip[:variant_id],
|
51
|
+
origin_id: trip[:origin_id],
|
52
|
+
origin: trip[:origin],
|
53
|
+
destination_id: trip[:destination_id],
|
54
|
+
destination: trip[:destination],
|
55
|
+
vehicle_id: trip[:vehicle_id],
|
56
|
+
departure_time: trip[:departure_time],
|
57
|
+
duration: trip[:duration]
|
58
|
+
}
|
59
|
+
SpreeCmCommissioner::TripResult.new(trip_result_options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def connected_trips # rubocop:disable Metrics/MethodLength
|
64
|
+
result = SpreeCmCommissioner::TripConnection
|
65
|
+
.joins('
|
66
|
+
INNER JOIN spree_variants variant1 ON variant1.id = cm_trip_connections.from_trip_id
|
67
|
+
INNER JOIN spree_variants variant2 ON variant2.id = cm_trip_connections.to_trip_id
|
68
|
+
INNER JOIN spree_products AS routes1 ON routes1.id = variant1.product_id
|
69
|
+
INNER JOIN spree_products AS routes2 ON routes2.id = variant2.product_id
|
70
|
+
INNER JOIN cm_trips AS trip1 ON trip1.variant_id = cm_trip_connections.from_trip_id
|
71
|
+
INNER JOIN cm_trips AS trip2 ON trip2.variant_id = cm_trip_connections.to_trip_id
|
72
|
+
INNER JOIN cm_places trip1_origin ON trip1_origin.id = trip1.origin_id
|
73
|
+
INNER JOIN cm_places trip2_origin ON trip2_origin.id = trip2.origin_id
|
74
|
+
INNER JOIN cm_places trip2_destination ON trip2_destination.id = trip2.destination_id
|
75
|
+
INNER JOIN spree_vendors AS vendor1 ON vendor1.id = variant1.vendor_id
|
76
|
+
INNER JOIN spree_vendors AS vendor2 ON vendor2.id = variant2.vendor_id'
|
77
|
+
)
|
78
|
+
.select('cm_trip_connections.id AS id,
|
79
|
+
trip1.variant_id AS trip1_id,
|
80
|
+
trip1.origin_id AS trip1_origin_id,
|
81
|
+
trip1.destination_id AS trip1_destination_id,
|
82
|
+
trip1.departure_time AS trip1_departure_time,
|
83
|
+
trip1.duration AS trip1_duration,
|
84
|
+
routes1.short_name AS route1_short_name,
|
85
|
+
routes1.name AS route1_name,
|
86
|
+
trip1.vehicle_id AS trip1_vehicle,
|
87
|
+
vendor1.name AS trip1_vendor_name,
|
88
|
+
trip2.variant_id AS trip2_id,
|
89
|
+
trip2.origin_id AS trip2_origin_id,
|
90
|
+
trip2.destination_id AS trip2_destination_id,
|
91
|
+
trip2.departure_time AS trip2_departure_time,
|
92
|
+
trip2.duration AS trip2_duration,
|
93
|
+
trip2.vehicle_id AS trip2_vehicle,
|
94
|
+
routes2.short_name AS route2_short_name,
|
95
|
+
routes2.name AS route2_name,
|
96
|
+
trip1_origin.name AS trip1_origin,
|
97
|
+
trip2_origin.name AS trip2_origin,
|
98
|
+
trip2_destination.name AS trip2_destination,
|
99
|
+
vendor2.name AS trip2_vendor_name'
|
100
|
+
)
|
101
|
+
.where('trip1_origin.id = ? AND trip2_destination.id = ?', origin_id, destination_id)
|
102
|
+
|
103
|
+
return [] if result.blank?
|
104
|
+
|
105
|
+
build_trip_query_result(result)
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def build_trip_query_result(connections)
|
111
|
+
connections.map do |trip|
|
112
|
+
from_trip = {
|
113
|
+
trip_id: trip[:trip1_id],
|
114
|
+
origin_id: trip[:trip1_origin_id],
|
115
|
+
destination_id: trip[:trip1_destination_id],
|
116
|
+
departure_time: trip[:trip1_departure_time],
|
117
|
+
duration: trip[:trip1_duration],
|
118
|
+
vendor_name: trip[:trip1_vendor_name],
|
119
|
+
route_name: trip[:route1_name],
|
120
|
+
short_name: trip[:route1_short_name],
|
121
|
+
vehicle_id: trip[:trip1_vehicle],
|
122
|
+
origin: trip[:trip1_origin],
|
123
|
+
destination: trip[:trip2_origin]
|
124
|
+
}
|
125
|
+
to_trip = {
|
126
|
+
trip_id: trip[:trip2_id],
|
127
|
+
origin_id: trip[:trip2_origin_id],
|
128
|
+
destination_id: trip[:trip2_destination_id],
|
129
|
+
departure_time: trip[:trip2_departure_time],
|
130
|
+
duration: trip[:trip2_duration],
|
131
|
+
vendor_name: trip[:trip2_vendor_name],
|
132
|
+
route_name: trip[:route2_name],
|
133
|
+
short_name: trip[:route2_short_name],
|
134
|
+
vehicle_id: trip[:trip2_vehicle],
|
135
|
+
origin: trip[:trip2_origin],
|
136
|
+
destination: trip[:trip2_destination]
|
137
|
+
}
|
138
|
+
data = [SpreeCmCommissioner::TripResult.new(from_trip),
|
139
|
+
SpreeCmCommissioner::TripResult.new(to_trip)
|
140
|
+
]
|
141
|
+
SpreeCmCommissioner::TripQueryResult.new(data, connection_id: trip[:id])
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Spree
|
2
|
+
module V2
|
3
|
+
module Tenant
|
4
|
+
class IdCardSerializer < BaseSerializer
|
5
|
+
attributes :card_type
|
6
|
+
|
7
|
+
has_one :front_image, serializer: Spree::V2::Tenant::AssetSerializer
|
8
|
+
has_one :back_image, serializer: Spree::V2::Tenant::AssetSerializer
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spree
|
2
|
+
module V2
|
3
|
+
module Tenant
|
4
|
+
class TicketSerializer < BaseSerializer
|
5
|
+
include ::Spree::Api::V2::DisplayMoneyHelper
|
6
|
+
|
7
|
+
attributes :name
|
8
|
+
|
9
|
+
attribute :purchasable do |ticket|
|
10
|
+
value = ticket.purchasable?
|
11
|
+
[true, false].include?(value) ? value : nil
|
12
|
+
end
|
13
|
+
|
14
|
+
attribute :in_stock do |ticket|
|
15
|
+
value = ticket.in_stock?
|
16
|
+
[true, false].include?(value) ? value : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
attribute :available, &:available?
|
20
|
+
|
21
|
+
attribute :display_price do |ticket, params|
|
22
|
+
display_price(ticket, params[:currency])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module SpreeCmCommissioner
|
5
|
+
class AesEncryptionService
|
6
|
+
ALGORITHM = 'aes-256-gcm'.freeze
|
7
|
+
KEY_LENGTH = 32
|
8
|
+
IV_LENGTH = 12
|
9
|
+
TAG_LENGTH = 16
|
10
|
+
|
11
|
+
def self.encrypt(plaintext, key)
|
12
|
+
validate_key!(key)
|
13
|
+
|
14
|
+
cipher = OpenSSL::Cipher.new(ALGORITHM)
|
15
|
+
cipher.encrypt
|
16
|
+
cipher.key = key.b[0, KEY_LENGTH]
|
17
|
+
iv = cipher.random_iv
|
18
|
+
cipher.iv = iv
|
19
|
+
|
20
|
+
ciphertext = cipher.update(plaintext) + cipher.final
|
21
|
+
tag = cipher.auth_tag
|
22
|
+
|
23
|
+
combined = iv + ciphertext + tag
|
24
|
+
Base64.strict_encode64(combined)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.decrypt(encrypted_text, key)
|
28
|
+
validate_key!(key)
|
29
|
+
|
30
|
+
combined = Base64.decode64(encrypted_text)
|
31
|
+
iv = combined[0, IV_LENGTH]
|
32
|
+
tag = combined[-TAG_LENGTH..]
|
33
|
+
ciphertext = combined[IV_LENGTH...-TAG_LENGTH]
|
34
|
+
|
35
|
+
cipher = OpenSSL::Cipher.new(ALGORITHM)
|
36
|
+
cipher.decrypt
|
37
|
+
cipher.key = key.b[0, KEY_LENGTH]
|
38
|
+
cipher.iv = iv
|
39
|
+
cipher.auth_tag = tag
|
40
|
+
|
41
|
+
cipher.update(ciphertext) + cipher.final
|
42
|
+
rescue OpenSSL::Cipher::CipherError => e
|
43
|
+
raise "Decryption failed: #{e.message}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.validate_key!(key)
|
47
|
+
return if key.is_a?(String) && key.bytesize >= KEY_LENGTH
|
48
|
+
|
49
|
+
raise ArgumentError, "Key must be a string of at least #{KEY_LENGTH} bytes"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class RolePermissionsConstructor
|
3
|
+
def initialize(params)
|
4
|
+
@params = params[:role_permissions_attributes] || {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
construct_role_permissions
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def construct_role_permissions
|
14
|
+
role_permissions_attributes = {}
|
15
|
+
|
16
|
+
@params.each do |index, role_permission_attributes|
|
17
|
+
role_permission_attributes = role_permission_attributes.to_h.symbolize_keys
|
18
|
+
selected = role_permission_attributes.delete(:selected) == 'true'
|
19
|
+
role_permission_persisted = role_permission_attributes.key?(:id)
|
20
|
+
|
21
|
+
if role_permission_attributes[:permission_attributes]
|
22
|
+
permission_attributes = role_permission_attributes[:permission_attributes].to_h.symbolize_keys
|
23
|
+
permission_persisted = permission_attributes.key?(:id)
|
24
|
+
|
25
|
+
if permission_persisted
|
26
|
+
role_permission_attributes[:permission_id] = permission_attributes[:id]
|
27
|
+
role_permission_attributes.delete(:permission_attributes)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if selected
|
32
|
+
role_permissions_attributes[index] = role_permission_attributes
|
33
|
+
elsif role_permission_persisted
|
34
|
+
role_permission_attributes[:_destroy] = 1
|
35
|
+
role_permissions_attributes[index] = role_permission_attributes
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
role_permissions_attributes
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class RolePermissionsLoader
|
3
|
+
attr_reader :role, :permissions_config, :role_permissions
|
4
|
+
|
5
|
+
def initialize(role, permissions_config)
|
6
|
+
@role = role
|
7
|
+
@permissions_config = permissions_config
|
8
|
+
@role_permissions = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
load_role_permissions
|
13
|
+
role_permissions.uniq(&:slug)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def load_role_permissions
|
19
|
+
processed_entries = {}
|
20
|
+
|
21
|
+
permissions_config[:grouped].each do |entry, groups|
|
22
|
+
next if processed_entries[entry]
|
23
|
+
|
24
|
+
groups.each do |group_name, details|
|
25
|
+
next if details['actions'].empty?
|
26
|
+
|
27
|
+
permission = find_or_initialize_permission(entry, group_name)
|
28
|
+
role_permission = build_role_permission(permission)
|
29
|
+
@role_permissions << role_permission
|
30
|
+
end
|
31
|
+
|
32
|
+
processed_entries[entry] = true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_or_initialize_permission(entry, action)
|
37
|
+
SpreeCmCommissioner::Permission.where(
|
38
|
+
entry: entry,
|
39
|
+
action: action
|
40
|
+
).first_or_initialize
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_role_permission(permission)
|
44
|
+
if @role.persisted? && permission.persisted?
|
45
|
+
SpreeCmCommissioner::RolePermission.where(
|
46
|
+
role: @role,
|
47
|
+
permission: permission
|
48
|
+
).first_or_initialize
|
49
|
+
else
|
50
|
+
SpreeCmCommissioner::RolePermission.new(
|
51
|
+
role: @role,
|
52
|
+
permission: permission
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module SpreeCmCommissioner
|
5
|
+
class RsaService
|
6
|
+
def initialize(private_key: nil, public_key: nil)
|
7
|
+
@private_key = private_key
|
8
|
+
@public_key = public_key
|
9
|
+
end
|
10
|
+
|
11
|
+
def sign(data)
|
12
|
+
raise 'Private key is required to sign data' unless @private_key
|
13
|
+
|
14
|
+
private_key_object = OpenSSL::PKey::RSA.new(@private_key)
|
15
|
+
signature = private_key_object.sign(OpenSSL::Digest.new('SHA256'), data)
|
16
|
+
"#{data}.#{Base64.strict_encode64(signature)}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def verify(data, signature)
|
20
|
+
raise 'Public key is required to verify signature' unless @public_key
|
21
|
+
|
22
|
+
public_key_object = OpenSSL::PKey::RSA.new(@public_key)
|
23
|
+
signature_bytes = Base64.decode64(signature)
|
24
|
+
public_key_object.verify(OpenSSL::Digest.new('SHA256'), signature_bytes, data)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -35,6 +35,9 @@ module SpreeCmCommissioner
|
|
35
35
|
when 'telegram_web_app_auth'
|
36
36
|
options = { telegram_init_data: params[:telegram_init_data], telegram_bot_username: params[:tg_bot] }
|
37
37
|
SpreeCmCommissioner::UserTelegramWebAppAuthenticator.call(options)
|
38
|
+
when 'vattanac_bank_web_app_auth'
|
39
|
+
options = { session_id: params[:session_id] }
|
40
|
+
SpreeCmCommissioner::UserVattanacBankWebAppAuthenticator.call(options)
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
@@ -42,6 +45,7 @@ module SpreeCmCommissioner
|
|
42
45
|
return 'login_auth' if params.key?(:username) && params.key?(:password)
|
43
46
|
return 'social_auth' if params.key?(:id_token)
|
44
47
|
return 'telegram_web_app_auth' if params.key?(:telegram_init_data) && params.key?(:tg_bot)
|
48
|
+
return 'vattanac_bank_web_app_auth' if params.key?(:session_id)
|
45
49
|
|
46
50
|
raise exception(I18n.t('authenticator.invalid_or_missing_params'))
|
47
51
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<% content_for :page_actions do %>
|
2
|
-
<%= button_link_to Spree.t(:add_new_events), new_admin_user_event_path, class: "btn-success", icon: 'add.svg', id: 'admin_new_operator_link' %>
|
2
|
+
<%= button_link_to Spree.t(:add_new_events), new_admin_user_event_path(user_id: @user.id), class: "btn-success", icon: 'add.svg', id: 'admin_new_operator_link' %>
|
3
3
|
<% end %>
|
4
4
|
|
5
5
|
<%= render partial: 'spree/admin/users/tabs', locals: { current: :user_events } %>
|
@@ -3,7 +3,11 @@
|
|
3
3
|
<% elsif @taxon.present? && @taxonomy.present? %>
|
4
4
|
<%= render partial: 'users', locals: { user_events: @user_events, taxon: @taxon, taxonomy: @taxonomy } %>
|
5
5
|
<% else %>
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
<% content_for :page_actions do %>
|
7
|
+
<%= button_link_to Spree.t(:add_new_events), new_admin_user_event_path(user_id: @user.id), class: "btn-success", icon: 'add.svg', id: 'admin_new_operator_link' %>
|
8
|
+
<% end %>
|
9
|
+
<%= render partial: 'spree/admin/users/tabs', locals: { current: :user_events } %>
|
10
|
+
<small class="form-text text-muted">
|
11
|
+
<%= raw I18n.t('user_taxon.empty_info') %>
|
12
|
+
</small>
|
9
13
|
<% end %>
|
data/config/routes.rb
CHANGED
@@ -483,7 +483,9 @@ Spree::Core::Engine.add_routes do
|
|
483
483
|
patch :associate
|
484
484
|
end
|
485
485
|
resource :cart_guests, only: %i[create destroy]
|
486
|
-
resources :guests, only: %i[create update show]
|
486
|
+
resources :guests, only: %i[create update show] do
|
487
|
+
resources :id_cards, only: %i[create update destroy]
|
488
|
+
end
|
487
489
|
|
488
490
|
resource :checkout, controller: :checkout, only: %i[update] do
|
489
491
|
patch :next
|
@@ -508,11 +510,16 @@ Spree::Core::Engine.add_routes do
|
|
508
510
|
resource :profile_images, only: %i[update destroy]
|
509
511
|
resources :line_items, only: %i[index show]
|
510
512
|
resources :guest_card_classes
|
513
|
+
resources :tickets, only: :index
|
514
|
+
|
515
|
+
resource :reset_passwords, only: [:update]
|
516
|
+
resource :change_passwords, only: [:update]
|
517
|
+
resource :user_contacts, only: [:update]
|
511
518
|
end
|
512
519
|
|
513
520
|
namespace :storefront do
|
514
521
|
resources :waiting_room_sessions, only: :create
|
515
|
-
|
522
|
+
resources :vattanac_banks, only: %i[create]
|
516
523
|
resource :cart, controller: :cart, only: %i[show create destroy] do
|
517
524
|
patch :restart_checkout_flow
|
518
525
|
end
|
@@ -50,6 +50,15 @@ FactoryBot.define do
|
|
50
50
|
trip.permanent_stock = 10
|
51
51
|
trip.stock_items = [create(:stock_item, variant: trip, stock_location: route.vendor.stock_locations.first)]
|
52
52
|
trip.stock_items.first.adjust_count_on_hand(10)
|
53
|
+
|
54
|
+
# option types
|
55
|
+
route.option_types << create(:cm_option_type, :origin)
|
56
|
+
route.option_types << create(:cm_option_type, :destination)
|
57
|
+
route.option_types << create(:cm_option_type, :departure_time)
|
58
|
+
route.option_types << create(:cm_option_type, :duration_in_hours)
|
59
|
+
route.option_types << create(:cm_option_type, :duration_in_minutes)
|
60
|
+
route.option_types << create(:cm_option_type, :allow_seat_selection)
|
61
|
+
route.option_types << create(:cm_option_type, :vehicle)
|
53
62
|
end
|
54
63
|
end
|
55
64
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :permission, class: 'SpreeCmCommissioner::Permission' do
|
3
|
+
entry { 'organizer/events' }
|
4
|
+
action { 'view_events' }
|
5
|
+
end
|
6
|
+
|
7
|
+
factory :role_permission, class: 'SpreeCmCommissioner::RolePermission' do
|
8
|
+
association :role, factory: :role
|
9
|
+
association :permission, factory: :permission
|
10
|
+
end
|
11
|
+
end
|