effective_resources 2.23.0 → 2.25.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5203021d6f8cd741603bcf0459f4277f6227c56fde16fd21fb99cae45564667
4
- data.tar.gz: 505149510d60183e7b0935a043f6be30d96dbb79099225a89c6fdc136ad1100d
3
+ metadata.gz: 3a0aa5a3bcbd09397c6cd7815465cdfe0882045fba170ced84f6dbf59732db87
4
+ data.tar.gz: 0f78f2cce168bbda0d6221d6f8ea41b143c080d97b52ad78c7193c659d1aafa7
5
5
  SHA512:
6
- metadata.gz: 5efcc14c75d711551ae84574fd1bb64970273a170c7135a645af656b55be45ea8b71520827950933b13d636a32c51c5b0a4a58326666bbcf8722394ae086b6ad
7
- data.tar.gz: ca89163745a47fe5be4342149df505800565cf6afc6991a9d765de4099d8b2efe17f570f27026eadaa5f7c6629edcd6d7f25c4f0ba5e6a13ea6b840f52c49f15
6
+ metadata.gz: 035ca01e53c2d094b2174048e9a1f27f01b64e9cf12539587ac94350402b4569562e3be33322eb44f23182a88d5eb2fa68df4d8ff491ad0b6cbc95f2d2da3c09
7
+ data.tar.gz: 1df2b4a3f3ba19cd4e3d2b1875cd1d58627f3ab181bdb8cf0ebf268fcec8ea8e161754ec7a1f91618dbecb71e6d8c94ee7f5163aa833444a1e616c8c066712cf
@@ -28,6 +28,10 @@ module Effective
28
28
  params[resource_name].to_unsafe_h
29
29
  end
30
30
 
31
+ to_assign ||= if params[effective_resource_name].present? && params[effective_resource_name].respond_to?(:to_unsafe_h)
32
+ params[effective_resource_name].to_unsafe_h
33
+ end
34
+
31
35
  to_assign ||= if params.present?
32
36
  params.to_unsafe_h.except(:controller, :action, :id, :duplicate_id)
33
37
  end
@@ -103,6 +103,10 @@ module Effective
103
103
  effective_resource.name
104
104
  end
105
105
 
106
+ def effective_resource_name # effective_notification
107
+ effective_resource.resource_name
108
+ end
109
+
106
110
  def resource_name_id
107
111
  (effective_resource.name + '_id').to_sym
108
112
  end
@@ -69,7 +69,7 @@ module Effective
69
69
 
70
70
  def build_wizard_resource
71
71
  resource = resource_scope.new
72
- resource.strict_loading!(false) if resource.respond_to?(:strict_loading!)
72
+ (resource.strict_loading!(false) rescue false) if resource.respond_to?(:strict_loading!)
73
73
  resource
74
74
  end
