web47core 0.9.0 → 1.0.0
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 +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
|