web47core 0.4.5 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62f27101007d6a08a3a21570d5d03b299ff09618587b024298cb6ba7a0a2acc1
4
- data.tar.gz: aadbb1ff2be4b2176903302ce2f013332e8f1bf911dc7a49b761b594836cfaf6
3
+ metadata.gz: b89eaeeec4187eecc158409f7f0af8ba2748814cdab21fe9f19cb0ac071adf64
4
+ data.tar.gz: 288b0ceb85c4ba0656106357e7c3dbe28ecc0ee094e32b1d74595fa004361795
5
5
  SHA512:
6
- metadata.gz: 1d5e07109eb32edf3760ab0e3f6e38b6dfcf8dc052d6953101914c44fbfef69eda0508086bf0ac7d2ecdc07d7a209335a02f254e6d2f9d145e5fd3d759228593
7
- data.tar.gz: ce504663f0b0fddd7296bfb0f4e28ba5b04fe471c0491acbc25f84aa600810c3c67bab020ee4574eedebe1dc022d05ca251c17f604964089b57b6ca245306b71
6
+ metadata.gz: 6e1815ea8ac8f046d9ac3964c0dbb3935b33ce04108dd82359f6df9ebc24c0fe91898e97cf5f7e2263e242bd70ceb2e8e41f0b6b956a687196e8340c9009563c
7
+ data.tar.gz: bd952fc65ed2eea64389e92911ea46b439ecfd593b6821a026a5757b8eeb4c4444a5c17e6c812211f03a6363f578d88a9d760cd9cca85ba6a4d16d93cb53b46e
data/README.md CHANGED
@@ -145,6 +145,10 @@ Before starting the server, you need to run the database command
145
145
  ```mongo
146
146
  db.cron_tabs.updateMany({_type: 'JobCronTab'}, {$set: {_type: 'Cron::JobTab'}});
147
147
  ```
148
+ #### Routes
149
+ Update abilities to new class names
150
+ CronTab, JobCronTab, CronJobServer to Cron::Tab, Cron::JobTab, Cron::Server
151
+
148
152
  #### Routes
149
153
  The following routes should be added to the correct namespace for your applicaiton