75
75
 
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EffectiveResourcesEmailHelper
4
+ def mailer_froms_collection(froms: nil)
5
+ froms ||= EffectiveResources.mailer_froms
6
+
7
+ froms.map do |from|
8
+ html = content_tag(:span, escape_once(from))
9
+ [from, from, 'data-html': html]
10
+ end
11
+ end
12
+
13
+ # acts_as_email_form
14
+ def email_form_fields(form, action = nil, skip: true, to: nil, variables: nil, partial: nil)
15
+ raise('expected a form') unless form.respond_to?(:object)
16
+
17
+ resource = form.object
18
+
19
+ # Intended for acts_as_email_form but sometimes we use a duck typed object to save these fields as well
20
+ unless resource.class.respond_to?(:acts_as_email_form?) || resource.respond_to?("email_form_action=")
21
+ raise('expected an acts_as_email_form resource or one that responds to email_form_action')
22
+ end
23
+
24
+ # Load the template.
25
+ email_template = if action.present? && defined?(EffectiveEmailTemplates)
26
+ action.kind_of?(Effective::EmailTemplate) ? action : Effective::EmailTemplate.where(template_name: action).first!
27
+ end
28
+
29
+ # These defaults are only used when there is no email_template
30
+ email_defaults = form.object.email_form_defaults(action) unless email_template.present?
31
+
32
+ from = email_template&.from || email_defaults[:from] || EffectiveResources.mailer_froms.first
33
+ subject = email_template&.subject || email_defaults[:subject] || ''
34
+ body = email_template&.body || email_defaults[:body] || ''
35
+ content_type = email_template&.content_type || email_defaults[:content_type] || ''
36
+
37
+ locals = {
38
+ form: form,
39
+ email_to: to,
40
+ email_from: from,
41
+ email_subject: subject,
42
+ email_body: body,
43
+ email_content_type: content_type,
44
+ email_skip: skip,
45
+ email_action: (action || true),
46
+ email_template: email_template,
47
+ email_variables: variables
48
+ }
49
+
50
+ render(partial: (partial || 'effective/acts_as_email_form/fields'), locals: locals)
51
+ end
52
+
53
+ # acts_as_email_notification
54
+ def email_notification_fields(form, action, partial: nil, variables: nil)
55
+ raise('expected a form') unless form.respond_to?(:object)
56
+
57
+ resource = form.object
58
+
59
+ # Intended for acts_as_email_notification
60
+ raise('expected an acts_as_email_notification resource') unless resource.class.respond_to?(:acts_as_email_notification?)
61
+
62
+ # Load the template.
63
+ email_template = if action.present? && defined?(EffectiveEmailTemplates)
64
+ action.kind_of?(Effective::EmailTemplate) ? action : Effective::EmailTemplate.where(template_name: action).first!
65
+ end
66
+
67
+ raise('expected an Effective::EmailTemplate') unless email_template.kind_of?(Effective::EmailTemplate)
68
+
69
+ locals = {
70
+ form: form,
71
+
72
+ email_from: email_template.try(:from),
73
+ email_subject: email_template.try(:subject),
74
+ email_body: email_template.try(:body),
75
+ email_cc: email_template.try(:cc),
76
+ email_bcc: email_template.try(:bcc),
77
+ email_content_type: email_template.try(:content_type),
78
+
79
+ email_template: email_template,
80
+ email_variables: variables
81
+ }
82
+
83
+ render(partial: (partial || 'effective/acts_as_email_notification/fields'), locals: locals)
84
+ end
85
+
86
+ def email_message_html?(message)
87
+ message.parts.find { |part| part.content_type.start_with?('text/html') }.present?
88
+ end
89
+
90
+ def email_message_plain?(message)
91
+ message.parts.find { |part| part.content_type.start_with?('text/html') }.blank?
92
+ end
93
+
94
+ def email_message_body(message)
95
+ html_body = message.parts.find { |part| part.content_type.start_with?('text/html') }.try(:body).to_s
96
+ plain_body = message.parts.find { |part| part.content_type.start_with?('text/plain') }.try(:body).to_s
97
+ message_body = message.body.to_s
98
+
99
+ html_body.presence || plain_body.presence || message_body.presence
100
+ end
101
+
102
+ end
@@ -49,24 +49,24 @@ module ActsAsEmailForm
49
49
  validates :email_form_subject, liquid: true
50
50
  validates :email_form_body, liquid: true
51
51
  end
52
+ end
52
53
 
53
- def email_form_params
54
- { from: email_form_from, subject: email_form_subject, body: email_form_body }.compact
55
- end
56
-
57
- def email_form_skip?
58
- EffectiveResources.truthy?(email_form_skip)
59
- end
54
+ module ClassMethods
55
+ def acts_as_email_form?; true; end
56
+ end
60
57
 
61
- # Only considered when not using an effective email template
62
- def email_form_defaults(action)
63
- { from: nil, subject: nil, body: nil, content_type: 'text/plain' }
64
- end
58
+ # Instance methods
59
+ def email_form_params
60
+ { from: email_form_from, subject: email_form_subject, body: email_form_body }.compact
61
+ end
65
62
 
63
+ def email_form_skip?
64
+ EffectiveResources.truthy?(email_form_skip)
66
65
  end
67
66
 
68
- module ClassMethods
69
- def acts_as_email_form?; true; end
67
+ # Only considered when not using an effective email template
68
+ def email_form_defaults(action)
69
+ { from: nil, subject: nil, body: nil, content_type: 'text/plain' }
70
70
  end
71
71
 
72
72
  end
