dscf-core 0.1.7 → 0.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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/dscf/core/json_response.rb +12 -1
- data/app/controllers/concerns/dscf/core/reviewable_controller.rb +345 -0
- data/app/controllers/dscf/core/auth_controller.rb +19 -14
- data/app/models/concerns/dscf/core/reviewable_model.rb +31 -0
- data/app/models/dscf/core/review.rb +22 -0
- data/app/models/dscf/core/role.rb +8 -0
- data/app/models/dscf/core/user.rb +8 -0
- data/app/serializers/dscf/core/address_serializer.rb +10 -0
- data/app/serializers/dscf/core/business_serializer.rb +10 -0
- data/app/serializers/dscf/core/business_type_serializer.rb +9 -0
- data/app/serializers/dscf/core/review_serializer.rb +16 -0
- data/app/serializers/dscf/core/role_serializer.rb +9 -0
- data/app/serializers/dscf/core/user_auth_serializer.rb +10 -0
- data/app/serializers/dscf/core/user_profile_serializer.rb +12 -0
- data/app/serializers/dscf/core/user_role_serializer.rb +10 -0
- data/app/serializers/dscf/core/user_serializer.rb +14 -0
- data/db/migrate/20250926102025_create_dscf_core_reviews.rb +14 -0
- data/lib/dscf/core/version.rb +1 -1
- data/lib/generators/common/USAGE +39 -0
- data/lib/generators/common/common_generator.rb +579 -0
- data/lib/generators/common/templates/controller.rb.erb +75 -0
- data/lib/generators/common/templates/request_spec.rb.erb +33 -0
- data/lib/generators/common/templates/serializer.rb.erb +43 -0
- data/spec/factories/dscf/core/reviews.rb +11 -0
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c8bc7f7428e10e98816b30968fa31e0609cba87e3292c8ad8d248f38067e578
|
4
|
+
data.tar.gz: db88e3856be17b5a02d0350d28d303d3ec59abf09cf2641bae204b990bf6704c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f436f1f1d10c5c8e43c6683d8d104175d480d15dab6005e7b198ef4237e9c6fee26c15ea9a17d8fba4ad0b0f14a50aecbceb735157f4103b549e1ae4cc62a06
|
7
|
+
data.tar.gz: 8a4dda4a6efa99ebc8469fa9bf5ba69af0edbf3065f5c5ee288f591d2d65ee844a8bcf8d723a91bcec7840edc673c8db61584c752de63c0d1b96546b9f6af7a3
|
@@ -8,7 +8,18 @@ module Dscf
|
|
8
8
|
when ActiveRecord::Base, ActiveRecord::Relation
|
9
9
|
ActiveModelSerializers::SerializableResource.new(data, options)
|
10
10
|
when Hash
|
11
|
-
data
|
11
|
+
# Handle hash data with potential serializer options
|
12
|
+
serialized_hash = {}
|
13
|
+
data.each do |key, value|
|
14
|
+
if options[key] && value.is_a?(ActiveRecord::Base)
|
15
|
+
# Use specific serializer for this key if provided
|
16
|
+
serializer_opts = options[key].is_a?(Hash) ? options[key] : {}
|
17
|
+
serialized_hash[key] = ActiveModelSerializers::SerializableResource.new(value, serializer_opts)
|
18
|
+
else
|
19
|
+
serialized_hash[key] = serialize(value, options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
serialized_hash
|
12
23
|
when Array
|
13
24
|
data.map { |value| serialize(value, options) }
|
14
25
|
else
|
@@ -0,0 +1,345 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
module ReviewableController
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include Dscf::Core::JsonResponse
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :review_context_configs, default: {}
|
9
|
+
class_attribute :reviewable_model_class, default: nil
|
10
|
+
|
11
|
+
# Initialize with default context config for zero-config support
|
12
|
+
self.review_context_configs = default_context_config.dup
|
13
|
+
|
14
|
+
# Auto-define default actions for zero-config
|
15
|
+
define_default_review_actions
|
16
|
+
|
17
|
+
before_action :set_reviewable_resource, if: :review_action?
|
18
|
+
before_action :authorize_review_action!, if: :review_action?
|
19
|
+
end
|
20
|
+
|
21
|
+
class_methods do
|
22
|
+
def reviewable_model(model_class)
|
23
|
+
self.reviewable_model_class = model_class
|
24
|
+
end
|
25
|
+
|
26
|
+
def reviewable_context(context_name, options = {})
|
27
|
+
statuses = options[:statuses]&.map(&:to_s) || %w[pending approved rejected modify]
|
28
|
+
initial_status = options[:initial_status]&.to_s || "pending"
|
29
|
+
|
30
|
+
# Convert linear transitions array to hash if provided
|
31
|
+
transitions = if options[:transitions].is_a?(Array)
|
32
|
+
validate_linear_transitions(options[:transitions], statuses, context_name)
|
33
|
+
build_linear_transitions(options[:transitions])
|
34
|
+
else
|
35
|
+
options[:transitions] || {}
|
36
|
+
end
|
37
|
+
|
38
|
+
defaults = {
|
39
|
+
statuses: statuses,
|
40
|
+
initial_status: initial_status,
|
41
|
+
transitions: transitions,
|
42
|
+
actions: options[:actions] || default_actions
|
43
|
+
}
|
44
|
+
|
45
|
+
validate_action_config(defaults[:actions], defaults[:statuses], context_name)
|
46
|
+
unless defaults[:statuses].include?(defaults[:initial_status])
|
47
|
+
raise ArgumentError, <<~MSG
|
48
|
+
Initial status '#{defaults[:initial_status]}' in context '#{context_name}' must be one of: #{defaults[:statuses].join(', ')}
|
49
|
+
MSG
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add to existing configs
|
53
|
+
self.review_context_configs = review_context_configs.merge(context_name.to_sym => defaults)
|
54
|
+
|
55
|
+
# Define methods for all actions in this context
|
56
|
+
defaults[:actions].each_key do |action_name|
|
57
|
+
# Only define if not already defined
|
58
|
+
define_review_action_method(action_name) unless method_defined?(action_name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def define_default_review_actions
|
63
|
+
default_context_config.each do |context_name, config|
|
64
|
+
validate_action_config(config[:actions], config[:statuses], context_name)
|
65
|
+
config[:actions].each_key do |action_name|
|
66
|
+
define_review_action_method(action_name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def define_review_action_method(action_name)
|
72
|
+
define_method(action_name) do
|
73
|
+
context = current_review_context
|
74
|
+
action_config = context_config[:actions][action_name.to_sym]
|
75
|
+
unless action_config
|
76
|
+
return render_error(
|
77
|
+
errors: ["Action '#{action_name}' not defined for context '#{context}'"],
|
78
|
+
status: :bad_request
|
79
|
+
)
|
80
|
+
end
|
81
|
+
perform_review_action(**action_config.slice(:status, :require_feedback, :after, :update_model))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def default_actions
|
86
|
+
{
|
87
|
+
approve: {status: "approved"},
|
88
|
+
reject: {status: "rejected", require_feedback: true},
|
89
|
+
request_modification: {status: "modify", require_feedback: true},
|
90
|
+
resubmit: {status: "pending", update_model: true}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def default_context_config
|
95
|
+
{
|
96
|
+
default: {
|
97
|
+
statuses: %w[pending approved rejected modify],
|
98
|
+
initial_status: "pending",
|
99
|
+
transitions: {"pending" => %w[approved rejected modify], "modify" => ["pending"]},
|
100
|
+
actions: default_actions
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def validate_action_config(actions, statuses, context_name)
|
106
|
+
actions.each do |action_name, opts|
|
107
|
+
next if statuses.include?(opts[:status])
|
108
|
+
|
109
|
+
raise ArgumentError, <<~MSG
|
110
|
+
Action '#{action_name}' in context '#{context_name}' maps to invalid status '#{opts[:status]}'. Must be one of: #{statuses.join(', ')}
|
111
|
+
MSG
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def validate_linear_transitions(transitions, statuses, context_name)
|
116
|
+
transitions.each do |status|
|
117
|
+
unless statuses.include?(status.to_s)
|
118
|
+
raise ArgumentError, "Transition status '#{status}' in context '#{context_name}' must be one of: #{statuses.join(', ')}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def build_linear_transitions(transitions)
|
124
|
+
transitions.each_with_object({}).with_index do |(status, hash), index|
|
125
|
+
next_status = transitions[index + 1]
|
126
|
+
hash[status.to_s] = next_status ? [next_status.to_s] : []
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def review_action_names
|
131
|
+
# Get actions from initialized contexts + default fallback
|
132
|
+
all_actions = review_context_configs.values.flat_map { |config| config[:actions].keys }
|
133
|
+
all_actions += default_context_config[:default][:actions].keys
|
134
|
+
all_actions.uniq
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def review_action?
|
141
|
+
self.class.review_action_names.include?(action_name.to_sym)
|
142
|
+
end
|
143
|
+
|
144
|
+
def perform_review_action(status:, require_feedback: false, after: nil, update_model: false)
|
145
|
+
begin
|
146
|
+
context_config
|
147
|
+
rescue ArgumentError => e
|
148
|
+
return render_error(errors: [e.message], status: :bad_request)
|
149
|
+
end
|
150
|
+
|
151
|
+
current_review = reviewable_resource.current_review_for(current_review_context)
|
152
|
+
|
153
|
+
feedback = if require_feedback
|
154
|
+
feedback_data = params[:review_feedback]
|
155
|
+
feedback_data = feedback_data.to_unsafe_h if feedback_data.respond_to?(:to_unsafe_h)
|
156
|
+
|
157
|
+
return render_error(errors: ["Feedback is required for #{status}"]) if feedback_data.blank?
|
158
|
+
|
159
|
+
feedback_data
|
160
|
+
end
|
161
|
+
|
162
|
+
unless valid_transition?(current_review&.status, status)
|
163
|
+
return render_error(
|
164
|
+
errors: [
|
165
|
+
"Cannot transition from '#{current_review&.status || context_config[:initial_status]}' to '#{status}'"
|
166
|
+
]
|
167
|
+
)
|
168
|
+
end
|
169
|
+
|
170
|
+
begin
|
171
|
+
ActiveRecord::Base.transaction do
|
172
|
+
# Update the model if required (e.g., for resubmit with changes)
|
173
|
+
if update_model
|
174
|
+
begin
|
175
|
+
model_updates = model_params
|
176
|
+
if model_updates.present? && !reviewable_resource.update(model_updates)
|
177
|
+
return render_error(errors: reviewable_resource.errors.full_messages)
|
178
|
+
end
|
179
|
+
rescue ActionController::ParameterMissing => e
|
180
|
+
return render_error(errors: [e.message])
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Update existing review or create new one if none exists
|
185
|
+
review = current_review || reviewable_resource.build_review_for(current_review_context)
|
186
|
+
review.assign_attributes(
|
187
|
+
status: status,
|
188
|
+
feedback: feedback,
|
189
|
+
reviewed_by: current_user,
|
190
|
+
reviewed_at: Time.current
|
191
|
+
)
|
192
|
+
|
193
|
+
before_review_action(review)
|
194
|
+
review.save!
|
195
|
+
execute_after_callbacks(review, after)
|
196
|
+
after_review_action(review)
|
197
|
+
end
|
198
|
+
render_success(data: reviewable_resource.reload)
|
199
|
+
rescue StandardError => e
|
200
|
+
render_error(errors: [e.message], status: :unprocessable_entity)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def execute_after_callbacks(review, after_callbacks = nil)
|
205
|
+
# Get action callbacks from the current action config or passed callbacks
|
206
|
+
action_config = context_config[:actions][action_name.to_sym]
|
207
|
+
action_callbacks = after_callbacks || action_config&.[](:after)
|
208
|
+
return unless action_callbacks
|
209
|
+
|
210
|
+
Array(action_callbacks).each do |callback|
|
211
|
+
if callback.is_a?(Symbol)
|
212
|
+
send(callback, review)
|
213
|
+
elsif callback.respond_to?(:call)
|
214
|
+
callback.call(review)
|
215
|
+
else
|
216
|
+
raise "Invalid callback: #{callback.inspect}"
|
217
|
+
end
|
218
|
+
rescue StandardError => e
|
219
|
+
Rails.logger.error "Callback failed: #{callback.inspect}, error: #{e.message}"
|
220
|
+
raise
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def current_review_context
|
225
|
+
params[:context]&.to_sym || :default
|
226
|
+
end
|
227
|
+
|
228
|
+
def available_contexts
|
229
|
+
# Get all configured contexts plus default if not explicitly configured
|
230
|
+
contexts = self.class.review_context_configs.keys
|
231
|
+
contexts << :default unless contexts.include?(:default)
|
232
|
+
contexts
|
233
|
+
end
|
234
|
+
|
235
|
+
def context_config
|
236
|
+
context = current_review_context
|
237
|
+
config = self.class.review_context_configs[context]
|
238
|
+
|
239
|
+
# If requesting default context and it's not configured, use the built-in default
|
240
|
+
config = self.class.default_context_config[:default] if context == :default && config.nil?
|
241
|
+
|
242
|
+
# If context is not found and it's not the default, it's invalid
|
243
|
+
raise ArgumentError, "Invalid context '#{context}'. Available contexts: #{available_contexts.join(', ')}" if config.nil?
|
244
|
+
|
245
|
+
Rails.logger.debug "Context config for '#{context}': #{config.inspect}"
|
246
|
+
config
|
247
|
+
end
|
248
|
+
|
249
|
+
def allowed_statuses
|
250
|
+
context_config[:statuses]
|
251
|
+
end
|
252
|
+
|
253
|
+
def valid_transition?(from, to)
|
254
|
+
return true if context_config[:transitions].blank?
|
255
|
+
|
256
|
+
allowed_to = context_config[:transitions][from || context_config[:initial_status]] || []
|
257
|
+
allowed_to.include?(to)
|
258
|
+
end
|
259
|
+
|
260
|
+
def authorize_review_action!
|
261
|
+
# Override for custom auth
|
262
|
+
end
|
263
|
+
|
264
|
+
def before_review_action(review)
|
265
|
+
# Default implementation - can be overridden
|
266
|
+
# Check if there's a custom hook method defined
|
267
|
+
return unless respond_to?(:before_reviewable_action, true)
|
268
|
+
|
269
|
+
before_reviewable_action(review, reviewable_resource, current_review_context)
|
270
|
+
end
|
271
|
+
|
272
|
+
def after_review_action(review)
|
273
|
+
return unless respond_to?(:after_reviewable_action, true)
|
274
|
+
|
275
|
+
after_reviewable_action(review, reviewable_resource, current_review_context)
|
276
|
+
end
|
277
|
+
|
278
|
+
def current_user
|
279
|
+
# Default implementation that can be overridden
|
280
|
+
if respond_to?(:current_reviewer, true)
|
281
|
+
current_reviewer
|
282
|
+
else
|
283
|
+
return super if defined?(super)
|
284
|
+
return @current_user if defined?(@current_user)
|
285
|
+
return session[:user_id] if session && session[:user_id]
|
286
|
+
|
287
|
+
nil
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def model_params
|
292
|
+
# Default implementation that can be overridden
|
293
|
+
resource_name = controller_name.singularize
|
294
|
+
|
295
|
+
# First try the standard Rails pattern: resource_name_params
|
296
|
+
params_method = "#{resource_name}_params"
|
297
|
+
return send(params_method) if respond_to?(params_method, true)
|
298
|
+
|
299
|
+
# Fallback to generic reviewable_params
|
300
|
+
return reviewable_params if respond_to?(:reviewable_params, true)
|
301
|
+
|
302
|
+
# If neither exists, return empty hash (no model updates)
|
303
|
+
{}
|
304
|
+
rescue ActionController::ParameterMissing => e
|
305
|
+
raise e # Re-raise parameter missing errors
|
306
|
+
rescue StandardError => e
|
307
|
+
Rails.logger.warn "Failed to get model params: #{e.message}"
|
308
|
+
{}
|
309
|
+
end
|
310
|
+
|
311
|
+
def model_class
|
312
|
+
return reviewable_model_class if reviewable_model_class
|
313
|
+
|
314
|
+
model_name = controller_name.classify
|
315
|
+
|
316
|
+
controller_namespace = self.class.name.deconstantize
|
317
|
+
if controller_namespace.present?
|
318
|
+
namespaced_model = "#{controller_namespace}::#{model_name}"
|
319
|
+
return namespaced_model.constantize if Object.const_defined?(namespaced_model)
|
320
|
+
end
|
321
|
+
|
322
|
+
return model_name.constantize if Object.const_defined?(model_name)
|
323
|
+
|
324
|
+
raise NameError, "Could not determine model class for #{self.class.name}. " \
|
325
|
+
"Please configure it explicitly using 'reviewable_model ModelClass' " \
|
326
|
+
"in your controller class."
|
327
|
+
rescue NameError => e
|
328
|
+
Rails.logger.error "Model resolution failed for #{self.class.name}: #{e.message}"
|
329
|
+
raise
|
330
|
+
end
|
331
|
+
|
332
|
+
def set_reviewable_resource
|
333
|
+
@reviewable_resource = model_class.find(params[:id])
|
334
|
+
rescue ActiveRecord::RecordNotFound => e
|
335
|
+
render_error(status: :not_found, errors: [e.message])
|
336
|
+
rescue NameError => e
|
337
|
+
render_error(status: :internal_server_error, errors: ["Configuration error: #{e.message}"])
|
338
|
+
end
|
339
|
+
|
340
|
+
def reviewable_resource
|
341
|
+
@reviewable_resource
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
@@ -13,9 +13,14 @@ module Dscf
|
|
13
13
|
render_success(
|
14
14
|
"auth.success.login",
|
15
15
|
data: {
|
16
|
-
user:
|
16
|
+
user: user,
|
17
17
|
access_token: tokens[:access_token],
|
18
18
|
refresh_token: tokens[:refresh_token].refresh_token
|
19
|
+
},
|
20
|
+
serializer_options: {
|
21
|
+
user: {
|
22
|
+
serializer: Dscf::Core::UserAuthSerializer
|
23
|
+
}
|
19
24
|
}
|
20
25
|
)
|
21
26
|
else
|
@@ -34,9 +39,14 @@ module Dscf
|
|
34
39
|
render_success(
|
35
40
|
"auth.success.signup",
|
36
41
|
data: {
|
37
|
-
user:
|
42
|
+
user: user
|
38
43
|
},
|
39
|
-
status: :created
|
44
|
+
status: :created,
|
45
|
+
serializer_options: {
|
46
|
+
user: {
|
47
|
+
serializer: Dscf::Core::UserAuthSerializer
|
48
|
+
}
|
49
|
+
}
|
40
50
|
)
|
41
51
|
else
|
42
52
|
render_error(
|
@@ -57,7 +67,12 @@ module Dscf
|
|
57
67
|
render_success(
|
58
68
|
"auth.success.me",
|
59
69
|
data: {
|
60
|
-
user:
|
70
|
+
user: current_user
|
71
|
+
},
|
72
|
+
serializer_options: {
|
73
|
+
user: {
|
74
|
+
serializer: Dscf::Core::UserAuthSerializer
|
75
|
+
}
|
61
76
|
}
|
62
77
|
)
|
63
78
|
end
|
@@ -101,16 +116,6 @@ module Dscf
|
|
101
116
|
UserRole.create!(user: user, role: role)
|
102
117
|
end
|
103
118
|
|
104
|
-
def user_with_profile(user)
|
105
|
-
user.as_json(
|
106
|
-
only: %i[id email phone],
|
107
|
-
include: {
|
108
|
-
user_profile: {only: %i[first_name last_name verification_status]},
|
109
|
-
roles: {only: %i[name description]}
|
110
|
-
}
|
111
|
-
)
|
112
|
-
end
|
113
|
-
|
114
119
|
def authentication_required?
|
115
120
|
# Skip authentication for login, signup, and refresh endpoints
|
116
121
|
%w[login signup refresh].exclude?(action_name)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
module ReviewableModel
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :reviews, as: :reviewable, class_name: "Dscf::Core::Review", dependent: :destroy
|
8
|
+
end
|
9
|
+
|
10
|
+
def review_for(context = :default)
|
11
|
+
reviews.with_context(context).order(created_at: :desc)
|
12
|
+
end
|
13
|
+
|
14
|
+
def current_review_for(context = :default)
|
15
|
+
review_for(context).first
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_status_for(context = :default)
|
19
|
+
current_review = current_review_for(context)
|
20
|
+
return current_review.status if current_review
|
21
|
+
|
22
|
+
# Return default initial status for zero-config
|
23
|
+
"pending"
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_review_for(context = :default)
|
27
|
+
reviews.build(context: context.to_s)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class Review < ApplicationRecord
|
4
|
+
self.table_name = "dscf_core_reviews"
|
5
|
+
|
6
|
+
belongs_to :reviewable, polymorphic: true
|
7
|
+
belongs_to :reviewed_by, polymorphic: true, optional: true
|
8
|
+
|
9
|
+
validates :context, presence: true
|
10
|
+
|
11
|
+
scope :with_context, ->(ctx) { where(context: ctx.to_s) }
|
12
|
+
|
13
|
+
before_validation :set_default_context
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def set_default_context
|
18
|
+
self.context ||= "default"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -6,6 +6,14 @@ module Dscf
|
|
6
6
|
|
7
7
|
has_many :user_roles, class_name: "Dscf::Core::UserRole"
|
8
8
|
has_many :users, through: :user_roles, class_name: "Dscf::Core::User"
|
9
|
+
|
10
|
+
def self.ransackable_attributes(_auth_object = nil)
|
11
|
+
%w[id code name created_at updated_at]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.ransackable_associations(_auth_object = nil)
|
15
|
+
%w[user_roles users reviews]
|
16
|
+
end
|
9
17
|
end
|
10
18
|
end
|
11
19
|
end
|
@@ -14,6 +14,14 @@ module Dscf
|
|
14
14
|
|
15
15
|
before_create :set_default_temp_password
|
16
16
|
|
17
|
+
def self.ransackable_attributes(_auth_object = nil)
|
18
|
+
%w[id email phone verified_at created_at updated_at]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.ransackable_associations(_auth_object = nil)
|
22
|
+
%w[refresh_tokens user_roles roles businesses addresses documents user_profile]
|
23
|
+
end
|
24
|
+
|
17
25
|
private
|
18
26
|
|
19
27
|
def set_default_temp_password
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class AddressSerializer < ActiveModel::Serializer
|
4
|
+
attributes :id, :address_type, :country, :city, :sub_city, :woreda, :kebele, :house_numbers, :po_box, :latitude, :longitude,
|
5
|
+
:created_at, :updated_at
|
6
|
+
|
7
|
+
belongs_to :user, serializer: UserSerializer
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class BusinessSerializer < ActiveModel::Serializer
|
4
|
+
attributes :id, :name, :description, :contact_email, :contact_phone, :tin_number, :created_at, :updated_at
|
5
|
+
|
6
|
+
belongs_to :user, serializer: Dscf::Core::UserSerializer
|
7
|
+
belongs_to :business_type, serializer: Dscf::Core::BusinessTypeSerializer
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class ReviewSerializer < ActiveModel::Serializer
|
4
|
+
attributes :id, :context, :status, :feedback, :reviewed_at, :created_at, :updated_at
|
5
|
+
|
6
|
+
attribute :reviewable do
|
7
|
+
{
|
8
|
+
id: object.reviewable_id,
|
9
|
+
type: object.reviewable_type
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
belongs_to :reviewed_by, serializer: Dscf::Core::UserAuthSerializer
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class UserAuthSerializer < ActiveModel::Serializer
|
4
|
+
attributes :id, :email, :phone, :verified_at
|
5
|
+
|
6
|
+
has_one :user_profile, serializer: Dscf::Core::UserProfileSerializer
|
7
|
+
has_many :roles, serializer: Dscf::Core::RoleSerializer
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class UserProfileSerializer < ActiveModel::Serializer
|
4
|
+
attributes :id, :first_name, :middle_name, :last_name, :gender, :nationality, :date_of_birth,
|
5
|
+
:place_of_birth, :fayda_number, :occupation, :position_title, :employer_name,
|
6
|
+
:avg_monthly_income, :avg_annual_income, :pep_status, :risk_score, :watchlist_hit,
|
7
|
+
:verification_status, :created_at, :updated_at
|
8
|
+
|
9
|
+
belongs_to :user, serializer: Dscf::Core::UserSerializer
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Dscf
|
2
|
+
module Core
|
3
|
+
class UserSerializer < ActiveModel::Serializer
|
4
|
+
attributes :id, :email, :phone, :verified_at, :created_at, :updated_at
|
5
|
+
|
6
|
+
has_many :user_roles, serializer: Dscf::Core::UserRoleSerializer
|
7
|
+
has_many :roles, serializer: Dscf::Core::RoleSerializer
|
8
|
+
has_many :businesses, serializer: Dscf::Core::BusinessSerializer
|
9
|
+
has_many :addresses, serializer: Dscf::Core::AddressSerializer
|
10
|
+
|
11
|
+
has_one :user_profile, serializer: Dscf::Core::UserProfileSerializer
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateDscfCoreReviews < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :dscf_core_reviews do |t|
|
4
|
+
t.references :reviewable, polymorphic: true, null: false
|
5
|
+
t.string :context
|
6
|
+
t.string :status, default: "pending"
|
7
|
+
t.jsonb :feedback
|
8
|
+
t.references :reviewed_by, polymorphic: true
|
9
|
+
t.datetime :reviewed_at
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/dscf/core/version.rb
CHANGED