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 +4 -4
- data/README.md +53 -1
- data/app/assets/javascript/flash.coffee +6 -0
- data/app/helpers/core_helper.rb +30 -0
- data/app/helpers/core_nav_bar_helper.rb +30 -0
- data/app/helpers/model_modal_helper.rb +213 -0
- data/app/views/common/_flash.html.haml +6 -0
- data/config/locales/en.yml +1 -0
- data/lib/app/jobs/cron/switchboard_sync_configuration.rb +1 -0
- data/lib/app/jobs/cron/trim_audit_logs.rb +2 -0
- data/lib/app/jobs/cron/trim_collection.rb +13 -1
- data/lib/app/jobs/cron/trim_failed_delayed_jobs.rb +1 -1
- data/lib/app/models/concerns/core_system_configuration.rb +1 -0
- data/lib/web47core/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b89eaeeec4187eecc158409f7f0af8ba2748814cdab21fe9f19cb0ac071adf64
|
4
|
+
data.tar.gz: 288b0ceb85c4ba0656106357e7c3dbe28ecc0ee094e32b1d74595fa004361795
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/app/helpers/core_helper.rb
CHANGED
@@ -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
|
data/config/locales/en.yml
CHANGED
@@ -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}"
|
@@ -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
|
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?
|
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
|
#
|
data/lib/web47core/version.rb
CHANGED
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
|
+
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-
|
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
|