web47core 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -14
  3. data/Gemfile.lock +30 -9
  4. data/README.md +27 -4
  5. data/lib/app/models/concerns/app47_logger.rb +175 -0
  6. data/lib/app/models/concerns/core_account.rb +51 -0
  7. data/lib/app/models/concerns/standard_model.rb +104 -6
  8. data/lib/app/models/email_notification.rb +253 -0
  9. data/lib/app/models/email_template.rb +6 -0
  10. data/lib/app/models/notification.rb +276 -0
  11. data/lib/app/models/notification_template.rb +20 -0
  12. data/lib/app/models/slack_notification.rb +89 -0
  13. data/lib/app/models/sms_notification.rb +56 -0
  14. data/lib/app/models/smtp_configuration.rb +148 -0
  15. data/lib/app/models/template.rb +21 -0
  16. data/lib/templates/email/notification_failure.liquid +10 -0
  17. data/lib/templates/email/notification_failure.subject.liquid +1 -0
  18. data/lib/templates/slack/error_message.liquid +1 -0
  19. data/lib/web47core.rb +10 -2
  20. data/test/factories/account_factories.rb +9 -0
  21. data/test/factories/notification_factories.rb +14 -0
  22. data/test/models/app47_logger_test.rb +88 -0
  23. data/test/models/concerns/{formable_test.rb → standard_model_test.rb} +24 -5
  24. data/test/models/email_notification_test.rb +297 -0
  25. data/test/models/notification_test.rb +127 -0
  26. data/test/models/slack_notification_test.rb +50 -0
  27. data/test/notification_test_helper.rb +146 -0
  28. data/test/rails_setup.rb +4 -0
  29. data/test/test_helper.rb +10 -4
  30. data/test/test_models_helper.rb +14 -0
  31. data/web47core.gemspec +5 -2
  32. metadata +87 -14
  33. data/lib/app/models/concerns/auto_clear_cache.rb +0 -34
  34. data/lib/app/models/concerns/formable.rb +0 -111
  35. data/test/models/concerns/auto_clear_cache_test.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e82f9597abea49e585537bf7b37dd78220136b34e2f2bc0ade5592e4d70ae9d
4
- data.tar.gz: 523f737ac0beae20e3203ba4188c66e4cf5c09b8749084bf67dfd07fb039a3e7
3
+ metadata.gz: 623ae80309063bdc6c27dee1668a86ae4473da7db27a6ffedb9bd75df3b83d40
4
+ data.tar.gz: e39e28438fb5247ddb2cc65c9dd3b5c8edb8a98d9079921b3dc07d511b587ecb
5
5
  SHA512:
6
- metadata.gz: e4a973a0840c34dc033b5f512e9e5bb62618afa44f20fc5b9e6993a59ef0cbde59befc204becd175dd15db7f02f4952f516af9d77dfb9cbb8fd70fd17991fc32
7
- data.tar.gz: 6b2dff4fb23a286a60a0cccc2cd618d17b38379148aad5d385463df8a81ce55542ec9cde451516a52c6dfaf68204f585682849d546c6989800c4006fac95c091
6
+ metadata.gz: db0cd4d93d34398cf6e3a4739016db9fd63337e048917403ea9ec624ee5f516ecdb8a9ac278925f8f329dde34c3a42af16b856530ae976c5cc9534eca0999143
7
+ data.tar.gz: b5304422a552e6ec81a9e188000533a8a4652e66d3e6e8096b81abaf45d5e4646cc5ed5b7591265c5639f56225e977ba26cb68351eda9e1c20743d70b81b3580
data/Gemfile CHANGED
@@ -1,19 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
  ruby '2.4.1'
3
3
 
4
- git_source(:github) do |repo_name|
5
- repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/')
6
- "https://github.com/#{repo_name}.git"
7
- end
8
-
9
4
  # Specify your gem's dependencies
10
5
  gemspec