@@ -0,0 +1,124 @@
1
+ # ActsAsEmailNotification
2
+ # Used for email notification resources that are initialized from an effective_email_template but save their own liquid template content.
3
+ # Effective::EventNotification, Effective::PollNotification, Effective::Notification
4
+
5
+ module ActsAsEmailNotification
6
+ extend ActiveSupport::Concern
7
+
8
+ module Base
9
+ def acts_as_email_notification
10
+ include ::ActsAsEmailNotification
11
+ end
12
+ end
13
+
14
+ included do
15
+ if respond_to?(:effective_resource)
16
+ effective_resource do
17
+ from :string
18
+ cc :string
19
+ bcc :string
20
+
21
+ subject :string
22
+ body :text
23
+
24
+ content_type :string
25
+ end
26
+ end
27
+
28
+ validates :from, presence: true, email: true
29
+ validates :cc, email_cc: true
30
+ validates :bcc, email_cc: true
31
+
32
+ validates :subject, presence: true
33
+ validates :body, presence: true
34
+
35
+ validates :content_type, presence: true, inclusion: { in: ['text/plain', 'text/html'] }
36
+
37
+ validates :email_template, presence: true
38
+
39
+ with_options(if: -> { defined?(EffectiveEmailTemplates) }) do
40
+ validates :body, liquid: true
41
+ validates :subject, liquid: true
42
+ end
43
+
44
+ validate(if: -> { email_notification_html? && body.present? }) do
45
+ errors.add(:body, 'expected html tags in body') if email_notification_body_plain?
46
+ end
47
+
48
+ validate(if: -> { email_notification_plain? && body.present? }) do
49
+ errors.add(:body, 'unexpected html tags found in body') if email_notification_body_html?
50
+ end
51
+
52
+ validate(if: -> { email_notification_subject_template.present? }) do
53
+ if(invalid = email_notification_subject_variables - email_template_variables).present?
54
+ errors.add(:subject, "Invalid variable: #{invalid.to_sentence}")
55
+ end
56
+ end
57
+
58
+ validate(if: -> { email_notification_body_template.present? }) do
59
+ if(invalid = email_notification_body_variables - email_template_variables).present?
60
+ errors.add(:body, "Invalid variable: #{invalid.to_sentence}")
61
+ end
62
+ end
63
+ end
64
+
65
+ module ClassMethods
66
+ def acts_as_email_notification?; true; end
67
+ end
68
+
69
+ # To be overrided
70
+ def email_template
71
+ raise('to be implemented')
72
+ end
73
+
74
+ def email_template_variables
75
+ raise('to be implemented')
76
+ end
77
+
78
+ def email_notification_params
79
+ { from: from, cc: cc.presence, bcc: bcc.presence, subject: subject, body: body, content_type: content_type }
80
+ end
81
+
82
+ def email_notification_html?
83
+ content_type == 'text/html'
84
+ end
85
+
86
+ def email_notification_plain?
87
+ content_type == 'text/plain'
88
+ end
89
+
90
+ def email_notification_body_html?
91
+ body.present? && (body.include?('</p>') || body.include?('</div>'))
92
+ end
93
+
94
+ def email_notification_body_plain?
95
+ body.present? && !(body.include?('</p>') || body.include?('</div>'))
96
+ end
97
+
98
+ def email_notification_body_template
99
+ Liquid::Template.parse(body) rescue nil
100
+ end
101
+
102
+ def email_notification_subject_template
103
+ Liquid::Template.parse(subject) rescue nil
104
+ end
105
+
106
+ def email_notification_body_variables
107
+ template = email_notification_body_template()
108
+ return unless template.present?
109
+
110
+ Liquid::ParseTreeVisitor.for(template.root).add_callback_for(Liquid::VariableLookup) do |node|
111
+ [node.name, *node.lookups].join('.')
112
+ end.visit.flatten.uniq.compact
113
+ end
114
+
115
+ def email_notification_subject_variables
116
+ template = email_notification_subject_template()
117
+ return unless template.present?
118
+
119
+ Liquid::ParseTreeVisitor.for(template.root).add_callback_for(Liquid::VariableLookup) do |node|
120
+ [node.name, *node.lookups].join('.')
121
+ end.visit.flatten.uniq.compact
122
+ end
123
+
124
+ end
@@ -4,24 +4,35 @@
4
4
  = form.check_box :email_form_skip, label: 'Do not send email'
5
5
 
6
6
  = form.hide_if :email_form_skip, true do
7
- - errors = form.object.errors.present?
8
-
9
7
  - if email_to.present?
10
8
  = form.static_field :email_form_to, label: 'To', value: (email_to.try(:email) || email_to)
11
9
 
