web47core 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -0
- data/app/helpers/core_form_helper.rb +68 -4
- data/app/helpers/core_link_helper.rb +177 -25
- data/app/helpers/model_modal_helper.rb +1 -1
- data/app/views/delayed_jobs/_index.html.haml +1 -1
- data/app/views/delayed_jobs/_show.html.haml +1 -1
- data/lib/app/jobs/cron/job.rb +11 -0
- data/lib/app/models/concerns/search_able.rb +2 -2
- data/lib/app/models/concerns/seucre_fields.rb +23 -0
- data/lib/app/models/concerns/standard_model.rb +44 -13
- data/lib/app/models/concerns/time_zone_able.rb +10 -0
- data/lib/web47core/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70bf5b32aa6d77005704da9da81ad262c3ae29c616f0fe1534f3aab345787788
|
4
|
+
data.tar.gz: 23d93a745ac6455c5839e31dea6c8fdf7b309b20a5788d6d5cd9481796b44b58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69e34643867f8a073e28f031aeda323d6f6bcd61f93d38b8748b38f61f82109772ffbc0df984cd4e2fd6e7e1eff228addba62714ba6f96f314d42dc6dd1c4580
|
7
|
+
data.tar.gz: 61b2c9ec0213d473be51951b8d5a999ad584d153a92a7dd869a37bc61a679352e8c810f33375d10bbdd2c9058b48a037e1cfcedad684aec08d7feab3adf152a6
|
data/README.md
CHANGED
@@ -88,6 +88,7 @@ _Please do not ship to production code using the git repo, as the production ser
|
|
88
88
|
17. `CronJobServer` and `CronJobServerTest`
|
89
89
|
18. `JobCronTab` and `JobCronTabTest`
|
90
90
|
19. `CronTab`
|
91
|
+
20. `SecureFields`
|
91
92
|
|
92
93
|
#### Models
|
93
94
|
##### Concerns
|
@@ -145,6 +146,7 @@ Before starting the server, you need to run the database command
|
|
145
146
|
```mongo
|
146
147
|
db.cron_tabs.updateMany({_type: 'JobCronTab'}, {$set: {_type: 'Cron::JobTab'}});
|
147
148
|
```
|
149
|
+
|
148
150
|
#### Routes
|
149
151
|
Update abilities to new class names
|
150
152
|
CronTab, JobCronTab, CronJobServer to Cron::Tab, Cron::JobTab, Cron::Server
|
@@ -200,6 +202,12 @@ class CronController < AdminController
|
|
200
202
|
rescue_from Mongoid::Errors::DocumentNotFound, with: :document_not_found_error
|
201
203
|
end
|
202
204
|
```
|
205
|
+
|
206
|
+
To start or stop the cron server, run the bundler command:
|
207
|
+
```
|
208
|
+
bundle exec cron_server start|stop
|
209
|
+
```
|
210
|
+
|
203
211
|
##### DelayedJobController
|
204
212
|
Update the DelayedJobController with something like below, and remove the views and any localization you might have made.
|
205
213
|
```ruby
|
@@ -214,6 +222,12 @@ class DelayedJobsController < AdminController
|
|
214
222
|
rescue_from Mongoid::Errors::DocumentNotFound, with: :document_not_found_error
|
215
223
|
end
|
216
224
|
```
|
225
|
+
|
226
|
+
To start or stop the delayed jobs, run the bundler command:
|
227
|
+
```
|
228
|
+
bundle exec delayed_job start|stop
|
229
|
+
```
|
230
|
+
|
217
231
|
##### StatusController
|
218
232
|
Remove controller, views and localizations
|
219
233
|
##### SystemConfigurationsController
|
@@ -10,6 +10,30 @@ module CoreFormHelper
|
|
10
10
|
form.render_form(&block)
|
11
11
|
end
|
12
12
|
|
13
|
+
#
|
14
|
+
# Text area
|
15
|
+
#
|
16
|
+
def form_text_area(model, field, options = {})
|
17
|
+
classes = options[:classes] || %w[s12]
|
18
|
+
value = model.send(field)
|
19
|
+
# options[:value] = value
|
20
|
+
# options[:disabled] ||= false
|
21
|
+
# tag_options = {class: []} # text_field_options(model, field, options)
|
22
|
+
# tag_options[:class] += ['materialize-textarea']
|
23
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
24
|
+
concat(text_area(model, field, value, options))
|
25
|
+
concat(form_label_tag(model, field, value, options))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def text_area(model, field, value, options = {})
|
30
|
+
tag_options = text_field_options(model, field, options)
|
31
|
+
tag_options[:class] += ['materialize-textarea']
|
32
|
+
content_tag(:textarea, tag_options) do
|
33
|
+
concat(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
13
37
|
#
|
14
38
|
# Text field
|
15
39
|
#
|
@@ -18,6 +42,7 @@ module CoreFormHelper
|
|
18
42
|
value = model.send(field)
|
19
43
|
options[:type] = :text
|
20
44
|
options[:value] = value
|
45
|
+
options[:disabled] ||= false
|
21
46
|
tag_options = text_field_options(model, field, options)
|
22
47
|
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
23
48
|
concat(tag(:input, tag_options))
|
@@ -30,6 +55,7 @@ module CoreFormHelper
|
|
30
55
|
value = model.send(field)
|
31
56
|
options[:value] = value.strftime('%d %B, %Y') if value.present?
|
32
57
|
options[:type] = :text
|
58
|
+
options[:disabled] ||= false
|
33
59
|
tag_options = text_field_options(model, field, options)
|
34
60
|
tag_options[:class] = options[:date_picker_type] || 'simple-date-picker'
|
35
61
|
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
@@ -38,6 +64,23 @@ module CoreFormHelper
|
|
38
64
|
end
|
39
65
|
end
|
40
66
|
|
67
|
+
#
|
68
|
+
# Time picker field
|
69
|
+
#
|
70
|
+
def form_time_field(model, field, options = {})
|
71
|
+
classes = options[:classes] || %w[s12 m6 l4 xl3]
|
72
|
+
value = model.send(field)
|
73
|
+
options[:value] = value
|
74
|
+
options[:type] = :text
|
75
|
+
options[:disabled] ||= false
|
76
|
+
tag_options = text_field_options(model, field, options)
|
77
|
+
tag_options[:class] = options[:time_picker_type] || 'time-picker'
|
78
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
79
|
+
concat(tag(:input, tag_options))
|
80
|
+
concat(form_label_tag(model, field, value, options))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
41
84
|
#
|
42
85
|
# Password field
|
43
86
|
#
|
@@ -80,7 +123,13 @@ module CoreFormHelper
|
|
80
123
|
#
|
81
124
|
def form_select_tag(model, field, options = {})
|
82
125
|
form_name = form_field_name(model, field, options)
|
83
|
-
|
126
|
+
select_content = {
|
127
|
+
id: form_name,
|
128
|
+
name: form_name,
|
129
|
+
class: options[:input_classes],
|
130
|
+
disabled: options[:disabled]
|
131
|
+
}
|
132
|
+
content_tag(:select, select_content) do
|
84
133
|
form_select_option_key_values(model.send(field), options).each do |value|
|
85
134
|
concat(content_tag(:option, value: value[:key], selected: value[:selected]) do
|
86
135
|
concat(value[:value])
|
@@ -96,15 +145,16 @@ module CoreFormHelper
|
|
96
145
|
select_options << { key: '', value: options[:prompt], selected: false } if options[:prompt].present?
|
97
146
|
options[:options].each do |option_value|
|
98
147
|
option_value[:display_name] = option_value.display_name if option_value.respond_to?(:display_name)
|
148
|
+
option_value[:display_name] = option_value.user_display_name if option_value.respond_to?(:user_display_name)
|
99
149
|
select_options << case option_value
|
100
150
|
when String, Integer
|
101
151
|
{ key: option_value,
|
102
152
|
value: option_value,
|
103
153
|
selected: value.eql?(option_value) }
|
104
154
|
when Array
|
105
|
-
{ key: option_value.
|
106
|
-
value: option_value.
|
107
|
-
selected: value.to_s.eql?(option_value.
|
155
|
+
{ key: option_value.last,
|
156
|
+
value: option_value.first,
|
157
|
+
selected: value.to_s.eql?(option_value.last.to_s) }
|
108
158
|
when Hash
|
109
159
|
{ key: option_value[:key],
|
110
160
|
value: option_value[:value],
|
@@ -164,6 +214,20 @@ module CoreFormHelper
|
|
164
214
|
end
|
165
215
|
end
|
166
216
|
|
217
|
+
#
|
218
|
+
# File field
|
219
|
+
#
|
220
|
+
def form_file(model, field, file_types = '.xlsx', classes = %w[s12 m6 l4 xl3])
|
221
|
+
form_name = form_field_name(model, field)
|
222
|
+
form_id = "#{model.class.to_s.underscore}_#{field}"
|
223
|
+
value = model.send(field)
|
224
|
+
file_tag = tag(:input, id: form_id, name: form_name, type: :file, accept: file_types)
|
225
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
226
|
+
concat(file_tag)
|
227
|
+
concat(form_label_tag(model, field, value))
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
167
231
|
#
|
168
232
|
# get the label for field
|
169
233
|
#
|
@@ -5,12 +5,22 @@
|
|
5
5
|
#
|
6
6
|
module CoreLinkHelper
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# Generate a download link with the download icon
|
9
|
+
#
|
10
|
+
def download_tag(url, options = {})
|
11
|
+
content_tag(:a, href: url) do
|
12
|
+
concat(materialize_icon(options[:download_icon_name] || 'cloud_download'))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Setup the text as copy text
|
9
18
|
#
|
10
19
|
def copy_tag(copy_text, options = {})
|
11
20
|
content_tag(:p, class: 'stack-tight') do
|
12
|
-
concat(copy_text)
|
21
|
+
concat(content_tag(:span) { copy_text })
|
13
22
|
concat(copy_text_tag(copy_text, options))
|
23
|
+
concat(download_tag(options[:download_url], options)) if options[:download_url].present?
|
14
24
|
end
|
15
25
|
end
|
16
26
|
|
@@ -30,15 +40,25 @@ module CoreLinkHelper
|
|
30
40
|
# Add the table action button and setup the drop down
|
31
41
|
#
|
32
42
|
def table_action_button(action_id, icon_name = 'more_horiz')
|
33
|
-
datum = {
|
43
|
+
datum = { target: action_id,
|
34
44
|
constrainWidth: false,
|
35
45
|
gutter: 28,
|
36
46
|
alignment: 'right' }
|
37
|
-
content_tag(:a, class: 'dropdown-
|
47
|
+
content_tag(:a, class: 'dropdown-trigger', data: datum) do
|
38
48
|
concat(materialize_icon(icon_name))
|
39
49
|
end
|
40
50
|
end
|
41
51
|
|
52
|
+
#
|
53
|
+
# Add a favorite tag
|
54
|
+
#
|
55
|
+
def favorite_tag(favorite)
|
56
|
+
content_tag(:i,
|
57
|
+
class: 'material-icons pointer favorite',
|
58
|
+
id: favorite.id.to_s,
|
59
|
+
type: favorite.favorite_type) { concat('favorite_border') }
|
60
|
+
end
|
61
|
+
|
42
62
|
#
|
43
63
|
# Add a material icon by name
|
44
64
|
#
|
@@ -52,7 +72,7 @@ module CoreLinkHelper
|
|
52
72
|
# Generic link tag
|
53
73
|
#
|
54
74
|
def link_tag(title, path, options = {})
|
55
|
-
content_tag(:a, href: path) do
|
75
|
+
content_tag(:a, href: path, class: options[:class]) do
|
56
76
|
concat(content_tag(:i, class: 'material-icons left') { options[:icon_name] }) if options[:icon_name].present?
|
57
77
|
concat(title)
|
58
78
|
end
|
@@ -71,14 +91,15 @@ module CoreLinkHelper
|
|
71
91
|
end
|
72
92
|
|
73
93
|
#
|
74
|
-
# Edit
|
94
|
+
# Edit a thingy
|
75
95
|
#
|
76
96
|
def edit_link_tag(obj, path, options = {})
|
77
97
|
return unless can? :edit, obj
|
78
98
|
|
99
|
+
icon = options[:icon] || 'edit'
|
79
100
|
content_tag(:a, href: path) do
|
80
101
|
concat(content_tag(:i, class: 'material-icons') do
|
81
|
-
|
102
|
+
icon
|
82
103
|
end)
|
83
104
|
concat(options[:label]) if options[:label].present?
|
84
105
|
end
|
@@ -136,9 +157,10 @@ module CoreLinkHelper
|
|
136
157
|
def info_link_tag(obj, path, options = {})
|
137
158
|
return unless can? :read, obj
|
138
159
|
|
139
|
-
|
160
|
+
icon = options[:icon] || 'info'
|
161
|
+
content_tag(:a, href: path) do
|
140
162
|
concat(content_tag(:i, class: 'material-icons') do
|
141
|
-
|
163
|
+
icon
|
142
164
|
end)
|
143
165
|
concat(options[:label]) if options[:label].present?
|
144
166
|
end
|
@@ -149,6 +171,7 @@ module CoreLinkHelper
|
|
149
171
|
#
|
150
172
|
def action_list_tag(condition, path, options = {})
|
151
173
|
return unless condition
|
174
|
+
|
152
175
|
raise('Label Required') if options[:label].blank?
|
153
176
|
|
154
177
|
content_tag(:li) do
|
@@ -162,7 +185,9 @@ module CoreLinkHelper
|
|
162
185
|
def action_link_tag(condition, path, options = {})
|
163
186
|
return unless condition
|
164
187
|
|
165
|
-
|
188
|
+
confirmation = options[:confirmation] || t('links.action_confirmation')
|
189
|
+
confirmation_required = options[:confirmation].present? ? { confirm: confirmation } : {}
|
190
|
+
content_tag(:a, href: path, class: options[:classes], data: confirmation_required) do
|
166
191
|
concat(content_tag(:i, class: 'material-icons') do
|
167
192
|
options[:icon_name] || 'info'
|
168
193
|
end)
|
@@ -174,7 +199,7 @@ module CoreLinkHelper
|
|
174
199
|
# Delete a thingy in a pull down list
|
175
200
|
#
|
176
201
|
def delete_list_tag(obj, path, options = {})
|
177
|
-
return unless can? :
|
202
|
+
return unless can? :destroy, obj
|
178
203
|
|
179
204
|
options[:label] ||= I18n.t('ui_form.actions.delete')
|
180
205
|
content_tag(:li) do
|
@@ -186,7 +211,7 @@ module CoreLinkHelper
|
|
186
211
|
# Delete an thingy
|
187
212
|
#
|
188
213
|
def delete_link_tag(obj, path, options = {})
|
189
|
-
return unless can? :
|
214
|
+
return unless can? :destroy, obj
|
190
215
|
|
191
216
|
data = { method: :delete,
|
192
217
|
confirm: options[:confirm] || t('links.deletion_confirmation', name: obj.class.to_s.underscore.humanize) }
|
@@ -198,6 +223,111 @@ module CoreLinkHelper
|
|
198
223
|
end
|
199
224
|
end
|
200
225
|
|
226
|
+
#
|
227
|
+
# Create a thingy in a pull-down list
|
228
|
+
#
|
229
|
+
def create_list_tag(obj, path, options = {})
|
230
|
+
return unless can? :create, obj
|
231
|
+
|
232
|
+
options[:label] ||= I18n.t('ui_form.actions.create')
|
233
|
+
content_tag(:li) do
|
234
|
+
create_link_tag(obj, path, options)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
#
|
239
|
+
# Create a thingy
|
240
|
+
#
|
241
|
+
def create_link_tag(obj, path, options = {})
|
242
|
+
return unless can? :create, obj
|
243
|
+
|
244
|
+
confirmation = options[:confirmation] || t('links.action_confirmation', name: obj.class.to_s.underscore.humanize)
|
245
|
+
content_tag(:a, href: path, data: { confirm: confirmation }) do
|
246
|
+
concat(content_tag(:i, class: 'material-icons') do
|
247
|
+
options[:icon_name] || 'add'
|
248
|
+
end)
|
249
|
+
concat(options[:label]) if options[:label].present?
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# Send notification in a pull down list
|
255
|
+
#
|
256
|
+
def notification_list_tag(obj, path, options = {})
|
257
|
+
return unless can? :manage, obj
|
258
|
+
|
259
|
+
options[:label] ||= I18n.t('customer_account_users.index.reset_password')
|
260
|
+
content_tag(:li) do
|
261
|
+
notification_link_tag(obj, path, options)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
#
|
266
|
+
# Send notification
|
267
|
+
#
|
268
|
+
def notification_link_tag(obj, path, options = {})
|
269
|
+
return unless can? :manage, obj
|
270
|
+
|
271
|
+
content_tag(:a, href: path) do
|
272
|
+
concat(content_tag(:i, class: 'material-icons') do
|
273
|
+
options[:icon_name] || 'email'
|
274
|
+
end)
|
275
|
+
concat(options[:label]) if options[:label].present?
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
#
|
280
|
+
# Promote a publishable kb object in a pull down list
|
281
|
+
#
|
282
|
+
def promote_list_tag(obj, path, options = {})
|
283
|
+
return unless can? :promote, obj
|
284
|
+
|
285
|
+
options[:label] ||= I18n.t('links.promote')
|
286
|
+
content_tag(:li) do
|
287
|
+
promote_link_tag(obj, path, options)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
#
|
292
|
+
# Promote a publishable kb object
|
293
|
+
#
|
294
|
+
def promote_link_tag(obj, path, options = {})
|
295
|
+
return unless can? :promote, obj
|
296
|
+
|
297
|
+
content_tag(:a, href: path) do
|
298
|
+
concat(content_tag(:i, class: 'material-icons') do
|
299
|
+
'file_upload'
|
300
|
+
end)
|
301
|
+
concat(options[:label]) if options[:label].present?
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
#
|
306
|
+
# Demote a publishable kb object in a pull down list
|
307
|
+
#
|
308
|
+
def demote_list_tag(obj, path, options = {})
|
309
|
+
return unless can? :demote, obj
|
310
|
+
|
311
|
+
options[:label] ||= I18n.t('links.demote')
|
312
|
+
content_tag(:li) do
|
313
|
+
demote_link_tag(obj, path, options)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
#
|
318
|
+
# Demote a publishable kb object
|
319
|
+
#
|
320
|
+
def demote_link_tag(obj, path, options = {})
|
321
|
+
return unless can? :demote, obj
|
322
|
+
|
323
|
+
content_tag(:a, href: path) do
|
324
|
+
concat(content_tag(:i, class: 'material-icons') do
|
325
|
+
'file_download'
|
326
|
+
end)
|
327
|
+
concat(options[:label]) if options[:label].present?
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
201
331
|
#
|
202
332
|
# Edit a page
|
203
333
|
#
|
@@ -214,36 +344,58 @@ module CoreLinkHelper
|
|
214
344
|
#
|
215
345
|
# Add a thingy
|
216
346
|
#
|
217
|
-
def add_link_tag(klass, path)
|
218
|
-
return unless can?(:
|
347
|
+
def add_link_tag(klass, path, options = {})
|
348
|
+
return unless can?(:create, klass)
|
219
349
|
|
220
350
|
content_tag(:div, class: 'fixed-action-btn horizontal') do
|
221
|
-
concat(
|
222
|
-
|
223
|
-
|
351
|
+
concat(add_link_button(path, options))
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
#
|
356
|
+
# Add the `Add` button
|
357
|
+
#
|
358
|
+
def add_link_button(path, options)
|
359
|
+
options[:title] ||= t('ui_form.actions.add')
|
360
|
+
options[:icon] ||= 'add'
|
361
|
+
content_tag(:a,
|
362
|
+
href: path,
|
363
|
+
class: 'btn-floating btn-large right',
|
364
|
+
style: 'padding: 0;margin: 0px 15px',
|
365
|
+
title: options[:title]) do
|
366
|
+
concat(content_tag(:i, class: 'material-icons') { options[:icon] })
|
224
367
|
end
|
225
368
|
end
|
226
369
|
|
227
370
|
#
|
228
371
|
# Form cancel button
|
229
372
|
#
|
230
|
-
def form_cancel_button_tag(path)
|
373
|
+
def form_cancel_button_tag(path, name = 'cancel')
|
231
374
|
options = { class: 'btn-large waves-effect waves-light secondary', href: path }
|
232
375
|
content_tag(:a, options) do
|
233
|
-
concat(t(
|
376
|
+
concat(t("ui_form.actions.#{name}"))
|
234
377
|
end
|
235
378
|
end
|
236
379
|
|
237
380
|
#
|
238
381
|
# Form submit button
|
239
382
|
#
|
240
|
-
def form_submit_button_tag(
|
241
|
-
return unless
|
383
|
+
def form_submit_button_tag(condition = true, options = {})
|
384
|
+
return unless condition
|
242
385
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
386
|
+
tag_options = { class: 'btn-large waves-effect waves-light', type: :submit }
|
387
|
+
if options[:action].present?
|
388
|
+
tag_options[:name] = options[:name] || 'button_action'
|
389
|
+
tag_options[:value] = options[:action]
|
390
|
+
end
|
391
|
+
tag_options[:class] += ' disabled' if options[:disabled]
|
392
|
+
tag_options[:class] += ' disabled' if options[:disabled]
|
393
|
+
|
394
|
+
button_text = options[:text] || t('ui_form.actions.save')
|
395
|
+
button_icon = options[:icon] || 'save'
|
396
|
+
content_tag(:button, tag_options) do
|
397
|
+
concat(button_text)
|
398
|
+
concat(content_tag(:i, class: 'material-icons right') { button_icon })
|
247
399
|
end
|
248
400
|
end
|
249
401
|
end
|
@@ -160,7 +160,7 @@ module ModelModalHelper
|
|
160
160
|
end
|
161
161
|
|
162
162
|
def model_modal_standard(model, _options = {})
|
163
|
-
content_tag(:table, class: 'center-align
|
163
|
+
content_tag(:table, class: 'center-align highlight') do
|
164
164
|
concat(content_tag(:tbody) do
|
165
165
|
%w[_id _type created_at updated_at search_text sort_text].each do |field_name|
|
166
166
|
concat(model_modal_field(model, field_name))
|
@@ -34,7 +34,7 @@
|
|
34
34
|
.container
|
35
35
|
.row
|
36
36
|
.col.s12
|
37
|
-
%table.
|
37
|
+
%table.highlight.bordered.extended{data: {sort: {column: 'Run At,Priority', direction: 'desc,asc'}}}
|
38
38
|
%thead
|
39
39
|
%tr
|
40
40
|
%th=t('.run_at')
|
data/lib/app/jobs/cron/job.rb
CHANGED
@@ -27,5 +27,16 @@ module Cron
|
|
27
27
|
email.from_template('support_ticket_notification', params)
|
28
28
|
email.send_notification
|
29
29
|
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Sends support a notification if something goes awry
|
33
|
+
#
|
34
|
+
def notify_job_failure(error, event)
|
35
|
+
message = { job_name: self.class.to_s.titleize,
|
36
|
+
event: event,
|
37
|
+
error_message: error.message,
|
38
|
+
stack_trace: error.backtrace }
|
39
|
+
SlackNotification.say message, to: SystemConfiguration.slack_support_channel, template: :job_failure
|
40
|
+
end
|
30
41
|
end
|
31
42
|
end
|
@@ -16,7 +16,7 @@ module SearchAble
|
|
16
16
|
#
|
17
17
|
# Call backs
|
18
18
|
#
|
19
|
-
|
19
|
+
before_save :update_search_and_sort_text
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -31,7 +31,7 @@ module SearchAble
|
|
31
31
|
#
|
32
32
|
module ClassMethods
|
33
33
|
def matching_search_text(search_text = nil)
|
34
|
-
(search_text.blank? ? all : where(search_text: /#{search_text.downcase}/)).order(
|
34
|
+
(search_text.blank? ? all : where(search_text: /#{search_text.downcase}/)).order([:sort_text, 1])
|
35
35
|
end
|
36
36
|
|
37
37
|
def sort_order
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# A mixin for models with secure fields.
|
5
|
+
# Basically if the secure field is blank, nil or "", then delete it from the update.
|
6
|
+
#
|
7
|
+
module SecureFields
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
#
|
10
|
+
# Remove updates for secure fields
|
11
|
+
#
|
12
|
+
def update(params)
|
13
|
+
secure_fields.each { |field| params.delete(field) if params[field].blank? }
|
14
|
+
super(params)
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# List of secure fields
|
19
|
+
#
|
20
|
+
def secure_fields
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
end
|
@@ -22,8 +22,8 @@ module StandardModel
|
|
22
22
|
#
|
23
23
|
# Relationships
|
24
24
|
#
|
25
|
-
belongs_to :last_modified_by, polymorphic: true,
|
26
|
-
belongs_to :created_by, polymorphic: true,
|
25
|
+
belongs_to :last_modified_by, polymorphic: true, optional: true
|
26
|
+
belongs_to :created_by, polymorphic: true, optional: true
|
27
27
|
has_many Web47core::Config.audit_model_log_symbol, dependent: :nullify, inverse_of: :model
|
28
28
|
#
|
29
29
|
# Callbacks
|
@@ -57,14 +57,41 @@ module StandardModel
|
|
57
57
|
#
|
58
58
|
# Return the complete list of key names that would appear in the form.
|
59
59
|
#
|
60
|
-
def allowed_param_names(filter_names = [])
|
60
|
+
def allowed_param_names(filter_names = [], include_relationships = true)
|
61
61
|
# Always filter out the mongoid reserved items
|
62
|
-
filter_names += %w[created_at updated_at _type _id]
|
63
|
-
|
62
|
+
filter_names += %w[created_at updated_at _type _id search_text sort_text]
|
63
|
+
associations = many_to_many_associations
|
64
|
+
# filter out the relationship names so we don't have dups
|
65
|
+
associations.each { |association| filter_names << association.keys.first }
|
66
|
+
names = field_names(filter_names)
|
67
|
+
names += associations if include_relationships
|
68
|
+
names.delete_if { |name| filter_names.include?(name) }
|
64
69
|
rescue StandardError
|
65
70
|
attribute_names.delete_if { |name| filter_names.include?(name) }
|
66
71
|
end
|
67
72
|
|
73
|
+
#
|
74
|
+
# Return a collection of many to many associations. We basically
|
75
|
+
# need to turn the current value returned by attribute names
|
76
|
+
#
|
77
|
+
# relationship_ids
|
78
|
+
#
|
79
|
+
# to
|
80
|
+
#
|
81
|
+
# { relationship_ids => [] }
|
82
|
+
#
|
83
|
+
# Telling the permit command to accept the value as an array of items.
|
84
|
+
#
|
85
|
+
def many_to_many_associations
|
86
|
+
associations = []
|
87
|
+
reflect_on_all_associations.each do |association|
|
88
|
+
next unless association.macro == :has_and_belongs_to_many
|
89
|
+
|
90
|
+
associations << { association.key => [] }
|
91
|
+
end
|
92
|
+
associations
|
93
|
+
end
|
94
|
+
|
68
95
|
#
|
69
96
|
# allow the model to filter out a name if they want to, meaning the model
|
70
97
|
# can return a subset of attribute names
|
@@ -89,8 +116,12 @@ module StandardModel
|
|
89
116
|
#
|
90
117
|
def find_or_create_by_and_log!(user, attributes)
|
91
118
|
model = find_or_initialize_by(attributes)
|
92
|
-
|
93
|
-
|
119
|
+
if model.new_record?
|
120
|
+
model.last_modified_by = user
|
121
|
+
model.created_by = user
|
122
|
+
model.save!
|
123
|
+
log_change(user, model, attributes)
|
124
|
+
end
|
94
125
|
model
|
95
126
|
end
|
96
127
|
|
@@ -98,7 +129,7 @@ module StandardModel
|
|
98
129
|
# Record the creation with this user
|
99
130
|
#
|
100
131
|
def create_and_log(user, attributes)
|
101
|
-
model =
|
132
|
+
model = new(attributes)
|
102
133
|
model.last_modified_by = user
|
103
134
|
model.created_by = user
|
104
135
|
model.save
|
@@ -110,7 +141,7 @@ module StandardModel
|
|
110
141
|
# Record the creation with this user
|
111
142
|
#
|
112
143
|
def create_and_log!(user, attributes)
|
113
|
-
model =
|
144
|
+
model = new(attributes)
|
114
145
|
model.last_modified_by = user
|
115
146
|
model.created_by = user
|
116
147
|
model.save!
|
@@ -169,13 +200,13 @@ module StandardModel
|
|
169
200
|
Rails.cache.delete_matched "*#{account.id}*"
|
170
201
|
true # Force a return of true so that we don't break the callback chain.
|
171
202
|
rescue StandardError
|
172
|
-
|
203
|
+
true
|
173
204
|
end
|
174
205
|
|
175
206
|
#
|
176
207
|
# record a change for the object instance
|
177
208
|
#
|
178
|
-
def log_change(user, changes, action)
|
209
|
+
def log_change(user, changes, action = nil)
|
179
210
|
Web47core::Config.audit_model_log_class.create!(Web47core::Config.audit_model => user,
|
180
211
|
model: self,
|
181
212
|
action: action,
|
@@ -190,7 +221,7 @@ module StandardModel
|
|
190
221
|
# Safely get the display name of who last modified this object
|
191
222
|
#
|
192
223
|
def last_modified_by_display_name
|
193
|
-
last_modified_by.
|
224
|
+
last_modified_by.display_name
|
194
225
|
rescue StandardError
|
195
226
|
"#{last_modified_by_name} (#{last_modified_by_email}) - deleted"
|
196
227
|
end
|
@@ -199,7 +230,7 @@ module StandardModel
|
|
199
230
|
# Safely get the display name of who created this object
|
200
231
|
#
|
201
232
|
def created_by_display_name
|
202
|
-
created_by.
|
233
|
+
created_by.display_name
|
203
234
|
rescue StandardError
|
204
235
|
"#{created_by_name} (#{created_by_email}) - deleted"
|
205
236
|
end
|
@@ -27,6 +27,16 @@ module TimeZoneAble
|
|
27
27
|
TZInfo::Timezone.all_identifiers
|
28
28
|
end
|
29
29
|
|
30
|
+
#
|
31
|
+
# Return the given time in the localized time for this object
|
32
|
+
#
|
33
|
+
def local_date(date, format = :medium, default = 'N/A')
|
34
|
+
tz = TZInfo::Timezone.get(time_zone || 'GMT')
|
35
|
+
date.present? ? I18n.l(date.in_time_zone(tz).to_date, format: format) : default
|
36
|
+
rescue StandardError
|
37
|
+
default
|
38
|
+
end
|
39
|
+
|
30
40
|
#
|
31
41
|
# Return the given time in the localized time for this object
|
32
42
|
#
|
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: 1.0.0
|
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-
|
11
|
+
date: 2020-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -636,6 +636,7 @@ files:
|
|
636
636
|
- lib/app/models/concerns/email_able.rb
|
637
637
|
- lib/app/models/concerns/role_able.rb
|
638
638
|
- lib/app/models/concerns/search_able.rb
|
639
|
+
- lib/app/models/concerns/seucre_fields.rb
|
639
640
|
- lib/app/models/concerns/standard_model.rb
|
640
641
|
- lib/app/models/concerns/switchboard_able.rb
|
641
642
|
- lib/app/models/concerns/time_zone_able.rb
|