11
-
12
- gem 'aws-sdk-ec2'
13
- gem 'jwt'
14
- gem 'mongoid', '~> 6.4'
15
-
16
- group :test do
17
- gem 'simplecov'
18
- gem 'simplecov-lcov'
19
- end
data/Gemfile.lock CHANGED
@@ -1,15 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- web47core (0.0.8)
4
+ web47core (0.0.9)
5
5
  activesupport (~> 5.0)
6
- aws-sdk-ec2 (>= 1.60, <= 1.151)
6
+ aws-sdk-ec2 (> 1.140, <= 1.160)
7
7
  delayed_job_mongoid (~> 2.3)
8
+ haml
8
9
  jwt
10
+ liquid
9
11
  mongoid (> 6, < 7)
10
12
  rails (>= 4.2, < 5.3)
11
13
  redis (~> 4.1)
12
14
  redis-rails (> 5, < 6)
15
+ rest-client (>= 0, <= 2.1.0)
13
16
 
14
17
  GEM
15
18
  remote: https://rubygems.org/
@@ -60,7 +63,7 @@ GEM
60
63
  ansi (1.5.0)
61
64
  arel (9.0.0)
62
65
  aws-eventstream (1.0.3)
63
- aws-partitions (1.286.0)
66
+ aws-partitions (1.288.0)
64
67
  aws-sdk-core (3.92.0)
65
68
  aws-eventstream (~> 1.0, >= 1.0.2)
66
69
  aws-partitions (~> 1, >= 1.239.0)
@@ -94,6 +97,8 @@ GEM
94
97
  mongoid (>= 3.0, < 8)
95
98
  mongoid-compatibility (>= 0.4.0)
96
99
  docile (1.3.2)
100
+ domain_name (0.5.20190701)
101
+ unf (>= 0.0.5, < 1.0.0)
97
102
  erubi (1.9.0)
98
103
  factory_bot (5.1.1)
99
104
  activesupport (>= 4.2.0)
@@ -103,12 +108,19 @@ GEM
103
108
  ffi (1.12.2)
104
109
  globalid (0.4.2)
105
110
  activesupport (>= 4.2.0)
111
+ haml (5.1.2)
112
+ temple (>= 0.8.0)
113
+ tilt
106
114
  hashdiff (1.0.1)
115
+ http-accept (1.7.0)
116
+ http-cookie (1.0.3)
117
+ domain_name (~> 0.5)
107
118
  i18n (1.8.2)
108
119
  concurrent-ruby (~> 1.0)
109
120
  jmespath (1.4.0)
110
121
  json (2.3.0)
111
122
  jwt (2.2.1)
123
+ liquid (4.0.3)
112
124
  listen (3.2.1)
113
125
  rb-fsevent (~> 0.10, >= 0.10.3)
114
126
  rb-inotify (~> 0.9, >= 0.9.10)
@@ -120,6 +132,9 @@ GEM
120
132
  marcel (0.3.3)
121
133
  mimemagic (~> 0.3.2)
122
134
  method_source (1.0.0)
135
+ mime-types (3.3.1)
136
+ mime-types-data (~> 3.2015)
137
+ mime-types-data (3.2019.1009)
123
138
  mimemagic (0.3.4)
124
139
  mini_mime (1.0.2)
125
140
  mini_portile2 (2.4.0)
@@ -152,6 +167,7 @@ GEM
152
167
  mongoid-compatibility (0.5.1)
153
168
  activesupport
154
169
  mongoid (>= 2.0)
170
+ netrc (0.11.0)
155
171
  nio4r (2.5.2)
156
172
  nokogiri (1.10.9)
157
173
  mini_portile2 (~> 2.4.0)
@@ -205,6 +221,11 @@ GEM
205
221
  redis-store (>= 1.2, < 2)
206
222
  redis-store (1.8.2)
207
223
  redis (>= 4, < 5)
