barkest_core 1.5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/Gemfile +22 -0
  4. data/Gemfile.lock +254 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +364 -0
  7. data/Rakefile +37 -0
  8. data/app/assets/fonts/barkest_core/ArchivoNarrow-Bold.ttf +0 -0
  9. data/app/assets/fonts/barkest_core/ArchivoNarrow-BoldItalic.ttf +0 -0
  10. data/app/assets/fonts/barkest_core/ArchivoNarrow-Italic.ttf +0 -0
  11. data/app/assets/fonts/barkest_core/ArchivoNarrow-Regular.ttf +0 -0
  12. data/app/assets/images/barkest_core/.keep +0 -0
  13. data/app/assets/images/barkest_core/barcode-B.svg +181 -0
  14. data/app/assets/javascripts/barkest_core/.keep +0 -0
  15. data/app/assets/javascripts/barkest_core/application.js +22 -0
  16. data/app/assets/javascripts/barkest_core/bootstrap-datepicker.js +1800 -0
  17. data/app/assets/javascripts/barkest_core/field_init.js +7 -0
  18. data/app/assets/javascripts/barkest_core/jquery.doubleScroll.js +112 -0
  19. data/app/assets/javascripts/barkest_core/masked_edit.js +25 -0
  20. data/app/assets/javascripts/barkest_core/system_status.js.erb +201 -0
  21. data/app/assets/stylesheets/barkest_core/.keep +0 -0
  22. data/app/assets/stylesheets/barkest_core/application.css +17 -0
  23. data/app/assets/stylesheets/barkest_core/custom.css.scss +264 -0
  24. data/app/assets/stylesheets/barkest_core/datepicker3.css +790 -0
  25. data/app/controllers/.keep +0 -0
  26. data/app/controllers/access_groups_controller.rb +74 -0
  27. data/app/controllers/account_activations_controller.rb +29 -0
  28. data/app/controllers/application_controller.rb +5 -0
  29. data/app/controllers/barkest_core/application_controller_base.rb +113 -0
  30. data/app/controllers/barkest_core/engine_controller_base.rb +15 -0
  31. data/app/controllers/barkest_core/testsub_controller.rb +21 -0
  32. data/app/controllers/contact_controller.rb +32 -0
  33. data/app/controllers/log_view_controller.rb +31 -0
  34. data/app/controllers/password_resets_controller.rb +126 -0
  35. data/app/controllers/sessions_controller.rb +64 -0
  36. data/app/controllers/status_controller.rb +150 -0
  37. data/app/controllers/system_config_controller.rb +238 -0
  38. data/app/controllers/system_update_controller.rb +164 -0
  39. data/app/controllers/test_access_controller.rb +44 -0
  40. data/app/controllers/test_report_controller.rb +75 -0
  41. data/app/controllers/users_controller.rb +218 -0
  42. data/app/helpers/.keep +0 -0
  43. data/app/helpers/barkest_core/application_helper.rb +134 -0
  44. data/app/helpers/barkest_core/form_helper.rb +469 -0
  45. data/app/helpers/barkest_core/html_helper.rb +70 -0
  46. data/app/helpers/barkest_core/misc_helper.rb +68 -0
  47. data/app/helpers/barkest_core/pdf_helper.rb +180 -0
  48. data/app/helpers/barkest_core/recaptcha_helper.rb +115 -0
  49. data/app/helpers/barkest_core/sessions_helper.rb +94 -0
  50. data/app/helpers/barkest_core/status_helper.rb +118 -0
  51. data/app/helpers/barkest_core/users_helper.rb +32 -0
  52. data/app/mailers/.keep +0 -0
  53. data/app/mailers/application_mailer.rb +5 -0
  54. data/app/mailers/barkest_core/application_mailer_base.rb +30 -0
  55. data/app/mailers/barkest_core/contact_form.rb +20 -0
  56. data/app/mailers/barkest_core/user_mailer.rb +44 -0
  57. data/app/models/.keep +0 -0
  58. data/app/models/access_group.rb +121 -0
  59. data/app/models/access_group_group_member.rb +13 -0
  60. data/app/models/access_group_user_member.rb +11 -0
  61. data/app/models/barkest_core/auth_config.rb +95 -0
  62. data/app/models/barkest_core/authorize_failure.rb +7 -0
  63. data/app/models/barkest_core/contact_message.rb +37 -0
  64. data/app/models/barkest_core/database_config.rb +223 -0
  65. data/app/models/barkest_core/db_table.rb +21 -0
  66. data/app/models/barkest_core/email_config.rb +132 -0
  67. data/app/models/barkest_core/global_status.rb +267 -0
  68. data/app/models/barkest_core/log_entry.rb +101 -0
  69. data/app/models/barkest_core/log_view_options.rb +51 -0
  70. data/app/models/barkest_core/ms_sql_db_definition.rb +441 -0
  71. data/app/models/barkest_core/ms_sql_definition.rb +221 -0
  72. data/app/models/barkest_core/ms_sql_function.rb +423 -0
  73. data/app/models/barkest_core/not_logged_in.rb +7 -0
  74. data/app/models/barkest_core/pdf_table_builder.rb +407 -0
  75. data/app/models/barkest_core/self_update_config.rb +37 -0
  76. data/app/models/barkest_core/user_alert.rb +29 -0
  77. data/app/models/barkest_core/user_alert_generators.rb +58 -0
  78. data/app/models/barkest_core/user_manager.rb +404 -0
  79. data/app/models/barkest_core/work_path.rb +74 -0
  80. data/app/models/disable_user.rb +18 -0
  81. data/app/models/ldap_access_group.rb +15 -0
  82. data/app/models/system_config.rb +99 -0
  83. data/app/models/user.rb +405 -0
  84. data/app/models/user_login_history.rb +11 -0
  85. data/app/views/.keep +0 -0
  86. data/app/views/access_groups/_form.html.erb +19 -0
  87. data/app/views/access_groups/edit.html.erb +2 -0
  88. data/app/views/access_groups/index.html.erb +32 -0
  89. data/app/views/access_groups/new.html.erb +2 -0
  90. data/app/views/access_groups/show.html.erb +4 -0
  91. data/app/views/barkest_core/contact_form/contact.html.erb +16 -0
  92. data/app/views/barkest_core/contact_form/contact.text.erb +13 -0
  93. data/app/views/barkest_core/testsub/_links.html.erb +5 -0
  94. data/app/views/barkest_core/testsub/page1.html.erb +3 -0
  95. data/app/views/barkest_core/testsub/page2.html.erb +2 -0
  96. data/app/views/barkest_core/testsub/page3.html.erb +2 -0
  97. data/app/views/barkest_core/user_mailer/account_activation.html.erb +7 -0
  98. data/app/views/barkest_core/user_mailer/account_activation.text.erb +6 -0
  99. data/app/views/barkest_core/user_mailer/invalid_password_reset.html.erb +3 -0
  100. data/app/views/barkest_core/user_mailer/invalid_password_reset.text.erb +5 -0
  101. data/app/views/barkest_core/user_mailer/password_reset.html.erb +8 -0
  102. data/app/views/barkest_core/user_mailer/password_reset.text.erb +7 -0
  103. data/app/views/contact/index.html.erb +24 -0
  104. data/app/views/layouts/_footer_copyright.html.erb +1 -0
  105. data/app/views/layouts/_menu_admin.html.erb +5 -0
  106. data/app/views/layouts/_menu_anon.html.erb +0 -0
  107. data/app/views/layouts/_menu_auth.html.erb +3 -0
  108. data/app/views/layouts/_menu_footer.html.erb +1 -0
  109. data/app/views/layouts/_nav_logo.html.erb +1 -0
  110. data/app/views/layouts/application.html.erb +2 -0
  111. data/app/views/layouts/barkest_core/_application.html.erb +24 -0
  112. data/app/views/layouts/barkest_core/_footer.html.erb +18 -0
  113. data/app/views/layouts/barkest_core/_header.html.erb +38 -0
  114. data/app/views/layouts/barkest_core/_html_mailer.html.erb +11 -0
  115. data/app/views/layouts/barkest_core/_menu_account.html.erb +14 -0
  116. data/app/views/layouts/barkest_core/_menu_sample.html.erb +1 -0
  117. data/app/views/layouts/barkest_core/_messages.html.erb +4 -0
  118. data/app/views/layouts/barkest_core/_shim.html.erb +4 -0
  119. data/app/views/layouts/barkest_core/_subheader.html.erb +1 -0
  120. data/app/views/layouts/barkest_core/_text_mailer.text.erb +4 -0
  121. data/app/views/layouts/mailer.html.erb +1 -0
  122. data/app/views/layouts/mailer.text.erb +1 -0
  123. data/app/views/log_view/index.html.erb +100 -0
  124. data/app/views/password_resets/edit.html.erb +20 -0
  125. data/app/views/password_resets/new.html.erb +14 -0
  126. data/app/views/sessions/new.html.erb +27 -0
  127. data/app/views/shared/_error_messages.html.erb +29 -0
  128. data/app/views/shared/_generic_user_alert.html.erb +4 -0
  129. data/app/views/status/current.html.erb +34 -0
  130. data/app/views/status/test.html.erb +50 -0
  131. data/app/views/system_config/index.html.erb +25 -0
  132. data/app/views/system_config/show_auth.html.erb +28 -0
  133. data/app/views/system_config/show_database.html.erb +36 -0
  134. data/app/views/system_config/show_email.html.erb +21 -0
  135. data/app/views/system_config/show_self_update.html.erb +13 -0
  136. data/app/views/system_update/index.html.erb +31 -0
  137. data/app/views/system_update/new.html.erb +2 -0
  138. data/app/views/test_access/allow_anon.html.erb +2 -0
  139. data/app/views/test_access/require_admin.html.erb +2 -0
  140. data/app/views/test_access/require_group_x.html.erb +2 -0
  141. data/app/views/test_access/require_user.html.erb +2 -0
  142. data/app/views/test_report/index.csv.csvrb +23 -0
  143. data/app/views/test_report/index.html.erb +6 -0
  144. data/app/views/test_report/index.pdf.prawn +50 -0
  145. data/app/views/test_report/index.xlsx.axlsx +28 -0
  146. data/app/views/users/_user.html.erb +57 -0
  147. data/app/views/users/_user_details.html.erb +15 -0
  148. data/app/views/users/_user_details_for_list.html.erb +1 -0
  149. data/app/views/users/_user_form.html.erb +13 -0
  150. data/app/views/users/disable_confirm.html.erb +19 -0
  151. data/app/views/users/edit.html.erb +15 -0
  152. data/app/views/users/index.html.erb +9 -0
  153. data/app/views/users/new.html.erb +10 -0
  154. data/app/views/users/show.html.erb +46 -0
  155. data/bin/rails +12 -0
  156. data/config/routes.rb +3 -0
  157. data/db/migrate/20160617172539_create_access_groups.rb +10 -0
  158. data/db/migrate/20160617172725_create_users.rb +26 -0
  159. data/db/migrate/20160617172833_create_user_login_histories.rb +12 -0
  160. data/db/migrate/20160622151720_create_access_group_user_members.rb +9 -0
  161. data/db/migrate/20160622151925_create_access_group_group_members.rb +9 -0
  162. data/db/migrate/20160701005706_create_ldap_access_groups.rb +11 -0
  163. data/db/migrate/20161108155029_create_system_configs.rb +11 -0
  164. data/db/seeds/barkest_core_01_create_users.rb +42 -0
  165. data/db/seeds.rb +53 -0
  166. data/lib/barkest_core/concerns/association_with_defaults.rb +55 -0
  167. data/lib/barkest_core/concerns/boolean_parser.rb +88 -0
  168. data/lib/barkest_core/concerns/date_parser.rb +181 -0
  169. data/lib/barkest_core/concerns/email_tester.rb +55 -0
  170. data/lib/barkest_core/concerns/encrypted_fields.rb +156 -0
  171. data/lib/barkest_core/concerns/named_model.rb +73 -0
  172. data/lib/barkest_core/concerns/number_parser.rb +145 -0
  173. data/lib/barkest_core/concerns/utc_conversion.rb +60 -0
  174. data/lib/barkest_core/engine.rb +105 -0
  175. data/lib/barkest_core/extensions/active_record_extensions.rb +120 -0
  176. data/lib/barkest_core/extensions/application_configuration_extensions.rb +38 -0
  177. data/lib/barkest_core/extensions/application_extensions.rb +50 -0
  178. data/lib/barkest_core/extensions/axlsx_extenstions.rb +157 -0
  179. data/lib/barkest_core/extensions/fixture_set_extensions.rb +107 -0
  180. data/lib/barkest_core/extensions/generator_extensions.rb +271 -0
  181. data/lib/barkest_core/extensions/main_app_extensions.rb +35 -0
  182. data/lib/barkest_core/extensions/prawn_document_extensions.rb +367 -0
  183. data/lib/barkest_core/extensions/prawn_table_extensions.rb +131 -0
  184. data/lib/barkest_core/extensions/router_extensions.rb +106 -0
  185. data/lib/barkest_core/extensions/simple_formatter_extensions.rb +66 -0
  186. data/lib/barkest_core/extensions/test_case_extensions.rb +348 -0
  187. data/lib/barkest_core/extensions/time_extensions.rb +164 -0
  188. data/lib/barkest_core/handlers/csv_handler.rb +30 -0
  189. data/lib/barkest_core/version.rb +3 -0
  190. data/lib/barkest_core.rb +324 -0
  191. data/lib/generators/barkest/install_generator.rb +102 -0
  192. data/lib/generators/barkest_core/actions/01_patch_application_controller.rb +55 -0
  193. data/lib/generators/barkest_core/actions/02_patch_application_mailer.rb +56 -0
  194. data/lib/generators/barkest_core/actions/03_patch_assets.rb +62 -0
  195. data/lib/generators/barkest_core/actions/04_patch_layouts.rb +36 -0
  196. data/lib/generators/barkest_core/actions/05_patch_routes.rb +93 -0
  197. data/lib/generators/barkest_core/actions/06_patch_seeds.rb +60 -0
  198. data/lib/generators/barkest_core/actions/07_copy_migrations.rb +51 -0
  199. data/lib/generators/barkest_core/actions/08_configure_database.rb +52 -0
  200. data/lib/generators/barkest_core/actions/09_configure_secrets.rb +29 -0
  201. data/lib/generators/barkest_core/actions/99_patch_gitignore.rb +57 -0
  202. data/lib/generators/barkest_core/install_generator.rb +17 -0
  203. data/test/barkest_core_test.rb +83 -0
  204. data/test/controllers/access_groups_controller_test.rb +53 -0
  205. data/test/controllers/contact_controller_test.rb +10 -0
  206. data/test/controllers/sessions_controller_test.rb +10 -0
  207. data/test/controllers/users_controller_test.rb +10 -0
  208. data/test/dummy/.gitignore +10 -0
  209. data/test/dummy/README.rdoc +28 -0
  210. data/test/dummy/Rakefile +6 -0
  211. data/test/dummy/app/assets/images/.keep +0 -0
  212. data/test/dummy/app/assets/javascripts/application.js +14 -0
  213. data/test/dummy/app/assets/stylesheets/application.css +16 -0
  214. data/test/dummy/app/controllers/application_controller.rb +5 -0
  215. data/test/dummy/app/controllers/concerns/.keep +0 -0
  216. data/test/dummy/app/helpers/application_helper.rb +2 -0
  217. data/test/dummy/app/mailers/.keep +0 -0
  218. data/test/dummy/app/mailers/application_mailer.rb +3 -0
  219. data/test/dummy/app/models/.keep +0 -0
  220. data/test/dummy/app/models/concerns/.keep +0 -0
  221. data/test/dummy/app/views/layouts/application.html.erb +1 -0
  222. data/test/dummy/app/views/layouts/mailer.html.erb +1 -0
  223. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  224. data/test/dummy/app/views/system_config/show_fake.html.erb +3 -0
  225. data/test/dummy/bin/bundle +3 -0
  226. data/test/dummy/bin/rails +4 -0
  227. data/test/dummy/bin/rake +4 -0
  228. data/test/dummy/bin/setup +29 -0
  229. data/test/dummy/config/application.rb +27 -0
  230. data/test/dummy/config/boot.rb +5 -0
  231. data/test/dummy/config/environment.rb +5 -0
  232. data/test/dummy/config/environments/development.rb +47 -0
  233. data/test/dummy/config/environments/production.rb +79 -0
  234. data/test/dummy/config/environments/test.rb +44 -0
  235. data/test/dummy/config/initializers/assets.rb +11 -0
  236. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  237. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  238. data/test/dummy/config/initializers/db_updater_ext.rb +33 -0
  239. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  240. data/test/dummy/config/initializers/inflections.rb +16 -0
  241. data/test/dummy/config/initializers/mime_types.rb +4 -0
  242. data/test/dummy/config/initializers/session_store.rb +3 -0
  243. data/test/dummy/config/initializers/sys_config_ext.rb +12 -0
  244. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  245. data/test/dummy/config/locales/en.yml +23 -0
  246. data/test/dummy/config/routes.rb +60 -0
  247. data/test/dummy/config.ru +4 -0
  248. data/test/dummy/db/schema.rb +95 -0
  249. data/test/dummy/db/seeds/barkest_core_01_create_users.rb +42 -0
  250. data/test/dummy/db/seeds.rb +51 -0
  251. data/test/dummy/lib/assets/.keep +0 -0
  252. data/test/dummy/log/.keep +0 -0
  253. data/test/dummy/public/404.html +67 -0
  254. data/test/dummy/public/422.html +67 -0
  255. data/test/dummy/public/500.html +66 -0
  256. data/test/dummy/public/favicon.ico +0 -0
  257. data/test/dummy/sql/my_test_view.sql +3 -0
  258. data/test/fixtures/access_groups.yml +21 -0
  259. data/test/fixtures/users.yml +71 -0
  260. data/test/helpers/barkest_core/sessions_helper_test.rb +22 -0
  261. data/test/integration/access_group_mgmt_test.rb +33 -0
  262. data/test/integration/access_test.rb +24 -0
  263. data/test/integration/account_activations_access_test.rb +12 -0
  264. data/test/integration/contact_test.rb +98 -0
  265. data/test/integration/extra_partial_test.rb +41 -0
  266. data/test/integration/log_view_access_test.rb +12 -0
  267. data/test/integration/password_resets_test.rb +101 -0
  268. data/test/integration/reports_test.rb +53 -0
  269. data/test/integration/status_access_test.rb +27 -0
  270. data/test/integration/system_config_access_test.rb +24 -0
  271. data/test/integration/system_update_access_test.rb +19 -0
  272. data/test/integration/users_access_test.rb +34 -0
  273. data/test/integration/users_edit_test.rb +178 -0
  274. data/test/integration/users_index_test.rb +62 -0
  275. data/test/integration/users_login_test.rb +67 -0
  276. data/test/integration/users_signup_test.rb +54 -0
  277. data/test/mailers/.keep +0 -0
  278. data/test/mailers/barkest_core/contact_form_test.rb +28 -0
  279. data/test/mailers/barkest_core/user_mailer_test.rb +43 -0
  280. data/test/mailers/previews/barkest_core/contact_form_preview.rb +17 -0
  281. data/test/mailers/previews/barkest_core/user_mailer_preview.rb +26 -0
  282. data/test/models/access_group_group_member_test.rb +28 -0
  283. data/test/models/access_group_test.rb +114 -0
  284. data/test/models/access_group_user_member_test.rb +28 -0
  285. data/test/models/barkest_core/auth_config_test.rb +57 -0
  286. data/test/models/barkest_core/bool_parser_test.rb +28 -0
  287. data/test/models/barkest_core/contact_message_test.rb +61 -0
  288. data/test/models/barkest_core/database_config_test.rb +33 -0
  289. data/test/models/barkest_core/date_parser_test.rb +110 -0
  290. data/test/models/barkest_core/email_config_test.rb +57 -0
  291. data/test/models/barkest_core/global_status_test.rb +50 -0
  292. data/test/models/barkest_core/ms_sql_db_updater_test.rb +115 -0
  293. data/test/models/barkest_core/ms_sql_definition_test.rb +102 -0
  294. data/test/models/barkest_core/ms_sql_function_test.rb +131 -0
  295. data/test/models/barkest_core/number_parser_test.rb +29 -0
  296. data/test/models/barkest_core/self_update_config_test.rb +29 -0
  297. data/test/models/barkest_core/user_alert_test.rb +19 -0
  298. data/test/models/barkest_core/user_manager_test.rb +34 -0
  299. data/test/models/barkest_core/work_path_test.rb +26 -0
  300. data/test/models/disable_user_test.rb +27 -0
  301. data/test/models/generic_time_test.rb +66 -0
  302. data/test/models/ldap_access_group_test.rb +31 -0
  303. data/test/models/pdf_table_builder_test.rb +6 -0
  304. data/test/models/system_config_test.rb +78 -0
  305. data/test/models/user_login_history_test.rb +37 -0
  306. data/test/models/user_test.rb +130 -0
  307. data/test/test_helper.rb +63 -0
  308. 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