150
154
  ```ruby
@@ -179,4 +183,52 @@ The following routes should be added to the correct namespace for your applicait
179
183
  get :resubmit
180
184
  end
181
185
  end
182
- ```
186
+ ```
187
+ #### Controllers
188
+ ##### CronController
189
+ Update the CronController with something like below, and remove the views and any localization you might have made.
190
+ ```ruby
191
+ # frozen_string_literal: true
192
+
193
+ #
194
+ # Manage all crontabs in the system Configuration
195
+ #
196
+ class CronController < AdminController
197
+ load_and_authorize_resource :cron_tab, only: %w[run_now update edit], id_param: :id, class: 'Cron::Tab'
198
+ load_and_authorize_resource :cron_server, only: %w[demote destroy], id_param: :id, class: 'Cron::Server'
199
+ include ::CoreCronController
200
+ rescue_from Mongoid::Errors::DocumentNotFound, with: :document_not_found_error
201
+ end
202
+ ```
203
+ ##### DelayedJobController
204
+ Update the DelayedJobController with something like below, and remove the views and any localization you might have made.
205
+ ```ruby
206
+ # frozen_string_literal: true
207
+
208
+ #
209
+ # Manage access to delayed jobs for the admin UI
210
+ #
211
+ class DelayedJobsController < AdminController
212
+ include ::CoreDelayedJobsController
213
+ load_and_authorize_resource class: 'Delayed::Backend::Mongoid::Job'
214
+ rescue_from Mongoid::Errors::DocumentNotFound, with: :document_not_found_error
215
+ end
216
+ ```
217
+ ##### StatusController
218
+ Remove controller, views and localizations
219
+ ##### SystemConfigurationsController
220
+ Update the SystemConfigurationsController with something like below, and remove the views and any localization you might have made.
221
+ ```ruby
222
+ # frozen_string_literal: true
223
+
224
+ #
225
+ # Manage the system configuration page
226
+ #
227
+ class SystemConfigurationsController < AdminController
228
+ include ::CoreSystemConfigurationsController
229
+ load_and_authorize_resource :system_configuration
230
+ end
231
+ ```
232
+ #### ~/bin Directory
233
+
234
+ Remove the delayed_job, delayed_job.sh and cron_server.sh files
@@ -0,0 +1,6 @@
1
+ #
2
+ # Transform the flash message to toast messages
3
+ #
4
+ $(document).ready ->
5
+ $('.flash .message').each ->
6
+ M.toast(html: $(this).html())
@@ -11,6 +11,36 @@ module CoreHelper
11
11
  content_for(:title) { page_title }
12
12
  end
13
13
 
14
+ #
15
+ # Record the search url if one is needed
16
+ #
17
+ def search_url(search_url)
18
+ content_for(:search_url) { search_url }
19
+ end
20
+
21
+ #
22
+ # Set the bread crumbs for navigation
23
+ #
24
+ def breadcrumbs(&block)
25
+ content_for(:breadcrumb_content) { block }
26
+ end
27
+
28
+ #
29
+ # Map alerts to a valid icon
30
+ #
31
+ def flash_map_name(key)
32
+ case key
33
+ when 'alert'
34
+ 'notification_important'
35
+ when 'success'
36
+ 'check_circle'
37
+ when 'notice'
38
+ 'note'
39
+ else
40
+ key
41
+ end
42
+ end
43
+
14
44
  #
15
45
  # Pull the value from system configuration and mask the ones that match the given strings
16
46
  #
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Helpful methods for navigation bar on the side
5
+ #
6
+ module CoreNavBarHelper
7
+ #
8
+ # Determines which css attributes should be assigned to the current menu,
9
+ # options are
10
+ # <ul>
11
+ # <li>read-only - the menu is greyed out and disabled</li>
12
+ # <li>locked - a lock icon appears</li>
13
+ # <li>active - if the current controller matches either the name or names</li>
14
+ # </ul>
15
+ #
16
+ def nav_css(names, read_only = false, feature_enabled = true, feature_visible = true)
17
+ states = []
18
+ states << 'read-only' if read_only
19
+ states << 'locked' unless feature_enabled
20
+ states << 'hidden' unless feature_visible
21
+ if names.is_a? String
22
+ states << 'active' if names.eql?(controller.controller_name)
23
+ elsif names.is_a? Symbol
24
+ states << 'active' if names.to_s.eql?(controller.controller_name)
25
+ elsif names.is_a? Array
26
+ states << 'active' if names.include?(controller.controller_name)
27
+ end
28
+ states.join(' ')
29
+ end
30
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Helper to create a modal dialog for a given model
5
+ #
6
+ module ModelModalHelper
7
+ #
8
+ # Render the relationship for the model, using caching to speed things up a bit
9
+ #
10
+ # This helper should be used on the related objects in the table, to cut down on the database queries when rendering
11
+ # the table.
12
+ #
13
+ def related_modal_tag(model, relation, options = {})
14
+ related_model = fetch_related_model(model, relation)
15
+ return if related_model.blank?
16
+
17
+ dynamic_related_modal(related_model, related_model_edit_path(model, relation, related_model, options), options)
18
+ end
19
+
20
+ #
21
+ # Only show the trigger with the edit path, let the rest be generated later
22
+ #
23
+ def dynamic_related_modal(related_model, edit_path, _options = {})
24
+ model_name = related_model.class.to_s.underscore
25
+ datum = { view_url: edit_path.gsub('/edit', '') }
26
+ anchor_id = "#{model_name}-#{related_model.id}"
27
+ title = related_model.respond_to?(:short_name) ? related_model.short_name : related_model.name
28
+ content_tag(:div) do
29
+ concat(content_tag(:a, href: "##{anchor_id}", class: 'modal-trigger') do
30
+ concat(content_tag(:span, title))
31
+ end)
32
+ concat(content_tag(:div, id: anchor_id, class: 'modal', data: datum) do
33
+ concat(content_tag(:div, class: 'modal-content') do
34
+ concat(content_tag(:h2, class: 'center') do
35
+ concat(content_tag(:span, related_model.name))
36
+ end)
37
+ concat(content_tag(:div, class: 'center-align') do
38
+ concat(content_tag(:div, class: 'progress red lighten-4') do
39
+ tag(:div, class: 'indeterminate red')
40
+ end)
41
+ end)
42
+ end)
43
+ concat(model_modal_footer(related_model, edit_path))
44
+ end)
45
+ end
46
+ end
47
+
48
+ def related_model_edit_path(model, relation, related_model, options = {})
49
+ if options[:parent].present?
50
+ parent_model = fetch_related_model(model, options[:parent])
51
+ send("edit_#{options[:parent]}_#{relation}_path", parent_model, related_model)
52
+ else
53
+ send("edit_#{relation}_path", related_model)
54
+ end
55
+ end
56
+
57
+ def fetch_related_model(model, relation)
58
+ # First get the relationship from cache
59
+ related_id = model.send("#{relation}_id")
60
+ key = "model_modal::#{relation}::#{related_id}"
61
+ Rails.cache.fetch(key, expires_in: 6.hours) { model.send(relation) }
62
+ end
63
+
64
+ #
65
+ # Render a modal tag for the given model object
66
+ #
67
+ def model_modal_tag(model, edit_path, options = {})
68
+ model_modal_action(model, options) + model_modal(model, edit_path, options)
69
+ end
70
+
71
+ def model_modal_action(model, _options = {})
72
+ content_tag(:a, class: 'modal-trigger', href: "#modal-#{model.id}") do
73
+ concat(model.name)
74
+ end
75
+ end
76
+
77
+ def model_modal(model, edit_path, options = {})
78
+ content_tag(:div, class: 'modal', id: "modal-#{model.id}") do
79
+ concat(model_modal_content(model, options))
80
+ concat(model_modal_footer(model, edit_path))
81
+ end
82
+ end
83
+
84
+ def dynamic_model_modal(model, options = {})
85
+ model_modal_content(model, options) + model_modal_footer(model, "#{request.url}/edit")
86
+ end
87
+
88
+ def model_modal_content(model, options = {})
89
+ content_tag(:div, class: 'modal-content') do
90
+ concat(content_tag(:h2) { model.name })
91
+ concat(content_tag(:div, class: 'row') do
92
+ concat(model_modal_tabs(model, options))
93
+ concat(model_modal_fields_tab(model, options))
94
+ concat(model_modal_standard_tab(model, options))
95
+ concat(model_modal_logs_tab(model, options)) if model.respond_to?(:logs)
96
+ end)
97
+ end
98
+ end
99
+
100
+ def model_modal_tabs(model, _options = {})
101
+ content_tag(:div, class: 'col s12') do
102
+ concat(content_tag(:ul, class: 'tabs tabs-fixed-width') do
103
+ concat(content_tag(:li, class: 'tab') do
104
+ content_tag(:a, href: "#field-tab-#{model.id}") { model.class.to_s.titleize }
105
+ end)
106
+ concat(content_tag(:li, class: 'tab') { content_tag(:a, href: "#standard-tab-#{model.id}") { 'Details' } })
107
+ if model.respond_to?(:logs)
108
+ concat(content_tag(:li, class: 'tab') { content_tag(:a, href: "#logs-tab-#{model.id}") { 'Logs' } })
109
+ end
110
+ end)
111
+ end
112
+ end
113
+
114
+ def model_modal_standard_tab(model, options = {})
115
+ content_tag(:div, id: "standard-tab-#{model.id}", class: 'col s12') do
116
+ concat(model_modal_standard(model, options))
117
+ end
118
+ end
119
+
120
+ def model_modal_fields_tab(model, options = {})
121
+ content_tag(:div, id: "field-tab-#{model.id}", class: 'col s12') do
122
+ concat(model_modal_fields(model, options))
123
+ end
124
+ end
125
+
126
+ def model_modal_logs_tab(model, _options = {})
127
+ content_tag(:div, id: "logs-tab-#{model.id}", class: 'col s12') do
128
+ content_tag(:table, class: 'center-align') do
129
+ concat(content_tag(:thead) do
130
+ concat(content_tag(:tr) do
131
+ concat(content_tag(:th) { 'Created' })
132
+ concat(content_tag(:th) { 'Command' })
133
+ concat(content_tag(:th) { 'Message' })
134
+ end)
135
+ end)
136
+ concat(content_tag(:tbody) do
137
+ model.logs.each do |log|
138
+ concat(model_modal_log(log))
139
+ end
140
+ end)
141
+ end
142
+ end
143
+ end
144
+
145
+ def model_modal_log(log)
146
+ content_tag(:tr) do
147
+ concat(content_tag(:td) { log.created_at })
148
+ concat(content_tag(:td) { log.display_message })
149
+ end
150
+ end
151
+
152
+ def model_modal_fields(model, _options = {})
153
+ content_tag(:table, class: 'center-align') do
154
+ concat(content_tag(:tbody) do
155
+ model.class.allowed_param_names.sort.each do |field_name|
156
+ concat(model_modal_field(model, field_name))
157
+ end
158
+ end)
159
+ end
160
+ end
161
+
162
+ def model_modal_standard(model, _options = {})
163
+ content_tag(:table, class: 'center-align highlighted') do
164
+ concat(content_tag(:tbody) do
165
+ %w[_id _type created_at updated_at search_text sort_text].each do |field_name|
166
+ concat(model_modal_field(model, field_name))
167
+ end
168
+ end)
169
+ end
170
+ end
171
+
172
+ def model_modal_field(model, field_name)
173
+ content_tag(:tr) do
174
+ concat(content_tag(:th, class: 'right-align') do
175
+ field_name.titleize
176
+ end)
177
+ concat(content_tag(:td) do
178
+ model_modal_field_value(model, field_name)
179
+ end)
180
+ end
181
+ end
182
+
183
+ def model_modal_field_value(model, field_name)
184
+ value = model.respond_to?(field_name) ? model.send(field_name) : ''
185
+ case value
186
+ when BSON::ObjectId
187
+ if field_name.eql?('_id')
188
+ value.to_s
189
+ else
190
+ related_model = fetch_related_model(model, field_name.chomp('_id'))
191
+ related_model.present? ? related_model.name : 'N/A'
192
+ end
193
+ when FalseClass
194
+ 'No'
195
+ when TrueClass
196
+ 'Yes'
197
+ when Mongoid::Boolean, Boolean
198
+ value ? 'Yes' : 'No'
199
+ when Date, DateTime, Time
200
+ current_user.local_time(value, :long)
201
+ when Integer, Array
202
+ value.to_s
203
+ else
204
+ value
205
+ end
206
+ end
207
+
208
+ def model_modal_footer(model, edit_path)
209
+ content_tag(:div, class: 'modal-footer') do
210
+ concat(edit_modal_tag(model, edit_path))
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,6 @@
1
+ .flash
2
+ - flash.each do |key, value|
3
+ .message
4
+ %i.material-icons
5
+ = flash_map_name(key)
6
+ %p=value
@@ -7,6 +7,7 @@ en:
7
7
  actions:
8
8
  update: Update
9
9
  cancel: Cancel
10
+ save: Save
10
11
  time:
11
12
  formats:
12
13
  long: '%Y-%m-%d %H:%M:%ss (%Z)'
@@ -28,6 +28,7 @@ module Cron
28
28
  json = JSON.parse(response.body)
29
29
  config = SystemConfiguration.configuration
30
30
  json['results'].each { |key, value| update_config(config, key, value) }
31
+ config.switchboard_last_sync_at = Time.now.utc
31
32
  config.save!
32
33
  else
33
34
  App47Logger.log_error "Unable to fetch switchboard config, #{response.inspect}"
@@ -20,6 +20,8 @@ module Cron
20
20
  #
21
21
  def archive?(item)
22
22
  super && (!item.is_a?(UserModelAuditLog) || item.model.blank?)
23
+ rescue StandardError
24
+ super
23
25
  end
24
26
 
25
27
  #
@@ -14,16 +14,28 @@ module Cron
14
14
  count = 0
15
15
  total = collection.count
16
16
  while count <= total
17
- collection.limit(250).skip(count).each { |item| item.destroy if archive?(item) }
17
+ collection.limit(250).skip(count).each { |item| trim_item(item) if archive?(item) }
18
18
  count += 250
19
19
  end
20
20
  end
21
21
 
22
+ #
23
+ # Try to safely destroy the item, warn if not successful
24
+ #
25
+ def trim_item(item)
26
+ item.destroy
27
+ rescue StandardError => error
28
+ App47Logger.log_error "Unable to destroy item #{item.inspect}", error
29
+ end
30
+
22
31
  #
23
32
  # Test if this should be archived
24
33
  #
25
34
  def archive?(item)
26
35
  item.updated_at < allowed_time_for_item(item)
36
+ rescue StandardError => error
37
+ App47Logger.log_warn "Unable to archive item #{item.inspect}", error
38
+ false
27
39
  end
28
40
 
29
41
  #
@@ -34,7 +34,7 @@ module Cron
34
34
  # If the slack API is not present, don't delete jobs or we wont know about it.
35
35
  #
36
36
  def self.valid_environment?
37
- SystemConfiguration.slack_api_url.present? && Delayed::Backend::Mongoid::Job.count.positive?
37
+ SystemConfiguration.slack_api_url.present?
38
38
  end
39
39
  end
40
40
  end
@@ -59,6 +59,7 @@ module CoreSystemConfiguration
59
59
  field :switchboard_base_url, type: String, default: 'https://switchboard.app47.com'
60
60
  field :switchboard_stack_id, type: String
61
61
  field :switchboard_stack_api_token, type: String
62
+ field :switchboard_last_sync_at, type: Time
62
63
  #
63
64
  # Validations
64
65
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Web47core
4
- VERSION = '0.4.5'
4
+ VERSION = '0.5.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web47core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Schroeder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-05 00:00:00.000000000 Z
11
+ date: 2020-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -556,18 +556,22 @@ files:
556
556
  - LICENSE
557
557
  - README.md
558
558
  - app/assets/images/1x1.png
559
+ - app/assets/javascript/flash.coffee
559
560
  - app/controllers/exceptions_controller.rb
560
561
  - app/controllers/notifications_controller.rb
561
562
  - app/controllers/status_controller.rb
562
563
  - app/helpers/core_form_helper.rb
563
564
  - app/helpers/core_helper.rb
564
565
  - app/helpers/core_link_helper.rb
566
+ - app/helpers/core_nav_bar_helper.rb
567
+ - app/helpers/model_modal_helper.rb
565
568
  - app/views/admin/cron/edit.html.haml
566
569
  - app/views/admin/cron/index.html.haml
567
570
  - app/views/admin/delayed_jobs/index.html.haml
568
571
  - app/views/admin/delayed_jobs/show.html.haml
569
572
  - app/views/admin/system_configurations/edit.html.haml
570
573
  - app/views/admin/system_configurations/show.html.haml
574
+ - app/views/common/_flash.html.haml
571
575
  - app/views/common/_form_actions.html.haml
572
576
  - app/views/cron/_edit.html.haml
573
577
  - app/views/cron/_index.html.haml