224
+ rest-client (2.1.0)
225
+ http-accept (>= 1.7.0, < 2.0)
226
+ http-cookie (>= 1.0.2, < 2.0)
227
+ mime-types (>= 1.16, < 4.0)
228
+ netrc (~> 0.8)
208
229
  ruby-progressbar (1.10.1)
209
230
  safe_yaml (1.0.5)
210
231
  shoulda (3.6.0)
@@ -218,7 +239,6 @@ GEM
218
239
  json (>= 1.8, < 3)
219
240
  simplecov-html (~> 0.10.0)
220
241
  simplecov-html (0.10.2)
221
- simplecov-lcov (0.8.0)
222
242
  sprockets (3.7.2)
223
243
  concurrent-ruby (~> 1.0)
224
244
  rack (> 1, < 3)
@@ -226,12 +246,17 @@ GEM
226
246
  actionpack (>= 4.0)
227
247
  activesupport (>= 4.0)
228
248
  sprockets (>= 3.0.0)
249
+ temple (0.8.2)
229
250
  test-unit (3.3.5)
230
251
  power_assert
231
252
  thor (1.0.1)
232
253
  thread_safe (0.3.6)
254
+ tilt (2.0.10)
233
255
  tzinfo (1.2.6)
234
256
  thread_safe (~> 0.1)
257
+ unf (0.1.4)
258
+ unf_ext
259
+ unf_ext (0.0.7.6)
235
260
  vcr (5.1.0)
236
261
  webmock (3.8.3)
237
262
  addressable (>= 2.3.6)
@@ -247,24 +272,20 @@ PLATFORMS
247
272
  ruby
248
273
 
249
274
  DEPENDENCIES
250
- aws-sdk-ec2
251
275
  bundler
252
276
  codacy-coverage (~> 2.1.0)
253
277
  database_cleaner
254
278
  factory_bot
255
279
  factory_bot_rails
256
- jwt
257
280
  listen
258
281
  minitest (= 5.10.3)
259
282
  minitest-rails (= 3.0.0)
260
283
  minitest-rails-capybara (= 3.0.1)
261
284
  minitest-reporters
262
285
  mocha
263
- mongoid (~> 6.4)
264
286
  shoulda (= 3.6.0)
265
287
  shoulda-matchers (= 3.1.2)
266
- simplecov
267
- simplecov-lcov
288
+ simplecov (= 0.16.1)
268
289
  test-unit
269
290
  vcr
270
291
  web47core!
data/README.md CHANGED
@@ -61,13 +61,24 @@ gem 'web47core', git: 'git@github.com:App47/web47core.git', branch: :develop
61
61
 
62
62
  _Please do not ship to production code using the git repo, as the production servers will not have keys to pull from the web47core repo_
63
63
 
64
- ## Features
65
-
66
- ### Models
67
- #### Concerns
64
+ ## Remove the following files
68
65
  1. `StandardModel` - Includes the common set of includes, Mongoid, Auditable, AutoClearCache, etc.
69
66
  1. `CdnUrl` - Provide CDN URLs of your classes URLs when cdn_url is configured in system configuration
70
67
  1. `AutoClearCache` - Clears your objects cache out of Rails.cache using the object's id
68
+ 1. `Formable` - Consolidated into StandardModel, was used to provide common form operations for mongoid documents
69
+ 1. `EmailNotification`
70
+ 1. `EmailTemplate`
71
+ 1. `Notification`
72
+ 1. `NotificationTemplate`
73
+ 1. `SlackNotification`
74
+ 1. `SmsNotification`
75
+ 1. `Template`
76
+
77
+ ### Models
78
+ #### Concerns
79
+ 1. `StandardModel` - Includes the common set of includes, Mongoid, etc.
80
+ 1. `CoreSystemConfiguration` - Base system configuration to be included in the app's SystemConfiguration Object
81
+ 1. `CoreAccount` - Base account object that is related to notifications and the ilk.
71
82
  #### System Configuration
