bmc 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/README.md +28 -0
- data/Rakefile +41 -0
- data/app/assets/config/bmc_manifest.js +2 -0
- data/app/controllers/bmc/application_controller.rb +3 -0
- data/app/controllers/bmc/filters_controller.rb +38 -0
- data/app/controllers/concerns/bmc/api_controller_concern.rb +69 -0
- data/app/controllers/concerns/bmc/back_url_concern.rb +26 -0
- data/app/emails/bmc/email.rb +113 -0
- data/app/filters/bmc/filter/by_date.rb +6 -0
- data/app/filters/bmc/filter/by_date_begin.rb +7 -0
- data/app/filters/bmc/filter/by_date_end.rb +7 -0
- data/app/filters/bmc/filter/by_date_or_datetime_period.rb +56 -0
- data/app/filters/bmc/filter/by_date_period.rb +5 -0
- data/app/filters/bmc/filter/by_datetime_period.rb +5 -0
- data/app/filters/bmc/filter/by_key_value.rb +27 -0
- data/app/filters/bmc/filter/by_key_values.rb +13 -0
- data/app/filters/bmc/filter.rb +86 -0
- data/app/forms/bmc/mini_form_object.rb +29 -0
- data/app/helpers/bmc/all_helpers.rb +15 -0
- data/app/helpers/bmc/bootstrap_helper.rb +63 -0
- data/app/helpers/bmc/button_helper.rb +150 -0
- data/app/helpers/bmc/filters_helper.rb +16 -0
- data/app/helpers/bmc/font_awesome_helper.rb +67 -0
- data/app/helpers/bmc/form_helper.rb +24 -0
- data/app/helpers/bmc/i18n_helper.rb +5 -0
- data/app/helpers/bmc/link_helper.rb +42 -0
- data/app/helpers/bmc/pagination_helper.rb +22 -0
- data/app/helpers/bmc/routes_helper.rb +24 -0
- data/app/helpers/bmc/sorting_helper.rb +55 -0
- data/app/helpers/bmc/text_helper.rb +127 -0
- data/app/helpers/h.rb +3 -0
- data/app/jobs/concerns/bmc/setup_job_concern.rb +35 -0
- data/app/libs/bmc/collection_update.rb +38 -0
- data/app/libs/bmc/fcm/notifier.rb +32 -0
- data/app/libs/bmc/fcm/request.rb +54 -0
- data/app/libs/bmc/mini_model_serializer/serialize.rb +30 -0
- data/app/libs/bmc/mini_model_serializer/serializer.rb +23 -0
- data/app/libs/bmc/monkey.rb +39 -0
- data/app/libs/bmc/sortable_uuid_generator.rb +11 -0
- data/app/libs/bmc/token_generator.rb +37 -0
- data/app/mailers/bmc/application_mailer.rb +2 -0
- data/app/mailers/bmc/generic_mailer.rb +9 -0
- data/app/models/concerns/bmc/active_record_uuid_concern.rb +17 -0
- data/app/models/concerns/bmc/default_values_concern.rb +14 -0
- data/app/models/concerns/bmc/model_i18n.rb +56 -0
- data/app/models/concerns/bmc/model_to_s.rb +9 -0
- data/app/models/concerns/bmc/pluck_distinct.rb +13 -0
- data/app/models/concerns/bmc/pluck_to_hash.rb +9 -0
- data/app/models/concerns/bmc/polymorphic_id.rb +37 -0
- data/app/models/concerns/bmc/search.rb +28 -0
- data/app/models/concerns/bmc/timestamp_helpers.rb +17 -0
- data/app/serializers/bmc/serializers/base.rb +63 -0
- data/app/serializers/bmc/serializers/xlsx.rb +38 -0
- data/app/serializers/bmc/serializers.rb +2 -0
- data/app/sms/bmc/sms/application_sms.rb +42 -0
- data/app/sms/bmc/sms/message.rb +25 -0
- data/app/sms/bmc/sms/strategies/amazon_sns.rb +48 -0
- data/app/sms/bmc/sms/strategies/base.rb +15 -0
- data/app/sms/bmc/sms/strategies/test.rb +10 -0
- data/app/sms/bmc/sms.rb +35 -0
- data/app/sorters/bmc/sorter.rb +26 -0
- data/app/views/bmc/search/_form.html.slim +1 -0
- data/app/views/bmc/search/_form_bs3.html.slim +13 -0
- data/app/views/bmc/search/_form_bs4.html.slim +9 -0
- data/app/views/bmc/search/_form_bs5.html.slim +8 -0
- data/app/views/kaminari/bootstrap4/_first_page.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_gap.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_last_page.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_next_page.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_page.html.slim +6 -0
- data/app/views/kaminari/bootstrap4/_paginator.html.slim +12 -0
- data/app/views/kaminari/bootstrap4/_prev_page.html.slim +2 -0
- data/config/locales/actions.en.yml +76 -0
- data/config/locales/actions.fr.yml +76 -0
- data/config/locales/attributes.en.yml +108 -0
- data/config/locales/attributes.fr.yml +108 -0
- data/config/locales/common.en.yml +39 -0
- data/config/locales/common.fr.yml +39 -0
- data/config/locales/dates.fr.yml +8 -0
- data/config/locales/errors.en.yml +5 -0
- data/config/locales/errors.fr.yml +5 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20000101000000_enable_bmc_extensions.rb +7 -0
- data/lib/bmc/active_model_custom_error_messages.rb +23 -0
- data/lib/bmc/active_model_type_cast.rb +52 -0
- data/lib/bmc/config.rb +19 -0
- data/lib/bmc/core_and_rails_ext.rb +3 -0
- data/lib/bmc/engine.rb +36 -0
- data/lib/bmc/engine_file.rb +10 -0
- data/lib/bmc/errors_middleware.rb +50 -0
- data/lib/bmc/form_back_url.rb +18 -0
- data/lib/bmc/version.rb +3 -0
- data/lib/bmc.rb +5 -0
- data/lib/tasks/bmc_tasks.rake +4 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1f44e62a2b31e04cc714d58d89b5bf5752a26cb99b2e9013da86a5a7c7b52a15
|
4
|
+
data.tar.gz: 71693371c8912830ecbdbde9a6582c357dd0fdf63c8233ab1fc8c1e52723e828
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a865f824ca4aa26d2cb0d0e92360d4aa88f7a0e8cfa7a10d32d35875bfe4a33c53c7cd6f0809da4810c613426b9a56b8d7b3e29fad162f5e816f5137cbe7496
|
7
|
+
data.tar.gz: a3febb518d32c8bccbb22b414fad2bbbe3473c4689b66d76cf7836b5bde532be34e0b22485c344dd24c59d70b0522e214357e50379ee3b60b1aaf78b44946748
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# BMC
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'bmc'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install bmc
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'BMC'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
task default: :test
|
38
|
+
|
39
|
+
task "assets:precompile" do
|
40
|
+
Rake::Task["app:assets:precompile"].invoke
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class BMC::FiltersController < BMC::ApplicationController
|
2
|
+
skip_before_action :verify_authenticity_token, raise: false
|
3
|
+
skip_before_action :authenticate_user!, raise: false
|
4
|
+
skip_after_action :verify_authorized, raise: false
|
5
|
+
skip_after_action :verify_policy_scoped, raise: false
|
6
|
+
|
7
|
+
def create
|
8
|
+
filters = BMC::Filter.new(cookies)
|
9
|
+
new_filters = params.fetch(:filters, {}).permit!.to_h
|
10
|
+
filters.merge new_filters
|
11
|
+
|
12
|
+
# Rewrite cookie with 1 year expiry
|
13
|
+
cookies[:filters] = {
|
14
|
+
:value => cookies[:filters],
|
15
|
+
:expires => 1.year.from_now,
|
16
|
+
:path => "/",
|
17
|
+
}
|
18
|
+
|
19
|
+
redirect_to back_url
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def back_url
|
25
|
+
url = [
|
26
|
+
params[:form_url],
|
27
|
+
request.referer,
|
28
|
+
main_app.try(:root_path),
|
29
|
+
"/",
|
30
|
+
].find(&:present?)
|
31
|
+
|
32
|
+
# Delete page param
|
33
|
+
base, query_string = url.split("?")
|
34
|
+
query_string = query_string.to_s.split("&").delete_if { |p| p.include?("page=") }.join("&")
|
35
|
+
query_string = "?#{query_string}" if query_string.present?
|
36
|
+
base + query_string
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module BMC::ApiControllerConcern
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def render_json(json = {}, options = {})
|
7
|
+
json.reverse_merge!(current_user: current_user)
|
8
|
+
options.reverse_merge!(current_user: current_user)
|
9
|
+
|
10
|
+
json = BMC::MiniModelSerializer::Serialize.call(json, options)
|
11
|
+
|
12
|
+
render options.merge(json: json)
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_json_error(any_object, options = {})
|
16
|
+
if any_object.is_a?(ActiveModel::Validations)
|
17
|
+
json = {
|
18
|
+
:error => json_error_string_for_model(any_object),
|
19
|
+
:model_errors => json_errors_hash_for_model(any_object),
|
20
|
+
}
|
21
|
+
elsif any_object.is_a?(String)
|
22
|
+
json = {error: any_object}
|
23
|
+
else
|
24
|
+
json = any_object
|
25
|
+
end
|
26
|
+
|
27
|
+
options[:status] ||= :unprocessable_entity
|
28
|
+
|
29
|
+
render_json(json, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def json_errors_hash_for_model(object)
|
33
|
+
object.errors
|
34
|
+
.to_hash
|
35
|
+
.map { |a, m| [a, message: m.first, full_message: object.errors.full_message(a, m.first)] }
|
36
|
+
.uniq(&:first)
|
37
|
+
.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def json_error_string_for_model(object)
|
41
|
+
json_errors_hash_for_model(object).values.pluck(:full_message).join(", ")
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_not_found
|
45
|
+
render_json_error t("errors.not_found"), status: :not_found
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_forbidden
|
49
|
+
render_json_error t("errors.forbidden"), status: :forbidden
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_unauthorized
|
53
|
+
render_json_error t("errors.unauthorized"), status: :unauthorized
|
54
|
+
end
|
55
|
+
|
56
|
+
def render_forbidden_or_unauthorized
|
57
|
+
current_user ? render_forbidden : render_unauthorized
|
58
|
+
end
|
59
|
+
|
60
|
+
included do |controller|
|
61
|
+
if controller < ActionController::Rescue
|
62
|
+
if defined?(Pundit::NotAuthorizedError)
|
63
|
+
rescue_from Pundit::NotAuthorizedError, with: :render_forbidden_or_unauthorized
|
64
|
+
end
|
65
|
+
|
66
|
+
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BMC::BackUrlConcern
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def default_back_url
|
7
|
+
end
|
8
|
+
|
9
|
+
def back_url
|
10
|
+
url = [
|
11
|
+
params[:back_url],
|
12
|
+
request.referer,
|
13
|
+
default_back_url,
|
14
|
+
main_app.try(:root_path),
|
15
|
+
"/",
|
16
|
+
].find(&:present?)
|
17
|
+
|
18
|
+
uri = URI.parse(url)
|
19
|
+
uri.host = nil
|
20
|
+
uri.port = nil
|
21
|
+
uri.scheme = nil
|
22
|
+
uri.user = nil
|
23
|
+
uri.password = nil
|
24
|
+
uri.to_s
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
class BMC::Email
|
2
|
+
include ActiveModel::Model
|
3
|
+
include BMC::ModelToS
|
4
|
+
include BMC::ModelI18n
|
5
|
+
|
6
|
+
validates :to, presence: true
|
7
|
+
validates :subject, presence: true
|
8
|
+
validates :body, presence: true
|
9
|
+
|
10
|
+
validate :validate_addr_formats
|
11
|
+
|
12
|
+
attr_accessor(
|
13
|
+
:current_user,
|
14
|
+
:from,
|
15
|
+
:reply_to,
|
16
|
+
:to,
|
17
|
+
:cc,
|
18
|
+
:subject,
|
19
|
+
:body,
|
20
|
+
:attachments,
|
21
|
+
)
|
22
|
+
|
23
|
+
def initialize(*)
|
24
|
+
super
|
25
|
+
assign_default_values
|
26
|
+
end
|
27
|
+
|
28
|
+
def attachment_names
|
29
|
+
attachments.keys.join(", ")
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_and_deliver
|
33
|
+
ok = valid?
|
34
|
+
deliver if ok
|
35
|
+
ok
|
36
|
+
end
|
37
|
+
|
38
|
+
def data
|
39
|
+
{
|
40
|
+
:from => from,
|
41
|
+
:reply_to => reply_to,
|
42
|
+
:to => to,
|
43
|
+
:cc => cc,
|
44
|
+
:subject => subject,
|
45
|
+
:body => body,
|
46
|
+
:attachments => attachments,
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def deliver
|
51
|
+
deliver_now
|
52
|
+
end
|
53
|
+
|
54
|
+
def deliver_now
|
55
|
+
BMC::GenericMailer.generic_email(data).deliver_now
|
56
|
+
end
|
57
|
+
|
58
|
+
def deliver_later
|
59
|
+
BMC::GenericMailer.generic_email(data).deliver_later
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def assign_default_values
|
65
|
+
self.from ||= default_from
|
66
|
+
self.reply_to ||= default_reply_to
|
67
|
+
self.to ||= default_to
|
68
|
+
self.cc ||= default_cc
|
69
|
+
self.subject ||= default_subject
|
70
|
+
self.body ||= default_body
|
71
|
+
self.attachments ||= default_attachments
|
72
|
+
end
|
73
|
+
|
74
|
+
def default_from
|
75
|
+
end
|
76
|
+
|
77
|
+
def default_reply_to
|
78
|
+
"#{current_user} <#{current_user.email}>" if current_user
|
79
|
+
end
|
80
|
+
|
81
|
+
def default_to
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_cc
|
85
|
+
end
|
86
|
+
|
87
|
+
def default_subject
|
88
|
+
end
|
89
|
+
|
90
|
+
def default_body
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_attachments
|
94
|
+
{}
|
95
|
+
end
|
96
|
+
|
97
|
+
def validate_addr_formats
|
98
|
+
validate_addr_formats_for(:from)
|
99
|
+
validate_addr_formats_for(:reply_to)
|
100
|
+
validate_addr_formats_for(:to)
|
101
|
+
validate_addr_formats_for(:cc)
|
102
|
+
end
|
103
|
+
|
104
|
+
def validate_addr_formats_for(attr)
|
105
|
+
require "mail"
|
106
|
+
|
107
|
+
string = public_send(attr).to_s
|
108
|
+
return if string.blank?
|
109
|
+
addrs = Mail.new(to: string).to_addrs
|
110
|
+
return true if addrs.any? && addrs.all? { |addr| URI::MailTo::EMAIL_REGEXP.match?(addr) }
|
111
|
+
errors.add(attr, :invalid)
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class BMC::Filter::ByDateOrDatetimePeriod < BMC::Filter::ByKeyValue
|
2
|
+
def initialize(*)
|
3
|
+
if instance_of?(BMC::Filter::ByDateOrDatetimePeriod)
|
4
|
+
raise "please use FilterStrategyByDatePeriod or FilterStrategyByDatetimePeriod"
|
5
|
+
end
|
6
|
+
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply(query, value) # rubocop:disable Metrics/MethodLength
|
11
|
+
value = value.to_s
|
12
|
+
|
13
|
+
if value == "today"
|
14
|
+
a = now
|
15
|
+
b = now
|
16
|
+
elsif value == "yesterday"
|
17
|
+
a = (now - 1.day)
|
18
|
+
b = (now - 1.day)
|
19
|
+
elsif value == "this_week"
|
20
|
+
a = now.beginning_of_week
|
21
|
+
b = now.end_of_week
|
22
|
+
elsif value == "this_month"
|
23
|
+
a = now.beginning_of_month
|
24
|
+
b = now.end_of_month
|
25
|
+
elsif value == "this_year"
|
26
|
+
a = now.beginning_of_year
|
27
|
+
b = now.end_of_year
|
28
|
+
elsif value == "last_week"
|
29
|
+
a = (now - 1.week).beginning_of_week
|
30
|
+
b = (now - 1.week).end_of_week
|
31
|
+
elsif value == "last_month"
|
32
|
+
a = (now - 1.month).beginning_of_month
|
33
|
+
b = (now - 1.month).end_of_month
|
34
|
+
elsif value == "last_year"
|
35
|
+
a = (now - 1.year).beginning_of_year
|
36
|
+
b = (now - 1.year).end_of_year
|
37
|
+
elsif (m = value.match(/last\.([0-9]+)\.(days?|weeks?|months?|years?)/))
|
38
|
+
a = now - m[1].to_i.public_send(m[2])
|
39
|
+
b = now
|
40
|
+
else
|
41
|
+
return query
|
42
|
+
end
|
43
|
+
|
44
|
+
if now.is_a?(Time)
|
45
|
+
a = a.beginning_of_day if a
|
46
|
+
b = b.end_of_day if b
|
47
|
+
end
|
48
|
+
|
49
|
+
column = column_for(query)
|
50
|
+
|
51
|
+
query = query.where("#{column} >= ?", a) if a
|
52
|
+
query = query.where("#{column} <= ?", b) if b
|
53
|
+
|
54
|
+
query
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class BMC::Filter::ByKeyValue
|
2
|
+
attr_reader :key
|
3
|
+
|
4
|
+
def initialize(key = nil)
|
5
|
+
super()
|
6
|
+
@key = key
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(query, value)
|
10
|
+
value = true if value == "true"
|
11
|
+
value = false if value == "false"
|
12
|
+
|
13
|
+
column = column_for(query)
|
14
|
+
|
15
|
+
if value.to_s.in?(%w(nil null))
|
16
|
+
query.where("#{column} IS NULL")
|
17
|
+
elsif value.to_s.in?(%w(not_nil not_null))
|
18
|
+
query.where("#{column} IS NOT NULL")
|
19
|
+
else
|
20
|
+
query.where("#{column} = ?", value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def column_for(query)
|
25
|
+
key.is_a?(Symbol) ? "#{query.model.table_name}.#{key}" : key.to_s
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class BMC::Filter::ByKeyValues < BMC::Filter::ByKeyValue
|
2
|
+
def apply(query, value)
|
3
|
+
value = value.split if value.is_a?(String)
|
4
|
+
value = value.select(&:present?)
|
5
|
+
column = column_for(query)
|
6
|
+
|
7
|
+
if value.any?
|
8
|
+
query.where("#{column} IN (?)", value)
|
9
|
+
else
|
10
|
+
query
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class BMC::Filter
|
2
|
+
include ActiveModel::Model
|
3
|
+
|
4
|
+
STRATEGIES = {}
|
5
|
+
|
6
|
+
attr_reader :jar
|
7
|
+
|
8
|
+
def initialize(jar)
|
9
|
+
@jar = jar
|
10
|
+
end
|
11
|
+
|
12
|
+
def strategies
|
13
|
+
self.class::STRATEGIES.with_indifferent_access
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply(query)
|
17
|
+
strategies.each do |key, strategy|
|
18
|
+
value = get(key)
|
19
|
+
|
20
|
+
next if value.blank?
|
21
|
+
|
22
|
+
query = strategy.apply(query, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
return query
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(method, *args)
|
29
|
+
if method.to_s.end_with?("=")
|
30
|
+
key = method.to_s[0..-2]
|
31
|
+
value = args.first
|
32
|
+
action = :write
|
33
|
+
else
|
34
|
+
key = method.to_s
|
35
|
+
action = :read
|
36
|
+
end
|
37
|
+
|
38
|
+
if strategies.key?(key) && action == :read
|
39
|
+
get(key)
|
40
|
+
elsif strategies.key?(key) && action == :write
|
41
|
+
set(key, value)
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def respond_to_missing?(method, *)
|
48
|
+
super || strategies.key?(method.to_s) || strategies.key?(method.to_s.chomp("="))
|
49
|
+
end
|
50
|
+
|
51
|
+
def read
|
52
|
+
JSON.parse jar["filters"].to_s
|
53
|
+
rescue JSON::ParserError
|
54
|
+
{}
|
55
|
+
end
|
56
|
+
|
57
|
+
def write(filters)
|
58
|
+
jar["filters"] = filters.to_json
|
59
|
+
end
|
60
|
+
|
61
|
+
def merge(new_filters)
|
62
|
+
write read.merge(new_filters)
|
63
|
+
end
|
64
|
+
|
65
|
+
def actives_count
|
66
|
+
read.count { |k, v| strategies.key?(k.to_s) && v.present? }
|
67
|
+
end
|
68
|
+
|
69
|
+
def any?
|
70
|
+
actives_count.positive?
|
71
|
+
end
|
72
|
+
|
73
|
+
def empty?
|
74
|
+
!any?
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def get(key)
|
80
|
+
read[key.to_s]
|
81
|
+
end
|
82
|
+
|
83
|
+
def set(key, value)
|
84
|
+
merge(key.to_s => value)
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class BMC::MiniFormObject < SimpleDelegator
|
2
|
+
include ActiveModel::Validations
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def valid?
|
6
|
+
__getobj__.valid?
|
7
|
+
run_validations!
|
8
|
+
end
|
9
|
+
|
10
|
+
def invalid?
|
11
|
+
!valid?
|
12
|
+
end
|
13
|
+
|
14
|
+
alias validate valid?
|
15
|
+
|
16
|
+
def validate!
|
17
|
+
valid? || raise_validation_error
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegators :__getobj__, :errors
|
21
|
+
|
22
|
+
def save
|
23
|
+
valid? && __getobj__.save
|
24
|
+
end
|
25
|
+
|
26
|
+
def save!
|
27
|
+
validate! && __getobj__.save!
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BMC::AllHelpers
|
2
|
+
include BMC::BootstrapHelper
|
3
|
+
include BMC::ButtonHelper
|
4
|
+
include BMC::FiltersHelper
|
5
|
+
include BMC::FontAwesomeHelper
|
6
|
+
include BMC::FormHelper
|
7
|
+
include BMC::I18nHelper
|
8
|
+
include BMC::LinkHelper
|
9
|
+
include BMC::PaginationHelper
|
10
|
+
include BMC::RoutesHelper
|
11
|
+
include BMC::SortingHelper
|
12
|
+
include BMC::TextHelper
|
13
|
+
|
14
|
+
extend self
|
15
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module BMC::BootstrapHelper
|
2
|
+
class << self
|
3
|
+
attr_writer :card_classes
|
4
|
+
|
5
|
+
def card_classes
|
6
|
+
@card_classes ||= {
|
7
|
+
:card => "card",
|
8
|
+
:header => "card-header",
|
9
|
+
:body => "card-body",
|
10
|
+
:footer => "card-footer",
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def bs_progress_bar(percentage)
|
16
|
+
percentage = percentage.round if percentage.respond_to?(:round)
|
17
|
+
|
18
|
+
tag.div(class: "progress") do
|
19
|
+
tag.div(class: "progress-bar", style: "width:#{percentage}%") do
|
20
|
+
"#{percentage}%"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def bs_card( # rubocop:disable Metrics/ParameterLists
|
26
|
+
header: nil,
|
27
|
+
body: true,
|
28
|
+
footer: nil,
|
29
|
+
card_tag: :div,
|
30
|
+
header_tag: :div,
|
31
|
+
body_tag: :div,
|
32
|
+
footer_tag: :div,
|
33
|
+
card_class: nil,
|
34
|
+
header_class: nil,
|
35
|
+
body_class: nil,
|
36
|
+
footer_class: nil,
|
37
|
+
&block
|
38
|
+
)
|
39
|
+
global_classes = BMC::BootstrapHelper.card_classes
|
40
|
+
card_classes = ([global_classes[:card]] + card_class.to_s.split).compact.sort
|
41
|
+
header_classes = ([global_classes[:header]] + header_class.to_s.split).compact.sort
|
42
|
+
body_classes = ([global_classes[:body]] + body_class.to_s.split).compact.sort
|
43
|
+
footer_classes = ([global_classes[:footer]] + footer_class.to_s.split).compact.sort
|
44
|
+
|
45
|
+
if header
|
46
|
+
header_html = content_tag(header_tag, class: header_classes) { header }
|
47
|
+
end
|
48
|
+
|
49
|
+
if body
|
50
|
+
body_html = content_tag(body_tag, class: body_classes) { capture(&block) }
|
51
|
+
else
|
52
|
+
body_html = capture(&block)
|
53
|
+
end
|
54
|
+
|
55
|
+
if footer
|
56
|
+
footer_html = content_tag(footer_tag, class: footer_classes) { footer }
|
57
|
+
end
|
58
|
+
|
59
|
+
content_tag(card_tag, class: card_classes) do
|
60
|
+
[header_html, body_html, footer_html].compact.sum
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|