blade-setting 0.1.8 → 0.2.1

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.
data/bin/bs CHANGED
@@ -1,33 +1,93 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require_relative '../lib/blade/setting'
4
3
 
4
+ SCRIPT_RAILS = File.join('bin', 'rails')
5
5
  require 'tty-prompt'
6
6
  prompt = TTY::Prompt.new
7
- result = prompt.collect do
8
- key(:setting_path).ask('The generated config file path', default: '/app/settings')
7
+ prompt.warn('Load Rails App Env now...you may need to wait a seconds')
9
8
 
10
- setting_choices = %w(redis sentry influxdb scout_apm send_cloud elastic_search wechat carrierwave)
9
+ def in_rails_application?
10
+ File.exists?(SCRIPT_RAILS)
11
+ end
11
12
 
12
- prompt.say('Please select the config file you want to generate,
13
- (Use arrow keys, press Space to select and Enter to finish, and letter keys to filter)')
14
- key(:configs).multi_select('check configs',
15
- setting_choices, filter: true)
13
+ def ok
14
+ prompt = TTY::Prompt.new
15
+ prompt.ok("generate complete ! check files now")
16
+ exit(0);
17
+ end
18
+
19
+ if in_rails_application?
20
+ app_path = Dir.pwd + '/config/environment'
21
+ require app_path
22
+ prompt.ok('Load Rails Application ENV Success!')
23
+ else
24
+ prompt.error('You are not in Rails app root,please enter your rails app directory and run the cli tool')
25
+ exit(0);
26
+ end
16
27
 
17
- key(:yml_path).ask('The generated yml path', default: '/environments')
28
+ require_relative '../lib/blade/setting'
18
29
 
19
- key(:extra_yml_path).ask('Other environment? (Input words like sit,dit,prod)', default: 'dev,sit,dit,prod') do |q|
20
- q.convert -> (input) {input.split(/,\s*/)}
30
+ menu_result = prompt.collect do
31
+ key(:menu).select('select the menu you want to do') do |menu|
32
+ menu.choice "Generate yml and setting logic files", 1
33
+ menu.choice "Generate Model's crud scaffold", 2
34
+ menu.choice "Add graphql base file to your project", 3
35
+ menu.choice "Add Base File for project [response.rb,application.json.jbuilder, application.helper, base_model_concern]", 4
21
36
  end
22
37
  end
23
38
 
24
- prompt.ok('config complete')
25
- prompt.warn("generating files ...plz don't quit")
39
+ case menu_result[:menu]
40
+ when 1
41
+ result = prompt.collect do
42
+ key(:setting_path).ask('The generated config file path', default: '/app/settings')
43
+
44
+ setting_choices = %w(redis sentry database influxdb scout_apm send_cloud elastic_search wechat carrierwave)
45
+
46
+ prompt.say('Please select the config file you want to generate,
47
+ (Use arrow keys, press Space to select and Enter to finish, and letter keys to filter)')
48
+ key(:configs).multi_select('check configs',
49
+ setting_choices, filter: true)
50
+
51
+ key(:yml_path).ask('The generated yml path', default: '/environments')
52
+
53
+ key(:extra_yml_path).ask('Other environment? (Input words like sit,dit,prod)', default: 'dev,sit,dit,prod') do |q|
54
+ q.convert -> (input) {input.split(/,\s*/)}
55
+ end
56
+ end
57
+
58
+ prompt.ok('config complete')
59
+ prompt.warn("generating files ...plz don't quit")
26
60
  #生成setting logic
27
- Blade::BladeSetting.generate_setting_logic(result[:setting_path], result[:configs])
61
+ Blade::BladeSetting.generate_setting_logic(result[:setting_path], result[:configs])
62
+
63
+ prompt.warn('generating yml files ...')
64
+ Blade::BladeSetting.generate_setting_yml(result[:yml_path], result[:extra_yml_path], result[:configs])
65
+
66
+ prompt.ok("generate complete ! check files now")
67
+
68
+ when 2
69
+ model_result = prompt.collect do
70
+ key(:model_name).ask('enter the model name')
71
+ key(:namespace).ask('enter the controller namespace',default:'api')
72
+ end
73
+ ActiveRecord::Base.connection
74
+ model = Blade::BladeSetting.get_model(model_result[:model_name].classify)
75
+ if (model.blank?)
76
+ prompt.error("Model doesn't exist")
77
+ exit(0);
78
+ end
79
+ prompt.warn("generating files ...please don't quit")
80
+ Blade::BladeSetting.generate_model_template(model)
81
+ Blade::BladeSetting.generate_crud(model,model_result[:namespace])
82
+ ok();
83
+
84
+ when 3
85
+
86
+ when 4
87
+ Blade::BladeSetting.generate_base_files
88
+ ok();
89
+
90
+ end
28
91
 
29
- prompt.warn('generating yml files ...')
30
- Blade::BladeSetting.generate_setting_yml(result[:yml_path],result[:extra_yml_path], result[:configs])
31
92
 
32
- prompt.ok("generate complete ! check files now")
33
93
 
@@ -23,11 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.11"
26
+ spec.add_development_dependency "bundler", ">= 1.1"
27
27
  spec.add_development_dependency "rake", "~> 10.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
- spec.add_dependency "rainbow" ,"~>2.1.0"
30
29
  spec.add_dependency "tty-prompt", "~>0"
31
- spec.add_dependency "activesupport", '~> 5.0'
32
- spec.add_dependency "fileutils","~> 0.7.2"
33
30
  end
@@ -1,23 +1,26 @@
1
- require "uri"
2
- require "net/http"
3
- require "json"
4
- require "rainbow/ext/string"
5
- require "active_support/all"
6
- require 'fileutils'
7
- require 'blade/setting/yml_template'
1
+ require_relative '../blade/setting/yml_template'
2
+ require_relative '../blade/setting/model_template'
3
+ require_relative '../blade/setting/controller_template'
4
+ require_relative '../blade/setting/base_template'
5
+ require 'rails/generators'
8
6
  module Blade
9
7
 
10
8
  class BladeSetting
11
9
 
12
10
  class << self
13
11
 
12
+
13
+ # if in_rails_application? || in_rails_application_subdirectory?
14
+ # exit(0)
15
+ # else
16
+ # exit(1)
17
+ # end
18
+
14
19
  def generate_setting_logic(setting_path, configs = [])
15
20
 
16
21
  configs.each do |config|
17
22
 
18
23
  path = Dir.pwd
19
- p path + setting_path
20
-
21
24
  unless Dir.exist?(path + setting_path)
22
25
  FileUtils.mkdir_p path + setting_path
23
26
  end
@@ -34,11 +37,8 @@ end
34
37
  end
35
38
 
36
39
  def generate_setting_yml(yml_base_path, extra_path, configs = [])
37
-
38
40
  all_environment_paths = extra_path
39
-
40
41
  all_environment_paths.each do |env_path|
41
-
42
42
  path = Dir.pwd
43
43
  unless Dir.exist?(path + yml_base_path + '/' + env_path)
44
44
  FileUtils.mkdir_p path + yml_base_path + '/' + env_path + '/' + 'config'
@@ -49,7 +49,123 @@ end
49
49
  file.write yml_file
50
50
  end
51
51
  end
52
+ end
53
+
54
+ def generate_model_template(model_class)
55
+ model_file = Blade::Setting::ModelTemplate.model_template(model_class)
56
+ path = Dir.pwd + "/app/models/" + model_class.name.downcase + ".rb"
57
+ gt = Blade::Setting::ControllerTemplate::InstallGenerator.new
58
+ file = nil
59
+ file_path = Rails.root.join('app','models',"#{model_class.name.downcase}.rb")
60
+ # if File.exist?(path)
61
+ # file = File.open(path, "w")
62
+ # else
63
+ # file = File.new(path, "w")
64
+ # end
65
+ # file.write model_file;
66
+ gt.create_view_file(file_path,model_file)
67
+ end
68
+
69
+ def generate_crud(model_class, namespace)
70
+
71
+ model = model_class.name
72
+ arg1 = model_class.name.downcase
73
+ args = arg1.pluralize
74
+
75
+ #generate routes
76
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.add_routes(args, namespace)
77
+
78
+ #generate controller
79
+ con_path = Rails.root.join('app', 'controllers', namespace, "#{args}_controller.rb")
80
+ con_file = Blade::Setting::ControllerTemplate::InstallGenerator.controller_tmp(model_class, namespace);
81
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(con_path, con_file)
82
+
83
+
84
+ #generate views
85
+ index_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'index.json.jbuilder')
86
+ common_view_path = Rails.root.join('app', 'views', namespace, 'common', "_#{arg1}.json.jbuilder")
87
+ update_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'update.json.jbuilder')
88
+ create_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'create.json.jbuilder')
89
+ delete_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'destroy.json.jbuilder')
90
+
91
+ index_content = <<-File
92
+
93
+ json.#{args} do
94
+ if @#{args}.present?
95
+ render_json_array_partial(json,@#{args},'common/#{arg1}',:#{arg1})
96
+ else
97
+ {}
98
+ end
99
+ end
100
+ File
101
+ common_view_content = <<-File
102
+ if #{arg1}.present?
103
+ render_json_attrs(json, #{arg1})
104
+ else
105
+ json.#{arg1} {}
106
+ end
107
+
108
+ File
109
+
110
+ create_view_content = <<-File
111
+ if @#{arg1}.present?
112
+ json.#{arg1} do
113
+ render_json_attrs(json, @#{arg1})
114
+ end
115
+ else
116
+ json.#{arg1} {}
117
+ end
118
+ File
119
+ #
120
+ update_view_content = <<-File
121
+ json.#{arg1} do
122
+ if @#{arg1}.present?
123
+ render_json_attrs(json,@#{arg1})
124
+ else
125
+ {}
126
+ end
127
+ end
128
+
129
+ File
130
+
131
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(index_view_path, index_content)
132
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(create_view_path, create_view_content)
133
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(update_view_path, update_view_content)
134
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(common_view_path, common_view_content)
135
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(delete_view_path, '')
136
+
137
+ end
138
+
139
+ def generate_base_files
140
+
141
+ generator = Blade::Setting::ControllerTemplate::InstallGenerator.new
142
+
143
+ application_helper = Blade::Setting::BaseTemplate::APPLICATION_HELPER
144
+ application_builder = Blade::Setting::BaseTemplate::APPLICATION_JSON_BUILDER
145
+ base_model_concern = Blade::Setting::BaseTemplate::BASE_MODEL_CONCERN
146
+ response = Blade::Setting::BaseTemplate::RESPONSE
147
+ response_json = Blade::Setting::BaseTemplate::RESPONSE_JSON
148
+
149
+ application_helper_path = Rails.root.join('app', 'helpers','application_helper.rb')
150
+ application_builder_path = Rails.root.join('app', 'views', 'layouts' ,'application.json.jbuilder')
151
+ response_path = Rails.root.join('app', 'models' ,'response.rb')
152
+ base_model_concern_path = Rails.root.join('app', 'models', 'concerns', 'base_model_concern.rb')
153
+ response_json_path = Rails.root.join('app', 'views', 'common', '_response_status.json.jbuilder')
154
+
155
+ generator.create_view_file(application_builder_path, application_builder)
156
+ generator.create_view_file(application_helper_path, application_helper)
157
+ generator.create_view_file(response_path, response)
158
+ generator.create_view_file(base_model_concern_path, base_model_concern)
159
+ generator.create_view_file(response_json_path, response_json)
160
+ end
161
+
162
+ def generate_custom_yml(name)
163
+ gt = Blade::Setting::ControllerTemplate::InstallGenerator.new
164
+ end
165
+
52
166
 
167
+ def get_model(name)
168
+ ActiveSupport::Dependencies.constantize(name.classify)
53
169
  end
54
170
 
55
171
  end
@@ -0,0 +1,882 @@
1
+ module Blade
2
+ module Setting
3
+
4
+ module BaseTemplate
5
+
6
+
7
+ BASE_MODEL_CONCERN = <<-File
8
+ module BaseModelConcern
9
+ extend ActiveSupport::Concern
10
+
11
+ def self.get_model(model_name)
12
+ ActiveSupport::Dependencies.constantize(model_name.classify)
13
+ end
14
+
15
+ def self.params_blank?(params)
16
+ !params.select {|_k, v| v.blank?}.empty?
17
+ end
18
+
19
+ module ClassMethods
20
+ def get_model(model_name)
21
+ ActiveSupport::Dependencies.constantize(model_name.classify)
22
+ end
23
+
24
+ def permit_params
25
+ name = self.model_name.singular
26
+ p = "("
27
+ self.columns.each {|c|
28
+ if (c.name != 'id')
29
+ p += ":#{'#{c.name}'},"
30
+ end}
31
+ p += ")"
32
+ puts p
33
+ return "ok"
34
+ end
35
+
36
+ def api_params
37
+ name = self.model_name.singular
38
+ self.columns.each {|c| puts "param :#{'#{' "' + name + '[' + c.name + ']" ' }'},String,desc: '#{'#{c.comment}'}' "}
39
+ return "ok"
40
+ end
41
+
42
+ # 获取字段的备注信息
43
+ # 使用 User.column_comments => hash
44
+ def column_comments
45
+ column_comments = self.connection.retrieve_column_comments(self.table_name)
46
+ column_comments
47
+ end
48
+
49
+ # 使用 User.column_comment('username') => '用户名'
50
+ def column_comment(column_name)
51
+ column_name = column_name.to_s
52
+ return '' unless self.column_names.include?(column_name)
53
+
54
+ column_comments = self.connection.retrieve_column_comments(self.table_name)
55
+ comment = column_comments[column_name.to_sym]
56
+ comment
57
+ end
58
+
59
+ # 辅助方法 将传递进来的true false 转换为 是 否
60
+ def true_change(value = '')
61
+ temp_value = value
62
+ case value
63
+ when true, 'true'
64
+ temp_value = '是'
65
+ when false, 'false'
66
+ temp_value = '否'
67
+ when 'un_pass'
68
+ temp_value = '不通过'
69
+ when 'pass'
70
+ temp_value = '通过'
71
+ when 'success'
72
+ temp_value = '成功'
73
+ when 'fail'
74
+ temp_value = '失败'
75
+ when 'change'
76
+ temp_value = '课程确认'
77
+ when 'modify'
78
+ temp_value = '未通过'
79
+ when 'file'
80
+ temp_value = '失败,需补材料'
81
+ when 'internet'
82
+ temp_value = '在线申请'
83
+ when 'paper'
84
+ temp_value = '邮件申请'
85
+ when 'other'
86
+ temp_value = '线下支付'
87
+ when 'liuyangbao'
88
+ temp_value = '留洋宝支付'
89
+ when 'provide_credit_card'
90
+ temp_value = '提供信用卡信息'
91
+ when 'provided', 'provided_cer'
92
+ temp_value = '已提供'
93
+ when 'un_provided'
94
+ temp_value = '未提供'
95
+ when '是'
96
+ temp_value = true
97
+ when '否'
98
+ temp_value = false
99
+ when 'institutional_feedback'
100
+ temp_value = '院校反馈'
101
+ when 'refusal'
102
+ temp_value = '院校拒录取'
103
+ when 'offer'
104
+ temp_value = '成功'
105
+ when 'success_enter'
106
+ temp_value = '付费注册无条件'
107
+ when 'fail_enter'
108
+ temp_value = '付费注册有条件'
109
+ end
110
+
111
+ temp_value
112
+ end
113
+
114
+ # 获取七牛上传文件的凭证
115
+ def get_upload_token
116
+ put_policy = Qiniu::Auth::PutPolicy.new(
117
+ CarrierwaveSetting.qiniu.bucket, # 存储空间
118
+ nil, # 最终资源名,可省略,即缺省为“创建”语义
119
+ 1800, # 相对有效期,可省略,缺省为3600秒后 uptoken 过期
120
+ (Time.now + 30.minutes).to_i # 绝对有效期,可省略,指明 uptoken 过期期限(绝对值),通常用于调试,这里表示半小时
121
+ )
122
+
123
+ uptoken = Qiniu::Auth.generate_uptoken(put_policy) #生成凭证
124
+ bucket_domain = CarrierwaveSetting.qiniu.bucket_domain #存储空间名
125
+
126
+ return uptoken, bucket_domain
127
+ end
128
+
129
+ def es_find_by_id(id)
130
+ $elasticsearch_client.perform_request('GET', "#{'#{self.name.underscore.pluralize}/#{self.name}/#{id}'}")
131
+ end
132
+
133
+
134
+ def search_by_params(options = {})
135
+ result = self.all
136
+ if options.present?
137
+ keys = options.keys
138
+ keys.delete(:page)
139
+ keys.delete(:per)
140
+ keys.each do |key|
141
+ value = options[key]
142
+ next unless value.present? || !value.to_s.empty?
143
+ if key == :order || key == 'order'
144
+ if value.is_a?(Array)
145
+ value.each do |v|
146
+ orders = v.split(' ')
147
+ result = if orders.length == 2
148
+ result.order("#{'#{orders[0]}'} #{'#{orders[1].upcase}'}")
149
+ else
150
+ result.order(value)
151
+ end
152
+ end
153
+ else
154
+ orders = value.split(' ')
155
+ result = if orders.length == 2
156
+ result.order("#{'#{orders[0]}'} #{'#{orders[1].upcase}'}")
157
+ else
158
+ result.order(value)
159
+ end
160
+ end
161
+ elsif key.to_s.include?('like_')
162
+ query = ''
163
+ query_value = {}
164
+ attr_key = key.to_s.gsub('like_', '')
165
+ if attr_key.include?('.')
166
+ ref_table = attr_key.split('.')[0]
167
+ ref_key = attr_key.split('.')[1]
168
+
169
+ if value.is_a?(Array)
170
+ value.each_with_index do |v, i|
171
+ query += "upper(#{'#{attr_key}'}) like :value#{'#{i}'} "
172
+ query += 'or ' if i != value.length - 1
173
+ query_value.merge!({"value#{'#{i}'}": "%#{'#{v.upcase}'}%"})
174
+ end
175
+ result = result.where(query, query_value)
176
+ else
177
+ result = result.where("upper(#{'#{attr_key}'}) like ?", "%#{'#{value.upcase}'}%")
178
+ end
179
+ else
180
+
181
+ if value.is_a?(Array)
182
+ value.each_with_index do |v, i|
183
+ query += "#{'#{self.name.tableize}'}.#{'#{attr_key}'} like :value#{'#{i}'} "
184
+ query += 'or ' if i != value.length - 1
185
+ query_value.merge!({"value#{'#{i}'}": "%#{'#{v.upcase}'}%"})
186
+ end
187
+ result = result.where(query, query_value)
188
+ else
189
+ result = result.where("upper(#{'#{self.name.tableize}'}.#{'#{attr_key}'}) like ?", "%#{'#{value.upcase}'}%") if self.attribute_names.include?(attr_key)
190
+ end
191
+ end
192
+
193
+ # or || 兼容 'students.creator_id'的情况发生 可能传递多个,超过两个
194
+ elsif key.to_s =~ /^or_/
195
+ attr_key = key.to_s.gsub('or_', '')
196
+ values = value.split(' ')
197
+
198
+ if attr_key.include?('.')
199
+ search_key = "#{'#{attr_key}'}" if value.present?
200
+ else
201
+ search_key = "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key) && value.present?
202
+ end
203
+
204
+ query_string = ''
205
+ values.each_with_index do |v, i|
206
+ query_string += "#{'#{search_key}'} = '#{'#{values[i]}'}' or "
207
+ end
208
+ query_string.chomp!(' or ')
209
+
210
+ result = result.where(query_string)
211
+
212
+ # or一个value同时搜多个参数
213
+ elsif key.to_s.include?('&or&')
214
+ # 这边的需求是搜索学校、代理、学生等的拼音名 所以需要同时搜name和name_pinyin 暂时默认是直接需要like的
215
+ # 格式: 'schools.name&or&schools.full_name'
216
+ attr_keys = key.to_s.split('&or&')
217
+ if value.present?
218
+ # query_string = ''
219
+ query_hash = {value: "%#{'#{value.upcase}'}%"}
220
+ query_string = attr_keys.map.with_index do |attr_key, i|
221
+ convert_key = if attr_key.include?('.')
222
+ attr_key
223
+ else
224
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
225
+ end
226
+ convert_key_arr = convert_key.split('.')
227
+ # 用self的话会有问题
228
+ key_type = convert_key_arr.first.classify.constantize.type_for_attribute(convert_key_arr.last).type.to_s.classify
229
+ key_type == String.name ? "upper(#{'#{convert_key}'}) like :value or " : "#{'#{convert_key}'} = :value or "
230
+ end.flatten.join[0..-5]
231
+ result = result.where(query_string, query_hash)
232
+ end
233
+ elsif key.to_s =~ /^compare_/
234
+ attr_key = key.to_s.gsub(/^compare_/, '')
235
+ if value.present?
236
+ query_hash = {}
237
+ query_string = ""
238
+ if attr_key =~ /^lt_/
239
+ attr_key.gsub!(/^lt_/, '')
240
+ convert_key = if attr_key.include?('.')
241
+ attr_key
242
+ else
243
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
244
+ end
245
+ query_hash = {value: "#{'#{value.to_d}'}"}
246
+ query_string = "#{'#{convert_key}'} <= :value "
247
+ elsif attr_key =~ /^bt_/
248
+ attr_key.gsub!(/^bt_/, '')
249
+ convert_key = if attr_key.include?('.')
250
+ attr_key
251
+ else
252
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
253
+ end
254
+ query_hash = {min: "#{'#{value.split(' ')[0]}'}", max: "#{'#{value.split(' ')[1]}'}"}
255
+ query_string = "#{'#{convert_key}'} >= :min and #{'#{convert_key}'} <= :max "
256
+ elsif attr_key =~ /^gt_/
257
+ attr_key.gsub!(/^gt_/, '')
258
+ convert_key = if attr_key.include?('.')
259
+ attr_key
260
+ else
261
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
262
+ end
263
+ query_hash = {value: "#{'#{value.to_d}'}"}
264
+ query_string = "#{'#{convert_key}'} >= :value "
265
+ end
266
+ result = result.where(query_string, query_hash)
267
+ end
268
+ #between
269
+ elsif key.to_s.include?('between_')
270
+ attr_key = key.to_s.gsub('between_', '')
271
+ front, back = value.split(',')
272
+ if attr_key.include?('.')
273
+ result = result.between_fields("#{'#{attr_key}'}", front, back) if value.present? && value.split(',').length == 2
274
+ else
275
+ puts "betewwen #{'#{front}'} #{'#{back}'}"
276
+ result = result.between_fields("#{'#{self.name.tableize}'}.#{'#{attr_key}'}", front, back) if self.attribute_names.include?(attr_key) && value.present? && value.split(',').length == 2
277
+ end
278
+ elsif key.to_s.include?('array_column_')
279
+ attr_key = key.to_s.gsub('array_column_', '')
280
+ result = result.where("#{'#{attr_key}'} && ARRAY[?]::varchar[]", value)
281
+ elsif key.to_s.include?('not_')
282
+ attr_key = key.to_s.gsub('not_', '')
283
+ result = result.where.not("#{'#{attr_key}'} = ?", "#{'#{value}'}")
284
+ else
285
+ key = key.to_s.remove('between_').remove('like_').remove('not_')
286
+ if key.include?('.')
287
+ result = result.where(key.to_sym => value)
288
+ else
289
+ result = result.where("#{'#{self.name.tableize}'}.#{'#{key}'}".to_sym => value) if self.attribute_names.include?(key)
290
+ end
291
+ end
292
+ end
293
+ end
294
+ result
295
+ end
296
+
297
+ def resources_search_by_params(resources, options = {})
298
+ result = resources
299
+ if options.present?
300
+ keys = options.keys
301
+ keys.delete(:page)
302
+ keys.delete(:per)
303
+ keys.each do |key|
304
+ value = options[key]
305
+ next unless value.present? || !value.to_s.empty?
306
+ if key == :order || key == 'order'
307
+ orders = value.split(' ')
308
+
309
+ result = if orders.length == 2
310
+ result.order(orders[0].to_sym => orders[1].to_sym)
311
+ else
312
+ result.order(value)
313
+ end
314
+ else
315
+ result = result.where(key.to_sym => value) if result.model.instance_methods.include?(key) || result.model.attribute_names.include?(key.to_s)
316
+ if key.to_s.include?('like_')
317
+ attr_key = key.to_s.gsub('like_', '')
318
+ if attr_key.include?('.')
319
+ result = result.where("#{'#{attr_key}'} like ?", "%#{'#{value}'}%")
320
+ else
321
+ result = result.where("#{'#{result.model.name.tableize}'}.#{'#{attr_key}'} like ?", "%#{'#{value}'}%") if result.model.attribute_names.include?(attr_key)
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
327
+ result
328
+ end
329
+
330
+ def search_by_hash(args, result_objects = nil)
331
+ result = result_objects.present? ? result_objects : self.all
332
+
333
+ if args.present?
334
+ args.each_key do |key|
335
+ value = args[key]
336
+
337
+ next unless value.present? || !value.to_s.empty?
338
+
339
+ result = result.where("#{'#{self.name.tableize}'}.#{'#{key}'} like ?", "%#{'#{args[key]}'}%") if self.attribute_names.include?(key)
340
+ end
341
+ end
342
+
343
+ result
344
+ end
345
+
346
+ def validate_present?(params)
347
+ params.select(&:present?).empty?
348
+ end
349
+
350
+ def validate_blank?(params)
351
+ return true if params.blank?
352
+ !params.select(&:blank?).empty?
353
+ end
354
+
355
+ def validate_all_present?(*args)
356
+ args.select(&:blank?).empty?
357
+ end
358
+
359
+ def validate_all_blank?(*args)
360
+ return true if args.blank?
361
+ args.select(&:present?).empty?
362
+ end
363
+
364
+ def exist_resource(resource_id)
365
+ return nil if resource_id.blank?
366
+
367
+ self.find_by_id(resource_id)
368
+ end
369
+
370
+ # 为简单的对象保存记录
371
+ # 作者 liangyuzhe 20161225
372
+ def save_values_for_object(options)
373
+ record = nil
374
+ response = Response.rescue do |_res|
375
+ column_sym = (self.columns.map(&:name) - %w(id deleted_at created_at updated_at)).map(&:to_sym)
376
+ hash = {}
377
+ column_sym.each do |c|
378
+ hash.merge!(c => options[c])
379
+ end
380
+ record = self.create!(hash)
381
+ end
382
+ [response, record]
383
+ end
384
+
385
+ # postgresql查询jsonb数据方法
386
+ # params white_list String Array
387
+ # params params ActionController::Parameters
388
+ # params jsonb_column_name string
389
+ # 作者 liangyuzhe 20170108
390
+ #
391
+ def search_by_action_controller_params_for_jsonb(params, white_list, column_name)
392
+ if white_list.present?
393
+ if white_list.is_a? String
394
+ permitted = params.permit(white_list)
395
+ elsif white_list.is_a? Array
396
+ permitted = {}
397
+ white_list.each {|w| permitted.merge!(params.permit(w)) if w.is_a? String}
398
+ end
399
+ end
400
+ if permitted.present?
401
+ find_result(permitted.to_json, column_name)
402
+ else
403
+ self.all
404
+ end
405
+ rescue => e
406
+ yloge e, '传入的数据有问题'
407
+ end
408
+
409
+ # 得到数据方法
410
+ def find_result(permitted, column_name)
411
+ query = nil
412
+ self.columns.map(&:name).each do |c|
413
+ if column_name == c
414
+ query = self.where("#{'#{column_name}'} @> :permitted", permitted: permitted)
415
+ end
416
+ end
417
+ query
418
+ rescue => e
419
+ yloge e, '传入的数据有问题'
420
+ end
421
+
422
+
423
+ def hash_keys_to_symbol(hash)
424
+ {}.tap do |h|
425
+ hash.each {|key, value| h[key.to_sym] = map_value(value)}
426
+ end
427
+ end
428
+ end
429
+
430
+ # 为简单的对象更新记录
431
+ # 作者 liangyuzhe 20161225
432
+ def update_values_for_object(options)
433
+ record = nil
434
+ response = Response.rescue do |_res|
435
+ column_sym = (self.class.columns.map(&:name) - %w(id deleted_at created_at updated_at)).map(&:to_sym)
436
+ hash = {}
437
+ column_sym.each do |c|
438
+ hash.merge!(c => options[c]) if options[c].present?
439
+ end
440
+ record = self.update!(hash)
441
+ end
442
+ [response, record]
443
+ end
444
+
445
+ #构造查询条件
446
+ def self.build_search(options = {})
447
+ if options.present?
448
+ search_string = "where "
449
+ keys = options.keys
450
+ keys.each do |key|
451
+ value = options[key]
452
+ Rails.logger.info ">>>> build_search key: #{'#{key.to_s}'}"
453
+ Rails.logger.info ">>>> build_search value: #{'#{value.to_s}'}"
454
+
455
+ next unless (value.present? || !value.to_s.empty?) and value != "''" and !value.blank?
456
+ #模糊查询
457
+ if key.to_s.include?('like_')
458
+ attr_key = key.to_s.gsub('like_', '')
459
+ str = "#{'#{attr_key}'} like '%#{'#{value}'}%'"
460
+
461
+ #否定查询
462
+ elsif key.to_s.include?('no_')
463
+ attr_key = key.to_s.gsub('no_', '')
464
+ if attr_key == 'academic_category'
465
+ str = "#{'#{attr_key}'} != '#{'#{value.upcase}'}'"
466
+ else
467
+ str = "#{'#{attr_key}'} not like '%#{'#{value}'}%'"
468
+ end
469
+
470
+ #按日期区间查询
471
+ elsif key.to_s.include?('between_')
472
+ attr_key = key.to_s.gsub('between_', '')
473
+ date_array = value.split(',').collect {|item| item.tr('/', '-')}
474
+ str = ''
475
+ if date_array.size > 1
476
+ str = "#{'#{attr_key}'} between '#{'#{date_array[0]}'}' and '#{'#{date_array[1]}'}'"
477
+ elsif value[0].blank?
478
+ str = "#{'#{attr_key}'} <= '#{'#{date_array[0]}'}'"
479
+ elsif value[-1].blank?
480
+ str = "#{'#{attr_key}'} >= '#{'#{date_array[0]}'}'"
481
+ end
482
+
483
+ # #由于数据存在异常 用于特定的按月查询
484
+ # elsif key.to_s.include?('special_')
485
+ # attr_key = key.to_s.gsub('special_', '')
486
+ # begin_month = value.split(' ')[0]
487
+ # end_month = value.split(' ')[1]
488
+ # str = "(#{'#{attr_key}'} between '#{'#{begin_month}'}' and '#{'#{end_month}'}' or in_account_time_month between '#{'#{begin_month}'}' and '#{'#{end_month}'}')"
489
+
490
+ #由于数据存在异常 用于特定的按月查询
491
+ elsif key.to_s.include?('special_')
492
+ attr_key = key.to_s.gsub('special_', '')
493
+ date_array = value.split.collect {|item| item.tr('/', '-')}
494
+ str = ''
495
+ if date_array.size > 1
496
+ str = "(#{'#{attr_key}'} between '#{'#{date_array[0]}'}' and '#{'#{date_array[1]}'}' or in_account_time_month between '#{'#{date_array[0]}'}' and '#{'#{date_array[1]}'}')"
497
+ elsif value[0].blank?
498
+ str = "(#{'#{attr_key}'} <= '#{'#{date_array[0]}'}' or in_account_time_month <= '#{'#{date_array[0]}'}')"
499
+ elsif value[-1].blank?
500
+ str = "(#{'#{attr_key}'} >= '#{'#{date_array[0]}'}' or in_account_time_month >= '#{'#{date_array[0]}'}')"
501
+ end
502
+
503
+ elsif key.to_s.end_with?('_id')
504
+ str = ''
505
+ if value.size > 0
506
+ tmp = value.map {|item| item.to_i}.to_s
507
+ tmp.tr!('[', '(')
508
+ tmp.tr!(']', ')')
509
+ str = "#{'#{key}'} in #{'#{tmp}'}"
510
+ end
511
+
512
+ #多选模糊查询
513
+ elsif key.to_s.include?('multi_')
514
+ str = ""
515
+ attr_key = key.to_s.gsub('multi_', '')
516
+ value.each do |a|
517
+ next unless a.present?
518
+ tmp = "#{'#{attr_key}'} like '%#{'#{a}'}%'"
519
+ if a != value.first and str != ""
520
+ tmp = " or " + tmp
521
+ end
522
+ str += tmp
523
+ end
524
+ str = "(#{'#{str}'})"
525
+ else
526
+ if key == 'academic_category'
527
+ str = "#{'#{key}'} = '#{'#{value.upcase}'}'"
528
+ else
529
+ str = "#{'#{key.to_s}'}='#{'#{value}'}'"
530
+ end
531
+ end
532
+ if key != options.keys.first and search_string != "where "
533
+ str = " and " + str
534
+ end
535
+
536
+ search_string += str
537
+ end
538
+ if search_string == "where "
539
+ search_string = ""
540
+ end
541
+ # log(search_string)
542
+ return search_string
543
+ end
544
+ end
545
+
546
+ module AttributeType
547
+ DECIMAL = 'decimal'
548
+ STRING = 'string'
549
+ DATE = 'date'
550
+ end
551
+
552
+ def generate_pinyin_when_create
553
+ if self.deleted_at.blank?
554
+ self.class.attribute_names.each do |attribute|
555
+ self[attribute.intern] = PinYin.of_string(self[attribute.remove('_pinyin').intern]).join if attribute.include?('_pinyin')
556
+ end
557
+ end
558
+ end
559
+
560
+ end
561
+
562
+ File
563
+ # frozen_string_literal: true
564
+
565
+
566
+ APPLICATION_JSON_BUILDER = <<-File
567
+ json.partial! 'common/response_status', response: @response
568
+ page_params = {}
569
+ instance_variables.each do |iv|
570
+ begin
571
+ object = self.instance_variable_get(iv)
572
+ if object.respond_to?(:total_pages) && object.respond_to?(:total_count) && iv !=:@_config
573
+ page_params.merge!({total_pages: object.total_pages, total_count: object.total_count})
574
+ end
575
+ rescue => e
576
+ ylogi e
577
+ end
578
+ end
579
+
580
+ json.data do
581
+ json.merge! JSON.parse(yield)
582
+ if page_params.present?
583
+ json.merge! page_params
584
+ end
585
+ end
586
+ File
587
+
588
+ APPLICATION_HELPER = <<-File
589
+ # encoding: UTF-8
590
+ # frozen_string_literal: true
591
+
592
+ module ApplicationHelper
593
+ #
594
+ # 渲染json返回属性
595
+ #
596
+ # @param json [Unknown] json对象
597
+ # @param obj [ActiveRecord] 数据库表的对象
598
+ # @param attrs [Array] 需要渲染的表属性符号数组
599
+ #
600
+ def render_json_attrs(json, obj, attrs = nil)
601
+ # Rails.logger.info "obj=>#{'#{obj}'}"
602
+ if attrs.blank?
603
+ attrs = obj.class.columns.map(&:name)
604
+ end
605
+ attrs.each do |column|
606
+ next unless column != 'deleted_at'
607
+ key = column.to_sym
608
+ column_type = obj.class.columns.select { |c| c.name == column.to_s }.first.type
609
+ value = obj.__send__(column.to_sym)
610
+ if value.present?
611
+ value = value.to_time&.strftime('%F') if key.to_s == 'date' || key.to_s.include?('_date')
612
+ # 兼容代码
613
+ value = value.to_time&.strftime('%F %H:%M') if key.to_s =~ /_at$/ || key.to_s =~ /_time$/
614
+
615
+ # if (/^([a-zA-Z]+_)*id$/ =~ key).present? || key.to_s == 'whodunnit'
616
+ # if value.class == Array
617
+ # value = value.map { |v| v }
618
+ # else
619
+ # value = value
620
+ # end
621
+ # end
622
+ else
623
+ value = ''
624
+ value = false if value != true && column_type == :boolean
625
+ end
626
+ json.__send__(key, value)
627
+ end
628
+ end
629
+
630
+ def render_json_attrs_except(json, object, attrs = nil)
631
+ attrs = object.class.columns.map(&:name) - (attrs.map { |x| x.to_s }) if attrs.present?
632
+
633
+ render_json_attrs(json, object, attrs)
634
+ end
635
+
636
+ def render_json_array_partial(obj, array, particle, as)
637
+ obj.__send__('array!', array, partial: particle, as: as)
638
+ end
639
+
640
+ #
641
+ # 将准确时间转换成相对于当前的时间
642
+ #
643
+ def timeago(time)
644
+ return '' if time.blank?
645
+
646
+ if time.is_a?(String)
647
+ time = begin
648
+ Time.parse(time)
649
+ rescue
650
+ ''
651
+ end
652
+ elsif time.is_a?(Time)
653
+ time = time
654
+ end
655
+
656
+ return '' if time.blank?
657
+
658
+ time_now = Time.now
659
+
660
+ interval = (time_now - time).to_i
661
+
662
+ case interval
663
+ when 0 .. 3600
664
+ minutes = interval / 60
665
+
666
+ time = I18n.t('timeago.minutes', minutes: minutes)
667
+
668
+ when 3601 .. 86_400
669
+ hours = interval / 3600
670
+
671
+ time = I18n.t('timeago.hours', hours: hours)
672
+
673
+ when 86_401 .. 2_592_000
674
+ days = interval / 86_400
675
+
676
+ time = I18n.t('timeago.days', days: days)
677
+
678
+ else
679
+ time = time.strftime('%F %H:%M')
680
+ end
681
+
682
+ time
683
+ end
684
+
685
+ def get_model(model_name)
686
+ ActiveSupport::Dependencies.constantize(model_name.classify)
687
+ end
688
+
689
+
690
+ end
691
+ File
692
+
693
+ RESPONSE = <<-File
694
+ # frozen_string_literal: true
695
+ class Response
696
+ # 添加属性
697
+ attr_accessor :code, :message, :messages
698
+
699
+ #
700
+ # 状态码
701
+ #
702
+ module Code
703
+ # 添加模型常量国际化方法
704
+ # include Dictionary::Module::I18n
705
+
706
+ ################################################################################
707
+ #
708
+ # 20000 成功
709
+ #
710
+ ################################################################################
711
+
712
+ SUCCESS = '20000'
713
+
714
+ ################################################################################
715
+ #
716
+ # 3xxxx 数据相关
717
+ #
718
+ ################################################################################
719
+
720
+ # 用户绑定第三方账户
721
+
722
+ # 第三方账户已绑定其它用户
723
+ PROVIDER_BIND_ANOTHER_USER = '30010'
724
+
725
+ ################################################################################
726
+ #
727
+ # 4xxxx 业务相关
728
+ #
729
+ ################################################################################
730
+
731
+ # 非法请求
732
+ INVALID_REQUEST = '40300'
733
+
734
+ # 终端密钥错误
735
+ INVALID_TERMINAL_SESSION_KEY = '40301'
736
+
737
+ # 用户密钥错误
738
+ INVALID_USER_SESSION_KEY = '40302'
739
+
740
+ # 超出请求限制数
741
+ EXCEED_REQUEST_LIMIT = '40303'
742
+
743
+ # 版本号不适配
744
+ NOT_COMPATIBLE_REVISION = '40304'
745
+
746
+ # 访问令牌过期
747
+ ACCESS_TOKEN_EXPIRED = '40305'
748
+
749
+ ################################################################################
750
+ #
751
+ # 5xxxx 系统相关
752
+ #
753
+ ################################################################################
754
+
755
+ # 未知错误(通常在捕捉异常后使用)
756
+ ERROR = '50000'
757
+
758
+ # 请求参数缺失
759
+ # Todo: 移动到数据相关
760
+ MISS_REQUEST_PARAMS = '50001'
761
+
762
+ # 数据处理错误
763
+ # Todo: 移动到数据相关
764
+ DATA_PROCESS_ERROR = '51000'
765
+
766
+ # 数据缺失错误
767
+ # Todo: 移动到数据相关
768
+ DATA_MISS_ERROR = '51001'
769
+
770
+ ORDER_PAYMENT_COMPLETED = '55000'
771
+
772
+ NEED_LOGIN = '40100'
773
+
774
+ # 全部
775
+ # ALL = get_all_constants.map { |constant| constant.to_s.downcase }
776
+ end
777
+
778
+ #
779
+ # 实例对象
780
+ #
781
+ # @param code [Code] 编码
782
+ # @param message [String] 返回信息
783
+ # @param messages [Array] 可能的错误信息
784
+ #
785
+ # @return [Response] 返回实例化的对象
786
+ #
787
+ def initialize(code = Code::SUCCESS, message = '', messages = [])
788
+ @code = code
789
+ @message = message
790
+ @messages = messages
791
+ end
792
+
793
+ def method_missing(method_id, *arguments, &block)
794
+ method_message = *arguments.join
795
+ if (method_id.to_s =~ /^raise_[\w]+/) == 0
796
+ error_type = method_id.to_s.split('raise_')[1].upcase!
797
+ @code = "Response::Code::#{'#{error_type}'}".constantize
798
+ @message = method_message
799
+ raise StandardError.new(method_message)
800
+ else
801
+ super
802
+ end
803
+ end
804
+
805
+ def self.rescue(catch_block = nil)
806
+ response = self.new
807
+ Rails.logger.info "response为#{'#{response.to_json}'}"
808
+ begin
809
+ yield(response)
810
+ rescue => e
811
+ if (e.class != StandardError && ENV['RAILS_ENV'] == 'development')
812
+ throw e
813
+ end
814
+ catch_block.call if catch_block.present?
815
+ if response.code == Code::SUCCESS
816
+ response.code = Code::ERROR
817
+ response.message = e.message
818
+ end
819
+ end
820
+
821
+ response
822
+ end
823
+
824
+ #
825
+ # 生成一个错误异常
826
+ #
827
+ # @example
828
+ # Response.error
829
+ # => #<Response:0x007feb7b049638 @code="50000", @message="未知异常", @messages=[]>
830
+ #
831
+ # @return [Response] 响应对象
832
+ #
833
+ def self.error message = nil
834
+ response = self.new
835
+ response.code = Code::ERROR
836
+ response.message = message || '未知异常'
837
+
838
+ response
839
+ end
840
+
841
+ # private
842
+
843
+ #
844
+ # 抛出异常
845
+ #
846
+ # @example
847
+ # Response.new.raise(Response::Code::ERROR, 'some error message')
848
+ #
849
+ # @param code [Code] 编码
850
+ # @param message [String] 信息
851
+ #
852
+ # def _raise(code, message)
853
+ # @code = code
854
+ # @message = message
855
+ #
856
+ # raise StandardError, message
857
+ # end
858
+ end
859
+
860
+ File
861
+
862
+ RESPONSE_JSON = <<-File
863
+ # frozen_string_literal: true
864
+ json.status do |res|
865
+ if response.present?
866
+ res.code response.code || Response::Code::ERROR
867
+ res.message response.message
868
+ else
869
+ res.code Response::Code::ERROR
870
+ res.message ''
871
+ end
872
+
873
+ res.no SecureRandom.uuid
874
+ end
875
+
876
+ File
877
+
878
+ end
879
+
880
+ end
881
+
882
+ end