web47core 0.4.5 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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