12
- = form.select :email_form_from, mailer_froms_collection(), label: 'From', value: (email_from unless errors)
13
- = form.text_field :email_form_subject, label: 'Subject', value: (email_subject unless errors)
14
-
15
- - if email_content_type == 'text/html'
16
- = form.article_editor :email_form_body, label: 'Body', mode: :email, value: (email_body unless errors)
17
- - else
18
- = form.text_area :email_form_body, label: 'Body', rows: 10, value: (email_body unless errors)
10
+ - # With errors
11
+ - if form.object.errors.present?
12
+ = form.select :email_form_from, mailer_froms_collection(), label: 'From'
13
+ = form.text_field :email_form_subject, label: 'Subject'
14
+
15
+ - if email_content_type == 'text/html'
16
+ = form.article_editor :email_form_body, label: 'Body', mode: :email
17
+ - else
18
+ = form.text_area :email_form_body, label: 'Body', rows: 10
19
+
20
+ - # With no errors
21
+ - if form.object.errors.blank?
22
+ = form.select :email_form_from, mailer_froms_collection(), label: 'From', value: email_from
23
+ = form.text_field :email_form_subject, label: 'Subject', value: email_subject
24
+
25
+ - if email_content_type == 'text/html'
26
+ = form.article_editor :email_form_body, label: 'Body', mode: :email, value: email_body
27
+ - else
28
+ = form.text_area :email_form_body, label: 'Body', rows: 10, value: email_body
19
29
 
20
30
  - if email_variables.present?
21
- %p The available variables are:
31
+ = card do
32
+ %p The available variables are:
22
33
 
