barkest_core 1.5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +254 -0
- data/MIT-LICENSE +20 -0
- data/README.md +364 -0
- data/Rakefile +37 -0
- data/app/assets/fonts/barkest_core/ArchivoNarrow-Bold.ttf +0 -0
- data/app/assets/fonts/barkest_core/ArchivoNarrow-BoldItalic.ttf +0 -0
- data/app/assets/fonts/barkest_core/ArchivoNarrow-Italic.ttf +0 -0
- data/app/assets/fonts/barkest_core/ArchivoNarrow-Regular.ttf +0 -0
- data/app/assets/images/barkest_core/.keep +0 -0
- data/app/assets/images/barkest_core/barcode-B.svg +181 -0
- data/app/assets/javascripts/barkest_core/.keep +0 -0
- data/app/assets/javascripts/barkest_core/application.js +22 -0
- data/app/assets/javascripts/barkest_core/bootstrap-datepicker.js +1800 -0
- data/app/assets/javascripts/barkest_core/field_init.js +7 -0
- data/app/assets/javascripts/barkest_core/jquery.doubleScroll.js +112 -0
- data/app/assets/javascripts/barkest_core/masked_edit.js +25 -0
- data/app/assets/javascripts/barkest_core/system_status.js.erb +201 -0
- data/app/assets/stylesheets/barkest_core/.keep +0 -0
- data/app/assets/stylesheets/barkest_core/application.css +17 -0
- data/app/assets/stylesheets/barkest_core/custom.css.scss +264 -0
- data/app/assets/stylesheets/barkest_core/datepicker3.css +790 -0
- data/app/controllers/.keep +0 -0
- data/app/controllers/access_groups_controller.rb +74 -0
- data/app/controllers/account_activations_controller.rb +29 -0
- data/app/controllers/application_controller.rb +5 -0
- data/app/controllers/barkest_core/application_controller_base.rb +113 -0
- data/app/controllers/barkest_core/engine_controller_base.rb +15 -0
- data/app/controllers/barkest_core/testsub_controller.rb +21 -0
- data/app/controllers/contact_controller.rb +32 -0
- data/app/controllers/log_view_controller.rb +31 -0
- data/app/controllers/password_resets_controller.rb +126 -0
- data/app/controllers/sessions_controller.rb +64 -0
- data/app/controllers/status_controller.rb +150 -0
- data/app/controllers/system_config_controller.rb +238 -0
- data/app/controllers/system_update_controller.rb +164 -0
- data/app/controllers/test_access_controller.rb +44 -0
- data/app/controllers/test_report_controller.rb +75 -0
- data/app/controllers/users_controller.rb +218 -0
- data/app/helpers/.keep +0 -0
- data/app/helpers/barkest_core/application_helper.rb +134 -0
- data/app/helpers/barkest_core/form_helper.rb +469 -0
- data/app/helpers/barkest_core/html_helper.rb +70 -0
- data/app/helpers/barkest_core/misc_helper.rb +68 -0
- data/app/helpers/barkest_core/pdf_helper.rb +180 -0
- data/app/helpers/barkest_core/recaptcha_helper.rb +115 -0
- data/app/helpers/barkest_core/sessions_helper.rb +94 -0
- data/app/helpers/barkest_core/status_helper.rb +118 -0
- data/app/helpers/barkest_core/users_helper.rb +32 -0
- data/app/mailers/.keep +0 -0
- data/app/mailers/application_mailer.rb +5 -0
- data/app/mailers/barkest_core/application_mailer_base.rb +30 -0
- data/app/mailers/barkest_core/contact_form.rb +20 -0
- data/app/mailers/barkest_core/user_mailer.rb +44 -0
- data/app/models/.keep +0 -0
- data/app/models/access_group.rb +121 -0
- data/app/models/access_group_group_member.rb +13 -0
- data/app/models/access_group_user_member.rb +11 -0
- data/app/models/barkest_core/auth_config.rb +95 -0
- data/app/models/barkest_core/authorize_failure.rb +7 -0
- data/app/models/barkest_core/contact_message.rb +37 -0
- data/app/models/barkest_core/database_config.rb +223 -0
- data/app/models/barkest_core/db_table.rb +21 -0
- data/app/models/barkest_core/email_config.rb +132 -0
- data/app/models/barkest_core/global_status.rb +267 -0
- data/app/models/barkest_core/log_entry.rb +101 -0
- data/app/models/barkest_core/log_view_options.rb +51 -0
- data/app/models/barkest_core/ms_sql_db_definition.rb +441 -0
- data/app/models/barkest_core/ms_sql_definition.rb +221 -0
- data/app/models/barkest_core/ms_sql_function.rb +423 -0
- data/app/models/barkest_core/not_logged_in.rb +7 -0
- data/app/models/barkest_core/pdf_table_builder.rb +407 -0
- data/app/models/barkest_core/self_update_config.rb +37 -0
- data/app/models/barkest_core/user_alert.rb +29 -0
- data/app/models/barkest_core/user_alert_generators.rb +58 -0
- data/app/models/barkest_core/user_manager.rb +404 -0
- data/app/models/barkest_core/work_path.rb +74 -0
- data/app/models/disable_user.rb +18 -0
- data/app/models/ldap_access_group.rb +15 -0
- data/app/models/system_config.rb +99 -0
- data/app/models/user.rb +405 -0
- data/app/models/user_login_history.rb +11 -0
- data/app/views/.keep +0 -0
- data/app/views/access_groups/_form.html.erb +19 -0
- data/app/views/access_groups/edit.html.erb +2 -0
- data/app/views/access_groups/index.html.erb +32 -0
- data/app/views/access_groups/new.html.erb +2 -0
- data/app/views/access_groups/show.html.erb +4 -0
- data/app/views/barkest_core/contact_form/contact.html.erb +16 -0
- data/app/views/barkest_core/contact_form/contact.text.erb +13 -0
- data/app/views/barkest_core/testsub/_links.html.erb +5 -0
- data/app/views/barkest_core/testsub/page1.html.erb +3 -0
- data/app/views/barkest_core/testsub/page2.html.erb +2 -0
- data/app/views/barkest_core/testsub/page3.html.erb +2 -0
- data/app/views/barkest_core/user_mailer/account_activation.html.erb +7 -0
- data/app/views/barkest_core/user_mailer/account_activation.text.erb +6 -0
- data/app/views/barkest_core/user_mailer/invalid_password_reset.html.erb +3 -0
- data/app/views/barkest_core/user_mailer/invalid_password_reset.text.erb +5 -0
- data/app/views/barkest_core/user_mailer/password_reset.html.erb +8 -0
- data/app/views/barkest_core/user_mailer/password_reset.text.erb +7 -0
- data/app/views/contact/index.html.erb +24 -0
- data/app/views/layouts/_footer_copyright.html.erb +1 -0
- data/app/views/layouts/_menu_admin.html.erb +5 -0
- data/app/views/layouts/_menu_anon.html.erb +0 -0
- data/app/views/layouts/_menu_auth.html.erb +3 -0
- data/app/views/layouts/_menu_footer.html.erb +1 -0
- data/app/views/layouts/_nav_logo.html.erb +1 -0
- data/app/views/layouts/application.html.erb +2 -0
- data/app/views/layouts/barkest_core/_application.html.erb +24 -0
- data/app/views/layouts/barkest_core/_footer.html.erb +18 -0
- data/app/views/layouts/barkest_core/_header.html.erb +38 -0
- data/app/views/layouts/barkest_core/_html_mailer.html.erb +11 -0
- data/app/views/layouts/barkest_core/_menu_account.html.erb +14 -0
- data/app/views/layouts/barkest_core/_menu_sample.html.erb +1 -0
- data/app/views/layouts/barkest_core/_messages.html.erb +4 -0
- data/app/views/layouts/barkest_core/_shim.html.erb +4 -0
- data/app/views/layouts/barkest_core/_subheader.html.erb +1 -0
- data/app/views/layouts/barkest_core/_text_mailer.text.erb +4 -0
- data/app/views/layouts/mailer.html.erb +1 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/log_view/index.html.erb +100 -0
- data/app/views/password_resets/edit.html.erb +20 -0
- data/app/views/password_resets/new.html.erb +14 -0
- data/app/views/sessions/new.html.erb +27 -0
- data/app/views/shared/_error_messages.html.erb +29 -0
- data/app/views/shared/_generic_user_alert.html.erb +4 -0
- data/app/views/status/current.html.erb +34 -0
- data/app/views/status/test.html.erb +50 -0
- data/app/views/system_config/index.html.erb +25 -0
- data/app/views/system_config/show_auth.html.erb +28 -0
- data/app/views/system_config/show_database.html.erb +36 -0
- data/app/views/system_config/show_email.html.erb +21 -0
- data/app/views/system_config/show_self_update.html.erb +13 -0
- data/app/views/system_update/index.html.erb +31 -0
- data/app/views/system_update/new.html.erb +2 -0
- data/app/views/test_access/allow_anon.html.erb +2 -0
- data/app/views/test_access/require_admin.html.erb +2 -0
- data/app/views/test_access/require_group_x.html.erb +2 -0
- data/app/views/test_access/require_user.html.erb +2 -0
- data/app/views/test_report/index.csv.csvrb +23 -0
- data/app/views/test_report/index.html.erb +6 -0
- data/app/views/test_report/index.pdf.prawn +50 -0
- data/app/views/test_report/index.xlsx.axlsx +28 -0
- data/app/views/users/_user.html.erb +57 -0
- data/app/views/users/_user_details.html.erb +15 -0
- data/app/views/users/_user_details_for_list.html.erb +1 -0
- data/app/views/users/_user_form.html.erb +13 -0
- data/app/views/users/disable_confirm.html.erb +19 -0
- data/app/views/users/edit.html.erb +15 -0
- data/app/views/users/index.html.erb +9 -0
- data/app/views/users/new.html.erb +10 -0
- data/app/views/users/show.html.erb +46 -0
- data/bin/rails +12 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20160617172539_create_access_groups.rb +10 -0
- data/db/migrate/20160617172725_create_users.rb +26 -0
- data/db/migrate/20160617172833_create_user_login_histories.rb +12 -0
- data/db/migrate/20160622151720_create_access_group_user_members.rb +9 -0
- data/db/migrate/20160622151925_create_access_group_group_members.rb +9 -0
- data/db/migrate/20160701005706_create_ldap_access_groups.rb +11 -0
- data/db/migrate/20161108155029_create_system_configs.rb +11 -0
- data/db/seeds/barkest_core_01_create_users.rb +42 -0
- data/db/seeds.rb +53 -0
- data/lib/barkest_core/concerns/association_with_defaults.rb +55 -0
- data/lib/barkest_core/concerns/boolean_parser.rb +88 -0
- data/lib/barkest_core/concerns/date_parser.rb +181 -0
- data/lib/barkest_core/concerns/email_tester.rb +55 -0
- data/lib/barkest_core/concerns/encrypted_fields.rb +156 -0
- data/lib/barkest_core/concerns/named_model.rb +73 -0
- data/lib/barkest_core/concerns/number_parser.rb +145 -0
- data/lib/barkest_core/concerns/utc_conversion.rb +60 -0
- data/lib/barkest_core/engine.rb +105 -0
- data/lib/barkest_core/extensions/active_record_extensions.rb +120 -0
- data/lib/barkest_core/extensions/application_configuration_extensions.rb +38 -0
- data/lib/barkest_core/extensions/application_extensions.rb +50 -0
- data/lib/barkest_core/extensions/axlsx_extenstions.rb +157 -0
- data/lib/barkest_core/extensions/fixture_set_extensions.rb +107 -0
- data/lib/barkest_core/extensions/generator_extensions.rb +271 -0
- data/lib/barkest_core/extensions/main_app_extensions.rb +35 -0
- data/lib/barkest_core/extensions/prawn_document_extensions.rb +367 -0
- data/lib/barkest_core/extensions/prawn_table_extensions.rb +131 -0
- data/lib/barkest_core/extensions/router_extensions.rb +106 -0
- data/lib/barkest_core/extensions/simple_formatter_extensions.rb +66 -0
- data/lib/barkest_core/extensions/test_case_extensions.rb +348 -0
- data/lib/barkest_core/extensions/time_extensions.rb +164 -0
- data/lib/barkest_core/handlers/csv_handler.rb +30 -0
- data/lib/barkest_core/version.rb +3 -0
- data/lib/barkest_core.rb +324 -0
- data/lib/generators/barkest/install_generator.rb +102 -0
- data/lib/generators/barkest_core/actions/01_patch_application_controller.rb +55 -0
- data/lib/generators/barkest_core/actions/02_patch_application_mailer.rb +56 -0
- data/lib/generators/barkest_core/actions/03_patch_assets.rb +62 -0
- data/lib/generators/barkest_core/actions/04_patch_layouts.rb +36 -0
- data/lib/generators/barkest_core/actions/05_patch_routes.rb +93 -0
- data/lib/generators/barkest_core/actions/06_patch_seeds.rb +60 -0
- data/lib/generators/barkest_core/actions/07_copy_migrations.rb +51 -0
- data/lib/generators/barkest_core/actions/08_configure_database.rb +52 -0
- data/lib/generators/barkest_core/actions/09_configure_secrets.rb +29 -0
- data/lib/generators/barkest_core/actions/99_patch_gitignore.rb +57 -0
- data/lib/generators/barkest_core/install_generator.rb +17 -0
- data/test/barkest_core_test.rb +83 -0
- data/test/controllers/access_groups_controller_test.rb +53 -0
- data/test/controllers/contact_controller_test.rb +10 -0
- data/test/controllers/sessions_controller_test.rb +10 -0
- data/test/controllers/users_controller_test.rb +10 -0
- data/test/dummy/.gitignore +10 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +14 -0
- data/test/dummy/app/assets/stylesheets/application.css +16 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.keep +0 -0
- data/test/dummy/app/mailers/application_mailer.rb +3 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +1 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +1 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/app/views/system_config/show_fake.html.erb +3 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +27 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +47 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/db_updater_ext.rb +33 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/sys_config_ext.rb +12 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +60 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/schema.rb +95 -0
- data/test/dummy/db/seeds/barkest_core_01_create_users.rb +42 -0
- data/test/dummy/db/seeds.rb +51 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/sql/my_test_view.sql +3 -0
- data/test/fixtures/access_groups.yml +21 -0
- data/test/fixtures/users.yml +71 -0
- data/test/helpers/barkest_core/sessions_helper_test.rb +22 -0
- data/test/integration/access_group_mgmt_test.rb +33 -0
- data/test/integration/access_test.rb +24 -0
- data/test/integration/account_activations_access_test.rb +12 -0
- data/test/integration/contact_test.rb +98 -0
- data/test/integration/extra_partial_test.rb +41 -0
- data/test/integration/log_view_access_test.rb +12 -0
- data/test/integration/password_resets_test.rb +101 -0
- data/test/integration/reports_test.rb +53 -0
- data/test/integration/status_access_test.rb +27 -0
- data/test/integration/system_config_access_test.rb +24 -0
- data/test/integration/system_update_access_test.rb +19 -0
- data/test/integration/users_access_test.rb +34 -0
- data/test/integration/users_edit_test.rb +178 -0
- data/test/integration/users_index_test.rb +62 -0
- data/test/integration/users_login_test.rb +67 -0
- data/test/integration/users_signup_test.rb +54 -0
- data/test/mailers/.keep +0 -0
- data/test/mailers/barkest_core/contact_form_test.rb +28 -0
- data/test/mailers/barkest_core/user_mailer_test.rb +43 -0
- data/test/mailers/previews/barkest_core/contact_form_preview.rb +17 -0
- data/test/mailers/previews/barkest_core/user_mailer_preview.rb +26 -0
- data/test/models/access_group_group_member_test.rb +28 -0
- data/test/models/access_group_test.rb +114 -0
- data/test/models/access_group_user_member_test.rb +28 -0
- data/test/models/barkest_core/auth_config_test.rb +57 -0
- data/test/models/barkest_core/bool_parser_test.rb +28 -0
- data/test/models/barkest_core/contact_message_test.rb +61 -0
- data/test/models/barkest_core/database_config_test.rb +33 -0
- data/test/models/barkest_core/date_parser_test.rb +110 -0
- data/test/models/barkest_core/email_config_test.rb +57 -0
- data/test/models/barkest_core/global_status_test.rb +50 -0
- data/test/models/barkest_core/ms_sql_db_updater_test.rb +115 -0
- data/test/models/barkest_core/ms_sql_definition_test.rb +102 -0
- data/test/models/barkest_core/ms_sql_function_test.rb +131 -0
- data/test/models/barkest_core/number_parser_test.rb +29 -0
- data/test/models/barkest_core/self_update_config_test.rb +29 -0
- data/test/models/barkest_core/user_alert_test.rb +19 -0
- data/test/models/barkest_core/user_manager_test.rb +34 -0
- data/test/models/barkest_core/work_path_test.rb +26 -0
- data/test/models/disable_user_test.rb +27 -0
- data/test/models/generic_time_test.rb +66 -0
- data/test/models/ldap_access_group_test.rb +31 -0
- data/test/models/pdf_table_builder_test.rb +6 -0
- data/test/models/system_config_test.rb +78 -0
- data/test/models/user_login_history_test.rb +37 -0
- data/test/models/user_test.rb +130 -0
- data/test/test_helper.rb +63 -0
- metadata +798 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module BarkestCore
|
4
|
+
|
5
|
+
##
|
6
|
+
# Reads a log line from a JSON log file.
|
7
|
+
class LogEntry
|
8
|
+
|
9
|
+
include ActiveModel::Model
|
10
|
+
include ActiveModel::Validations
|
11
|
+
include Comparable
|
12
|
+
|
13
|
+
attr_reader :level, :time, :message, :app_name, :app_version, :process_id
|
14
|
+
|
15
|
+
validates :level, presence: true
|
16
|
+
validates :time, presence: true
|
17
|
+
validates :message, presence: true
|
18
|
+
|
19
|
+
SEVERITY_LIST = %w(DEBUG INFO WARN ERROR FATAL)
|
20
|
+
|
21
|
+
##
|
22
|
+
# Creates a LogEntry.
|
23
|
+
#
|
24
|
+
# The args can either be a JSON string or a Hash.
|
25
|
+
def initialize(*args)
|
26
|
+
args.each do |arg|
|
27
|
+
if arg.is_a?(String)
|
28
|
+
arg = JSON.parse(arg).symbolize_keys rescue nil
|
29
|
+
end
|
30
|
+
if arg.is_a?(Hash)
|
31
|
+
arg.each do |k,v|
|
32
|
+
k = k.to_sym
|
33
|
+
v = case k
|
34
|
+
when :level
|
35
|
+
v.to_sym
|
36
|
+
when :time
|
37
|
+
Time.parse(v)
|
38
|
+
when :process_id
|
39
|
+
v.to_i
|
40
|
+
else
|
41
|
+
v
|
42
|
+
end
|
43
|
+
instance_variable_set(:"@#{k}", v)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Gets the index in the log file.
|
51
|
+
def index
|
52
|
+
@index ||= 0
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Gets the level as a numeric ID.
|
57
|
+
def level_id
|
58
|
+
@level_id ||= SEVERITY_LIST.index(level.to_s.upcase) || 5
|
59
|
+
end
|
60
|
+
|
61
|
+
# :nodoc:
|
62
|
+
def inspect
|
63
|
+
"#<#{self.class.name} #{level} #{time} [#{app_name} #{app_version} (#{process_id})] #{message.length > 32 ? (message[0...32] + '...') : message}>"
|
64
|
+
end
|
65
|
+
|
66
|
+
# :nodoc:
|
67
|
+
def to_s
|
68
|
+
"#{level} #{time} [#{app_name} #{app_version} (#{process_id})] #{message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# :nodoc:
|
72
|
+
def <=>(other)
|
73
|
+
return 1 unless other.is_a?(LogEntry)
|
74
|
+
if index == other.index
|
75
|
+
time <=> other.time
|
76
|
+
else
|
77
|
+
index <=> other.index
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Reads a log file consisting of JSON records.
|
83
|
+
#
|
84
|
+
# If no log file is specified, the default log file is assumed.
|
85
|
+
def self.read_log(log_file = nil)
|
86
|
+
log_file ||= Rails.root.join('log', "#{Rails.env}.log")
|
87
|
+
|
88
|
+
ret = []
|
89
|
+
|
90
|
+
if File.exist?(log_file)
|
91
|
+
File.foreach(log_file, "\n").with_index do |line, index|
|
92
|
+
line = JSON.parse(line) rescue nil
|
93
|
+
ret << LogEntry.new(line.symbolize_keys.merge(index: index)) if line.is_a?(Hash)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
ret
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module BarkestCore
|
2
|
+
class LogViewOptions
|
3
|
+
include ActiveModel::Model
|
4
|
+
include BarkestCore::DateParser
|
5
|
+
|
6
|
+
attr_accessor :search, :max_records
|
7
|
+
attr_reader :start_time, :end_time
|
8
|
+
|
9
|
+
|
10
|
+
def min_severity=(value)
|
11
|
+
@min_severity = BarkestCore::LogEntry::SEVERITY_LIST.index(value.to_s.upcase)
|
12
|
+
end
|
13
|
+
|
14
|
+
def min_severity
|
15
|
+
return nil unless instance_variable_defined?(:@min_severity)
|
16
|
+
return nil unless @min_severity
|
17
|
+
BarkestCore::LogEntry::SEVERITY_LIST[@min_severity]
|
18
|
+
end
|
19
|
+
|
20
|
+
def min_severity_id
|
21
|
+
return nil unless instance_variable_defined?(:@min_severity)
|
22
|
+
@min_severity
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_time=(value)
|
26
|
+
@start_time = parse_for_date_column(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def end_time=(value)
|
30
|
+
@end_time = parse_for_date_column(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def search_regex
|
34
|
+
@search_regex ||=
|
35
|
+
if search.blank?
|
36
|
+
nil
|
37
|
+
else
|
38
|
+
/#{search.gsub('[]', '\[\]')}/i rescue nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def keep_log_entry?(log_entry)
|
43
|
+
return false if min_severity_id && log_entry.level_id < min_severity_id
|
44
|
+
return false if start_time && log_entry.time < start_time
|
45
|
+
return false if end_time && log_entry.time > (end_time + 1.day) # include events from the end date.
|
46
|
+
return false unless search_regex.nil? || search_regex.match(log_entry.message)
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,441 @@
|
|
1
|
+
module BarkestCore
|
2
|
+
##
|
3
|
+
# This class can be used to conditionally update a target SQL database with custom code.
|
4
|
+
#
|
5
|
+
# The updater will hunt through the SQL files found in the +sql_sources+ passed in.
|
6
|
+
# For each source, the updater calculates the new version and compares it against the
|
7
|
+
# existing version. If the new version is actually newer, the updater will update the
|
8
|
+
# object in the database.
|
9
|
+
class MsSqlDbDefinition
|
10
|
+
|
11
|
+
##
|
12
|
+
# The base error for errors raised by the updater class.
|
13
|
+
UpdateError = Class.new(StandardError)
|
14
|
+
|
15
|
+
##
|
16
|
+
# The error raised when the provided connection does not provide a user with full control over the database.
|
17
|
+
NeedFullAccess = Class.new(UpdateError)
|
18
|
+
|
19
|
+
##
|
20
|
+
# The error raised when an object type doesn't match the previous type for the object with the specified name.
|
21
|
+
ObjectTypeMismatch = Class.new(UpdateError)
|
22
|
+
|
23
|
+
##
|
24
|
+
# The name of the table holding the object versions.
|
25
|
+
VERSION_TABLE_NAME = 'zz_barkest__versions'
|
26
|
+
|
27
|
+
|
28
|
+
attr_reader :table_prefix
|
29
|
+
|
30
|
+
class Conn < ActiveRecord::Base
|
31
|
+
self.abstract_class = true
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Defines a new updater.
|
36
|
+
#
|
37
|
+
# Options can include +source_paths+, +before_update+, and +after_update+.
|
38
|
+
#
|
39
|
+
# The +before_update+ and +after_update+ options define a callback to be run before or after
|
40
|
+
# the database update is performed. This can be a string referencing a method or it can be a Proc.
|
41
|
+
#
|
42
|
+
# MsSqlDbDefinition.new(
|
43
|
+
# :before_update => 'MyClass.my_method(db_conn,user)',
|
44
|
+
# :after_update => Proc.new do |db_conn, user|
|
45
|
+
# ...
|
46
|
+
# end
|
47
|
+
# )
|
48
|
+
#
|
49
|
+
# If you use the string option, note that the +db_conn+ and +user+ variables are available. In the example
|
50
|
+
# above they are being passed to the method as arguments.
|
51
|
+
def initialize(options = {})
|
52
|
+
options = {
|
53
|
+
table_name_prefix: 'zz_barkest_'
|
54
|
+
}.merge(options || {}).symbolize_keys
|
55
|
+
|
56
|
+
@table_prefix = options[:table_name_prefix].to_s
|
57
|
+
valid_regex = /^[a-z][a-z0-9_]*$/im
|
58
|
+
raise 'invalid table prefix' unless valid_regex.match(@table_prefix)
|
59
|
+
|
60
|
+
@sources = [ ]
|
61
|
+
@source_paths = [ ]
|
62
|
+
@pre_update = options.delete(:before_update) || options.delete(:pre_update)
|
63
|
+
@post_update = options.delete(:after_update) || options.delete(:post_update)
|
64
|
+
|
65
|
+
# and any other paths provided via options.
|
66
|
+
if options[:source_paths]
|
67
|
+
if options[:source_paths].is_a?(String)
|
68
|
+
add_source_path options[:source_paths]
|
69
|
+
elsif options[:source_paths].respond_to?(:each)
|
70
|
+
options[:source_paths].each do |path|
|
71
|
+
add_source_path path.to_s
|
72
|
+
end
|
73
|
+
else
|
74
|
+
add_source_path options[:source_paths].to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Gets an object's name according to this DB updater.
|
82
|
+
def object_name(unprefixed_name)
|
83
|
+
name = unprefixed_name.to_s
|
84
|
+
return name if name.index(table_prefix) == 0
|
85
|
+
"#{table_prefix}#{name}"
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Gets all of the source paths that have currently been searched.
|
90
|
+
def source_paths
|
91
|
+
@source_paths.dup.freeze
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Gets all of the sources currently loaded.
|
96
|
+
def sources
|
97
|
+
@sources.dup.map{|t| t.name_prefix = table_prefix; t}.freeze
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Adds a source using a specific timestamp.
|
102
|
+
#
|
103
|
+
# The first line of the SQL should be a comment specifying the timestamp for the source.
|
104
|
+
# -- 2016-12-19 15:45
|
105
|
+
# -- 2016-12-19
|
106
|
+
# -- 201612191545
|
107
|
+
# -- 20161219
|
108
|
+
#
|
109
|
+
# The timestamp will be converted into a 12-digit number, if time is not specified it will be right-padded
|
110
|
+
# with zeroes to get to the 12-digit number.
|
111
|
+
#
|
112
|
+
# The +sql+ should be a valid create/alter table/view/function statement.
|
113
|
+
def add_source(sql)
|
114
|
+
sql_def = BarkestCore::MsSqlDefinition.new(sql, '')
|
115
|
+
sql_def.instance_variable_set(:@source_location, "::#{sql_def.name}::")
|
116
|
+
add_sql_def sql_def
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Adds a MsSqlDefinition object to the sources for this updater.
|
122
|
+
#
|
123
|
+
# The +definition+ should be a previously created MsSqlDefinition object.
|
124
|
+
def add_source_definition(definition)
|
125
|
+
add_sql_def definition
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Adds all SQL files found in the specified directory to the sources for this updater.
|
131
|
+
#
|
132
|
+
# The +path+ should contain the SQL files. If there are subdirectories, you should
|
133
|
+
# include them individually.
|
134
|
+
#
|
135
|
+
# The source files should specify a timestamp in the first comment.
|
136
|
+
# -- 2016-12-19 15:45
|
137
|
+
# -- 2016-12-19
|
138
|
+
# -- 201612191545
|
139
|
+
# -- 20161219
|
140
|
+
#
|
141
|
+
# The timestamp will be converted into a 12-digit number, if time is not specified it will be right-padded
|
142
|
+
# with zeroes to get to the 12-digit number.
|
143
|
+
#
|
144
|
+
def add_source_path(path)
|
145
|
+
raise 'path must be a string' unless path.is_a?(String)
|
146
|
+
|
147
|
+
path = File.expand_path(path)
|
148
|
+
raise 'cannot add root path' if path == '/'
|
149
|
+
path = path[0...-1] if path[-1] == '/'
|
150
|
+
|
151
|
+
unless @source_paths.include?(path)
|
152
|
+
@source_paths << path
|
153
|
+
|
154
|
+
if Dir.exist?(path)
|
155
|
+
Dir.glob("#{path}/*.sql").each do |source|
|
156
|
+
add_sql_def BarkestCore::MsSqlDefinition.new(File.read(source), source, File.mtime(source))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Performs the database update using the specified configuration.
|
166
|
+
#
|
167
|
+
# A warning will be logged if the runtime user has full access to the database.
|
168
|
+
#
|
169
|
+
# An error will be raised if there is the runtime user does not have full access and no update_user is provided,
|
170
|
+
# or if an update_user is provided who also does not have full access to the database.
|
171
|
+
def update_db(config, options = {})
|
172
|
+
|
173
|
+
begin
|
174
|
+
options ||= {}
|
175
|
+
|
176
|
+
runtime_user = config[:username]
|
177
|
+
|
178
|
+
Conn.remove_connection
|
179
|
+
Conn.establish_connection config
|
180
|
+
|
181
|
+
if have_db_control?
|
182
|
+
warn "WARNING: Runtime user '#{runtime_user}' has full access to the database. (this is not recommended)" unless Rails.env.test?
|
183
|
+
else
|
184
|
+
raise NeedFullAccess, 'please provide update_username and update_password for a user with full access to the database' unless config[:update_username]
|
185
|
+
|
186
|
+
use_config = config.dup
|
187
|
+
use_config[:username] = config[:update_username]
|
188
|
+
use_config[:password] = config[:update_password]
|
189
|
+
|
190
|
+
Conn.remove_connection
|
191
|
+
Conn.establish_connection use_config
|
192
|
+
|
193
|
+
raise NeedFullAccess, 'provided update user does not have full access to the database' unless have_db_control?
|
194
|
+
end
|
195
|
+
|
196
|
+
unless Conn.object_exists?(VERSION_TABLE_NAME)
|
197
|
+
debug 'Creating version tracking table...'
|
198
|
+
db_connection.execute <<-EOSQL
|
199
|
+
CREATE TABLE [#{VERSION_TABLE_NAME}] (
|
200
|
+
[object_name] VARCHAR(120) NOT NULL PRIMARY KEY,
|
201
|
+
[object_type] VARCHAR(40) NOT NULL,
|
202
|
+
[object_version] VARCHAR(40) NOT NULL,
|
203
|
+
[created] DATETIME NOT NULL,
|
204
|
+
[updated] DATETIME NOT NULL,
|
205
|
+
[created_by] VARCHAR(120),
|
206
|
+
[updated_by] VARCHAR(120)
|
207
|
+
)
|
208
|
+
EOSQL
|
209
|
+
end
|
210
|
+
|
211
|
+
if (proc = (options[:before_update] || options[:pre_update] || @pre_update))
|
212
|
+
if proc.is_a?(String)
|
213
|
+
code = proc
|
214
|
+
proc = Proc.new { |db_conn, user| eval code }
|
215
|
+
end
|
216
|
+
if proc.respond_to?(:call)
|
217
|
+
debug 'Running pre-update code...'
|
218
|
+
proc.call db_connection, runtime_user
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
debug 'Processing source list...'
|
223
|
+
sources.each do |src|
|
224
|
+
src.name_prefix = table_prefix
|
225
|
+
|
226
|
+
cur_ver = get_version src.prefixed_name
|
227
|
+
|
228
|
+
if cur_ver
|
229
|
+
raise ObjectTypeMismatch, "object type mismatch for #{src.prefixed_name}" unless src.type.upcase == cur_ver['object_type'].upcase
|
230
|
+
if cur_ver['object_version'].to_i >= src.version.to_i
|
231
|
+
debug " > Preserving #{src.prefixed_name}..."
|
232
|
+
next # source
|
233
|
+
else
|
234
|
+
debug " > Updating #{src.prefixed_name}..."
|
235
|
+
if src.is_create?
|
236
|
+
db_connection.execute src.drop_sql
|
237
|
+
end
|
238
|
+
end
|
239
|
+
else
|
240
|
+
debug " > Creating #{src.prefixed_name}..."
|
241
|
+
end
|
242
|
+
|
243
|
+
db_connection.execute src.update_sql
|
244
|
+
db_connection.execute src.grant_sql(runtime_user)
|
245
|
+
set_version src.prefixed_name, src.type, src.version
|
246
|
+
|
247
|
+
src.name_prefix = ''
|
248
|
+
end
|
249
|
+
|
250
|
+
if (proc = (options[:after_update] || options[:post_update] || @post_update))
|
251
|
+
if proc.is_a?(String)
|
252
|
+
code = proc
|
253
|
+
proc = Proc.new { |db_conn, user| eval code }
|
254
|
+
end
|
255
|
+
if proc.respond_to?(:call)
|
256
|
+
debug 'Running post-update code...'
|
257
|
+
proc.call db_connection, runtime_user
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
yield db_connection, runtime_user if block_given?
|
262
|
+
|
263
|
+
ensure
|
264
|
+
Conn.remove_connection
|
265
|
+
end
|
266
|
+
|
267
|
+
true
|
268
|
+
end
|
269
|
+
|
270
|
+
##
|
271
|
+
# Registers a DB updater and tells BarkestCore that the named database exists and could use a configuration.
|
272
|
+
#
|
273
|
+
# The +options+ will be passed to the MsSqlDbDefinition constructor, except for the +extra_params+ key.
|
274
|
+
# If this key is provided, it is pulled out and used for the defaults for the database configuration.
|
275
|
+
#
|
276
|
+
# Ideally this is to provide the +extra_[1|2]_name+, +extra_[1|2]_type+, and +extra_[1|2]_value+ parameters, but
|
277
|
+
# you can also use it to provide reasonable defaults for +host+, +database+, or even credentials.
|
278
|
+
#
|
279
|
+
def self.register(name, options={})
|
280
|
+
name = symbolize_name name
|
281
|
+
|
282
|
+
raise 'already registered' if registered.include?(name)
|
283
|
+
|
284
|
+
options = (options || {}).symbolize_keys
|
285
|
+
|
286
|
+
extra_params = options.delete(:extra_params)
|
287
|
+
if extra_params.is_a?(Hash)
|
288
|
+
repeat = true
|
289
|
+
while repeat
|
290
|
+
repeat = false
|
291
|
+
extra_params.dup.each do |k,v|
|
292
|
+
if v.is_a?(Hash)
|
293
|
+
extra_params.delete(k)
|
294
|
+
v.each do |subk,subv|
|
295
|
+
extra_params[:"#{k}_#{subk}"] = subv
|
296
|
+
end
|
297
|
+
repeat = true
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
options[:table_name_prefix] ||=
|
304
|
+
if name.to_s.index('barkest') == 0
|
305
|
+
"zz_#{name}_"
|
306
|
+
else
|
307
|
+
"zz_barkest_#{name}_"
|
308
|
+
end
|
309
|
+
|
310
|
+
updater = MsSqlDbDefinition.new(options)
|
311
|
+
|
312
|
+
registered[name] = updater
|
313
|
+
|
314
|
+
# Register with DatabaseConfig to enable the config page for this DB.
|
315
|
+
DatabaseConfig.register name
|
316
|
+
|
317
|
+
cfg_def = (extra_params.is_a?(Hash) ? extra_params : {})
|
318
|
+
.merge(
|
319
|
+
{
|
320
|
+
adapter: 'sqlserver',
|
321
|
+
pool: 5,
|
322
|
+
timeout: 30000,
|
323
|
+
port: 1433,
|
324
|
+
}
|
325
|
+
)
|
326
|
+
|
327
|
+
# Register with BarkestCore so that the default configuration is somewhat appropriate.
|
328
|
+
BarkestCore.register_db_config_defaults name, cfg_def
|
329
|
+
|
330
|
+
updater
|
331
|
+
end
|
332
|
+
|
333
|
+
##
|
334
|
+
# Gets a DB updater by name.
|
335
|
+
def self.[](name)
|
336
|
+
name = symbolize_name name
|
337
|
+
registered[name]
|
338
|
+
end
|
339
|
+
|
340
|
+
##
|
341
|
+
# Gets a list of all the DB updaters currently registered.
|
342
|
+
def self.keys
|
343
|
+
registered.keys
|
344
|
+
end
|
345
|
+
|
346
|
+
##
|
347
|
+
# Iterates through the registered DB updaters.
|
348
|
+
#
|
349
|
+
# Yields the db_name and the db_updater to the block.
|
350
|
+
def self.each
|
351
|
+
registered.each do |k,v|
|
352
|
+
yield k, v if block_given?
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
private
|
357
|
+
|
358
|
+
def self.symbolize_name(name)
|
359
|
+
name.to_s.underscore.gsub('/', '_').to_sym
|
360
|
+
end
|
361
|
+
|
362
|
+
def self.registered
|
363
|
+
@registered ||= {}
|
364
|
+
end
|
365
|
+
|
366
|
+
def get_version(object_name)
|
367
|
+
object_name = object_name.to_s.gsub("'", "''")
|
368
|
+
db_connection.exec_query("SELECT [object_name], [object_type], [object_version], [created], [updated], [created_by], [updated_by] FROM [#{VERSION_TABLE_NAME}] WHERE [object_name]='#{object_name}'").first
|
369
|
+
end
|
370
|
+
|
371
|
+
def set_version(object_name, object_type, object_version)
|
372
|
+
raw_obj_name = object_name
|
373
|
+
existing = get_version(raw_obj_name)
|
374
|
+
|
375
|
+
object_name = object_name.to_s.gsub("'", "''")
|
376
|
+
object_type = object_type.to_s.gsub("'", "''")
|
377
|
+
object_version = object_version.to_s.gsub("'", "''")
|
378
|
+
time = Time.now.strftime('%Y-%m-%d %H:%M:%S').gsub("'", "''")
|
379
|
+
app = (Rails && Rails.application) ? Rails.application.class.to_s.gsub("'", "''") : '<UNKNOWN>'
|
380
|
+
|
381
|
+
if existing
|
382
|
+
raise ObjectTypeMismatch, 'object type mismatch' unless existing['object_type'] == object_type
|
383
|
+
db_connection.execute "UPDATE [#{VERSION_TABLE_NAME}] SET [object_version]='#{object_version}', [updated]='#{time}', [updated_by]='#{app}' WHERE [object_name]='#{object_name}'"
|
384
|
+
else
|
385
|
+
db_connection.execute "INSERT INTO [#{VERSION_TABLE_NAME}] ([object_name], [object_type], [object_version], [created], [updated], [created_by], [updated_by]) VALUES ('#{object_name}','#{object_type}','#{object_version}','#{time}','#{time}','#{app}','#{app}')"
|
386
|
+
end
|
387
|
+
|
388
|
+
get_version raw_obj_name
|
389
|
+
end
|
390
|
+
|
391
|
+
def db_connection
|
392
|
+
Conn.connection
|
393
|
+
end
|
394
|
+
|
395
|
+
def have_db_control?
|
396
|
+
# user must have CONTROL permission on the database itself.
|
397
|
+
# if it does, then we are good to move forward.
|
398
|
+
result = db_connection.exec_query('SELECT COUNT(*) AS "one" FROM "fn_my_permissions"(NULL, \'DATABASE\') WHERE "permission_name"=\'CONTROL\'').first
|
399
|
+
result && result['one'] == 1
|
400
|
+
end
|
401
|
+
|
402
|
+
def debug(s)
|
403
|
+
if Rails && Rails.logger && Rails.logger.respond_to?(:debug)
|
404
|
+
Rails.logger.debug(s)
|
405
|
+
else
|
406
|
+
$stdout.puts s
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def warn(s)
|
411
|
+
if Rails && Rails.logger && Rails.logger.respond_to?(:warn)
|
412
|
+
Rails.logger.warn(s)
|
413
|
+
else
|
414
|
+
$stderr.puts s
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def add_sql_def(sql_def)
|
419
|
+
existing = @sources.find{ |item| item.name == sql_def.name }
|
420
|
+
if existing
|
421
|
+
if existing == sql_def
|
422
|
+
debug "A #{existing.type.downcase} named #{existing.name} is already defined with the same source."
|
423
|
+
return nil
|
424
|
+
end
|
425
|
+
if existing.type != sql_def.type
|
426
|
+
raise ObjectTypeMismatch, "Cannot change type of object named #{existing.name} from #{existing.type} to #{sql_def.type}."
|
427
|
+
end
|
428
|
+
if existing.version.to_i > sql_def.version.to_i
|
429
|
+
warn "A #{existing.type.downcase} named #{existing.name} is already defined with newer source."
|
430
|
+
return nil
|
431
|
+
end
|
432
|
+
if sql_def.is_create?
|
433
|
+
warn "Removing old definition for #{existing.type.downcase} named #{existing.name}."
|
434
|
+
@sources.delete existing
|
435
|
+
end
|
436
|
+
end
|
437
|
+
@sources << sql_def
|
438
|
+
end
|
439
|
+
|
440
|
+
end
|
441
|
+
end
|