72
83
  Define a `SystemConfiguration` class in your project and import the core concern.
73
84
 
@@ -80,4 +91,16 @@ class SystemConfiguration
80
91
  field :google_sso_client_id, type: String
81
92
  end
82
93
  ```
94
+ #### Account
95
+ Define a `Account` class in your project and import the core concern.
96
+
97
+ ```
98
+ class Account
99
+ include StandardModel
100
+ include CoreAccount
101
+
102
+ # Include your additional system configuration fields and methods
103
+ has_many :users
104
+ end
105
+ ```
83
106
 
@@ -0,0 +1,175 @@
1
+ #
2
+ # Mixin for App47 objects to handle logging in both the rails environment as well
3
+ # as the delayed jobs environment that doesn't know about Rails.logger
4
+ #
5
+ # Provides ways to log at the class level as well as instance level.
6
+ #
7
+ #
8
+ # Usage:
9
+ # App47Logger.log_debug('message')
10
+ #
11
+ # or
12
+ #
13
+ # class ClassName
14
+ # include App47Logger
15
+ #
16
+ # def method_name
17
+ # log_debug('message')
18
+ # end
19
+ #
20
+ module App47Logger
21
+ #
22
+ # Log a debug messages
23
+ #
24
+ def self.log_debug(message)
25
+ log_message :debug, message
26
+ end
27
+
28
+ #
29
+ # Log a warning messages
30
+ #
31
+ # 1. Prints the messages
32
+ # 2. If an exception is passed n
33
+ # 2a prints the exception message
34
+ # 2b prints the stack trace
35
+ #
36
+ def self.log_warn(message, exception = nil)
37
+ log_message :warn, message
38
+ log_exception :warn, exception
39
+ end
40
+
41
+ #
42
+ # Log an error messages
43
+ #
44
+ # 1. Prints the messages
45
+ # 2. If an exception is passed n
46
+ # 2a prints the exception message
47
+ # 2b prints the stack trace
48
+ #
49
+ def self.log_error(message, exception = nil)
50
+ log_message :error, message
51
+ log_exception(:error, exception)
52
+ message = { message: message, exception: exception&.message }
53
+ SlackNotification.say message, template: :error_message
54
+ end
55
+
56
+ #
57
+ # Log a given exception, but only the first 10 lines in anything but test.
58
+ #
59
+ # In testing, we want the full stack to know the test case that failed.
60
+ #
61
+ def self.log_exception(level, exception = nil, max_frame = 9)
62
+ return if exception.blank?
63
+
64
+ max_frame = -1 if ENV['RACK_ENV'].eql?('test')
65
+ log_message(level, exception.message)
66
+ exception.backtrace[0..max_frame].each { |frame| log_message(level, frame) } unless exception.backtrace.blank?
67
+ end
68
+
69
+ #
70
+ # Log a given message at the given level
71
+ #
72
+ def self.log_message(level, message)
73
+ if Rails.env.test?
74
+ puts "#{level}: #{message}"
75
+ elsif Delayed::Worker.logger.nil?
76
+ Rails.logger.send level, message
77
+ else
78
+ Delayed::Worker.logger.send level, message
79
+ end
80
+ end
81
+
82
+ #
83
+ # Log a debug message as part of the mixin
84
+ #
85
+ def log_message(level, message)
86
+ App47Logger.log_message level, message
87
+ end
88
+
89
+ #
90
+ # Log a debug message as part of the mixin
91
+ #
92
+ def log_debug(message)
93
+ App47Logger.log_debug message
94
+ end
95
+
96
+ #
97
+ # Log a warning message as part of the mixin
98
+ #
99
+ def log_warn(message, exception = nil)
100
+ App47Logger.log_warn message, exception
101
+ end
102
+
103
+ #
104
+ # Log an error message as part of the mixin
105
+ #
106
+ def log_error(message, exception = nil)
107
+ App47Logger.log_error message, exception
108
+ end
109
+
110
+ #
111
+ # Log a controller error message
112
+ #
113
+ def log_controller_error(exception, redirecting = false)
114
+ if exception.is_a? ActionController::RoutingError
115
+ App47Logger.log_warn "#{controller_name}##{action_name} #{clean_params(params)}", exception
116
+ else
117
+ App47Logger.log_error "#{controller_name}##{action_name} #{clean_params(params)}", exception
118
+ end
119
+ update_flash_messages(exception, redirecting) if defined?(request) && request.present?
120
+ end
121
+
122
+ #
123
+ # Update the flash message based on the type of exception we get
124
+ # Currently we only handle mongoid errors, but there may be other
125
+ # common errors we can handle formatting for...
126
+ #
127
+ def update_flash_messages(exception, redirecting = false)
128
+ case exception
129
+ when Mongoid::Errors::Validations
130
+ if redirecting
131
+ flash[:error] = exception.problem
132
+ flash[:warning] = exception.summary
133
+ else
134
+ flash.now[:error] = exception.problem
135
+ flash.now[:warning] = exception.summary
136
+ end
137
+ else
138
+ if redirecting
139
+ flash[:error] = exception.message
140
+ else
141
+ flash.now[:error] = exception.message
142
+ end
143
+ end
144
+ end
145
+
146
+ #
147
+ # Recursively hide any fields in the rails config filter_parameters
148
+ #
149
+ def clean_params(pars)
150
+ pars.each do |key, value|
151
+ if mask_parameter_keys.include?(key)
152
+ pars[key] = '[FILTERED]'
153
+ elsif delete_parameter_keys.include?(key)
154
+ pars.delete(key)
155
+ elsif value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
156
+ pars[key] = clean_params(value)
157
+ end
158
+ end
159
+ pars
160
+ end
161
+
162
+ #
163
+ # which parameters to filter out
164
+ #
165
+ def mask_parameter_keys
166
+ @mask_parameter_keys ||= Rails.application.config.filter_parameters
167
+ end
168
+
169
+ #
170
+ # which parameters to filter out
171
+ #
172
+ def delete_parameter_keys
173
+ @delete_parameter_keys ||= %w[file authenticity_token commit upload]
174
+ end
175
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # The System configuration. Various configuration items that can be updated/defined at run time
5
+ #
6
+ # Use of this class allows you to simply ask for the configuration parameter directly without
7
+ # first having to get an instance of it.
8
+ #
9
+ # SystemConfiguration.queue_impl #=> 'RedisQueue'
10
+ #
11
+ # This method only is allowed for accessors, you should NEVER set values on the SystemConfiguration
12
+ # unless you are updating via the Admin or Stack UI, or during testing to setup a specific configuration
13
+ # for that.
14
+ #
15
+ module CoreAccount
16
+ extend ActiveSupport::Concern
17
+
18
+ def self.included(base)
19
+ base.class_eval do
20
+ #
21
+ # Fields
22
+ #
23
+ field :name, type: String
24
+ #
25
+ # Relationships
26
+ #
27
+ has_many :notifications, dependent: :delete do
28
+ def emails
29
+ where(_type: 'EmailNotification')
30
+ end
31
+
32
+ def slacks
33
+ where(_type: 'SlackNotification')
34
+ end
35
+
36
+ def sms
37
+ where(_type: 'SmsNotification')
38
+ end
39
+ end
40
+ has_many :templates, dependent: :delete
41
+ embeds_one :smtp_configuration
42
+ end
43
+ end
44
+
45
+ #
46
+ # Return or build the smtp configuration for the account
47
+ #
48
+ def fetch_smtp_configuration
49
+ smtp_configuration || build_smtp_configuration
50
+ end
51
+ end
@@ -6,15 +6,18 @@
6
6
  #
7
7
  module StandardModel
8
8
  extend ActiveSupport::Concern
9
+ include Mongoid::Document
10
+ include Mongoid::Timestamps
11
+ include App47Logger
12
+ # include Auditable
9
13
 
10
14
  def self.included(base)
11
15
  base.class_eval do
12
- include Mongoid::Document
13
- include Mongoid::Timestamps
14
- # include App47Logger
15
- # include Auditable
16
- include Formable
17
- include AutoClearCache
16
+ #
17
+ # Callbacks
18
+ #
19
+ after_save :clear_cache
20
+ before_destroy :clear_cache
18
21
  end
19
22
  end
20
23
 
@@ -37,5 +40,100 @@ module StandardModel
37
40
  def make_options(options)
38
41
  options.collect { |t| [t, t.humanize] }
39
42
  end
43
+
44
+ #
45
+ # Return the complete list of key names that would appear in the form.
46
+ #
47
+ def allowed_param_names(filter_names = [])
48
+ # Always filter out the mongoid reserved items
49
+ filter_names += %w[created_at updated_at _type _id]
50
+ associations = all_associations
51
+ # filter out the relationship names so we don't have dups
52
+ associations.each { |association| filter_names << association.keys.first }
53
+ (field_names + associations).delete_if { |name| filter_names.include?(name) }
54
+ rescue StandardError
55
+ attribute_names.delete_if { |name| filter_names.include?(name) }
56
+ end
57
+
58
+ #
59
+ # allow the model to filter out a name if they want to, meaning the model
60
+ # can return a subset of attribute names
61
+ #
62
+ def field_names
63
+ attribute_names
64
+ end
65
+
66
+ #
67
+ # gather up the collections we care about and return them. For now, the
68
+ # many to many associations are the ones that need some extra help.
69
+ #
70
+ def all_associations
71
+ many_to_many_associations
72
+ end
73
+
74
+ #
75
+ # Return a collection of many to many assocations. We basically
76
+ # need to turn the current value returned by attribute names
77
+ #
78
+ # relationship_ids
79
+ #
80
+ # to
81
+ #
82
+ # { relationship_ids => [] }
83
+ #
84
+ # Telling the permit command to accept the value as an array of items.
85
+ #
86
+ def many_to_many_associations
87
+ associations = []
88
+ reflect_on_all_associations.each do |association|
89
+ next unless association.macro == :has_and_belongs_to_many
90
+
91
+ associations << { association.key => [] }
92
+ end
93
+ associations
94
+ end
95
+ end
96
+
97
+ #
98
+ # Remove updates for secure fields that come across as blank to start with and get removed on update
99
+ #
100
+ def update(params)
101
+ super(remove_blank_secure_fields(params))
102
+ end
103
+
104
+ alias :update_attributes :update
105
+
106
+ #
107
+ # Remove updates for secure fields that come across as blank to start with and get removed on update
108
+ #
109
+ def update!(params)
110
+ super(remove_blank_secure_fields(params))
111
+ end
112
+
113
+ alias :update_attributes! :update!
114
+
115
+ #
116
+ # List of secure fields, to add fields in concrete class, simply override this method
117
+ #
118
+ def secure_fields
119
+ []
120
+ end
121
+
122
+ def remove_blank_secure_fields(params)
123
+ secure_fields.each { |field| params.delete(field) if params[field].blank? }
124
+ params
125
+ end
126
+
127
+ #
128
+ # Clear the cache
129
+ #
130
+ def clear_cache
131
+ Rails.cache.delete_matched "*#{id}*"
132
+ return unless respond_to?(:account) && account.present? && account.is_a?(Account)
133
+
134
+ Rails.cache.delete_matched "*#{account.id}*"
135
+ true # Force a return of true so that we don't break the callback chain.
136
+ rescue StandardError
137
+ false
40
138
  end
41
139
  end