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 +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
|