23
- %ul
24
- - email_variables.each do |variable|
25
- %li {{ #{variable} }}
34
+ %ul
35
+ - email_variables.each do |variable|
36
+ %li {{ #{variable} }}
26
37
 
27
- %small.text-muted Please contact us to add additional variables
38
+ %small.text-muted Please contact us to add additional variables
@@ -0,0 +1,53 @@
1
+ - if email_template.present?
2
+ %p The following #{link_to(email_template, effective_email_templates.edit_admin_email_template_path(email_template), target: '_blank')} email will be sent:
3
+
4
+ = form.hidden_field :content_type, value: email_content_type
5
+
6
+ - uid = effective_bootstrap_unique_id
7
+ - expanded = form.object.cc.present? || form.object.bcc.present?
8
+ - mailer_subject_prefix_hint = EffectiveResources.mailer_subject_prefix_hint.to_s.strip.presence
9
+
10
+ - if form.object.new_record? && form.object.errors.blank?
11
+ .row
12
+ .col-md-10
13
+ = form.select :from, mailer_froms_collection(), label: 'From', value: email_from
14
+ .col-md-2.my-4
15
+ %a{href: "#acts-as-email-notification-collapse-#{uid}", 'data-toggle': 'collapse', role: 'button', 'aria-expanded': expanded, 'aria-controls': "acts-as-email-notification-collapse-#{uid}"} more...
16
+
17
+ .collapse{id: "acts-as-email-notification-collapse-#{uid}", class: ('show' if expanded)}
18
+ = form.text_field :cc, label: 'CC', value: email_cc
19
+ = form.text_field :bcc, label: 'BCC', value: email_bcc
20
+
21
+ = form.text_field :subject, value: email_subject, hint: (mailer_subject_prefix_hint ? "The subject of your email. It will be automatically prefixed with: #{mailer_subject_prefix_hint}" : 'The subject of your email')
22
+
23
+ - if email_content_type == 'text/html'
24
+ = form.article_editor :body, label: 'Body', mode: :email, value: email_body
25
+ - else
26
+ = form.text_area :body, label: 'Body', rows: 10, value: email_body
27
+
28
+ - else
29
+ .row
30
+ .col-md-10
31
+ = form.select :from, mailer_froms_collection(), label: 'From'
32
+ .col-md-2.my-4
33
+ %a{href: "#acts-as-email-notification-collapse-#{uid}", 'data-toggle': 'collapse', role: 'button', 'aria-expanded': expanded, 'aria-controls': "acts-as-email-notification-collapse-#{uid}"} more...
34
+
35
+ .collapse{id: "acts-as-email-notification-collapse-#{uid}", class: ('show' if expanded)}
36
+ = form.text_field :cc, label: 'CC'
37
+ = form.text_field :bcc, label: 'BCC'
38
+
39
+ = form.text_field :subject, hint: (mailer_subject_prefix_hint ? "The subject of your email. It will be automatically prefixed with: #{mailer_subject_prefix_hint}" : 'The subject of your email')
40
+
41
+ - if email_content_type == 'text/html'
42
+ = form.article_editor :body, label: 'Body', mode: :email
43
+ - else
44
+ = form.text_area :body, label: 'Body', rows: 10
45
+
46
+ - if email_variables.present?
47
+ = card do
48
+ %p You can use the following variables in the subject and body:
49
+
50
+ %ul
51
+ - email_variables.each do |variable|
52
+ %li {{ #{variable} }}
53
+
@@ -24,6 +24,7 @@ module EffectiveResources
24
24
  app.config.to_prepare do
25
25
  ActiveRecord::Base.extend(ActsAsArchived::Base)
26
26
  ActiveRecord::Base.extend(ActsAsEmailForm::Base)
27
+ ActiveRecord::Base.extend(ActsAsEmailNotification::Base)
27
28
  ActiveRecord::Base.extend(ActsAsTokened::Base)
28
29
  ActiveRecord::Base.extend(ActsAsSlugged::Base)
29
30
  ActiveRecord::Base.extend(ActsAsStatused::Base)
@@ -1,3 +1,3 @@
1
1
  module EffectiveResources
2
- VERSION = '2.23.0'.freeze
2
+ VERSION = '2.25.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.23.0
4
+ version: 2.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-20 00:00:00.000000000 Z
11
+ date: 2024-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -194,13 +194,14 @@ files:
194
194
  - app/controllers/concerns/effective/wizard_controller/permitted_params.rb
195
195
  - app/controllers/concerns/effective/wizard_controller/save.rb
196
196
  - app/controllers/concerns/effective/wizard_controller/wicked_overrides.rb
197
- - app/helpers/effective_acts_as_email_form_helper.rb
197
+ - app/helpers/effective_resources_email_helper.rb
198
198
  - app/helpers/effective_resources_helper.rb
199
199
  - app/helpers/effective_resources_private_helper.rb
200
200
  - app/helpers/effective_resources_wizard_helper.rb
201
201
  - app/mailers/concerns/effective_mailer.rb
202
202
  - app/models/concerns/acts_as_archived.rb
203
203
  - app/models/concerns/acts_as_email_form.rb
204
+ - app/models/concerns/acts_as_email_notification.rb
204
205
  - app/models/concerns/acts_as_paginable.rb
205
206
  - app/models/concerns/acts_as_purchasable_wizard.rb
206
207
  - app/models/concerns/acts_as_slugged.rb
@@ -256,6 +257,7 @@ files:
256
257
  - app/views/application/show.js.erb
257
258
  - app/views/application/update.js.erb
258
259
  - app/views/effective/acts_as_email_form/_fields.html.haml
260
+ - app/views/effective/acts_as_email_notification/_fields.html.haml
259
261
  - app/views/effective/acts_as_wizard/_wizard_step.html.haml
260
262
  - app/views/effective/resource/_actions.html.haml
261
263
  - app/views/effective/resource/_actions_dropleft.html.haml
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EffectiveActsAsEmailFormHelper
4
-
5
- def email_form_fields(form, action = nil, skip: true, to: nil, variables: nil, partial: nil)
6
- raise('expected a form') unless form.respond_to?(:object)
7
-
8
- resource = form.object
9
-
10
- # Intended for acts_as_email_form but sometimes we use a duck typed object to save these fields as well
11
- unless resource.class.respond_to?(:acts_as_email_form?) || resource.respond_to?("email_form_action=")
12
- raise('expected an acts_as_email_form resource or one that responds to email_form_action')
13
- end
14
-
15
- # Load the template.
16
- email_template = if action.present? && defined?(EffectiveEmailTemplates)
17
- action.kind_of?(Effective::EmailTemplate) ? action : Effective::EmailTemplate.where(template_name: action).first!
18
- end
19
-
20
- # These defaults are only used when there is no email_template
21
- email_defaults = form.object.email_form_defaults(action) unless email_template.present?
22
-
23
- from = email_template&.from || email_defaults[:from] || EffectiveResources.mailer_froms.first
24
- subject = email_template&.subject || email_defaults[:subject] || ''
25
- body = email_template&.body || email_defaults[:body] || ''
26
- content_type = email_template&.content_type || email_defaults[:content_type] || ''
27
-
28
- locals = {
29
- form: form,
30
- email_to: to,
31
- email_from: from,
32
- email_subject: subject,
33
- email_body: body,
34
- email_content_type: content_type,
35
- email_skip: skip,
36
- email_action: (action || true),
37
- email_template: email_template,
38
- email_variables: variables
39
- }
40
-
41
- render(partial: (partial || 'effective/acts_as_email_form/fields'), locals: locals)
42
- end
43
-
44
- def mailer_froms_collection(froms: nil)
45
- froms ||= EffectiveResources.mailer_froms
46
-
47
- froms.map do |from|
48
- html = content_tag(:span, escape_once(from))
49
- [from, from, 'data-html': html]
50
- end
51
- end
52
-
53
- end