locomotivecms_steam 1.1.2 → 1.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +41 -52
- data/lib/locomotive/steam/adapters/filesystem/sanitizers/page.rb +30 -35
- data/lib/locomotive/steam/adapters/filesystem.rb +8 -0
- data/lib/locomotive/steam/adapters/mongodb/command.rb +8 -1
- data/lib/locomotive/steam/adapters/mongodb.rb +10 -1
- data/lib/locomotive/steam/entities/content_entry.rb +13 -6
- data/lib/locomotive/steam/entities/page.rb +4 -0
- data/lib/locomotive/steam/entities/site.rb +1 -0
- data/lib/locomotive/steam/errors.rb +3 -0
- data/lib/locomotive/steam/initializers/dragonfly.rb +3 -5
- data/lib/locomotive/steam/initializers/sprockets.rb +10 -0
- data/lib/locomotive/steam/liquid/drops/content_entry.rb +8 -0
- data/lib/locomotive/steam/liquid/drops/content_entry_collection.rb +1 -1
- data/lib/locomotive/steam/liquid/tags/action.rb +59 -0
- data/lib/locomotive/steam/middlewares/entry_submission.rb +1 -1
- data/lib/locomotive/steam/middlewares/helpers.rb +8 -0
- data/lib/locomotive/steam/middlewares/locale.rb +1 -5
- data/lib/locomotive/steam/middlewares/locale_redirection.rb +1 -7
- data/lib/locomotive/steam/middlewares/renderer.rb +6 -3
- data/lib/locomotive/steam/middlewares/site.rb +12 -5
- data/lib/locomotive/steam/middlewares/sitemap.rb +6 -2
- data/lib/locomotive/steam/middlewares/thread_safe.rb +0 -4
- data/lib/locomotive/steam/models/associations/many_to_many.rb +1 -1
- data/lib/locomotive/steam/models/entity.rb +5 -0
- data/lib/locomotive/steam/models/repository.rb +4 -0
- data/lib/locomotive/steam/repositories/content_entry_repository.rb +23 -4
- data/lib/locomotive/steam/repositories/content_type_field_repository.rb +4 -0
- data/lib/locomotive/steam/services/action_service.rb +92 -0
- data/lib/locomotive/steam/services/content_entry_service.rb +114 -0
- data/lib/locomotive/steam/services/email_service.rb +102 -0
- data/lib/locomotive/steam/services/entry_submission_service.rb +6 -58
- data/lib/locomotive/steam/services/liquid_parser_service.rb +6 -0
- data/lib/locomotive/steam/services/url_builder_service.rb +5 -2
- data/lib/locomotive/steam/services.rb +13 -1
- data/lib/locomotive/steam/version.rb +1 -1
- data/lib/locomotive/steam.rb +5 -3
- data/locomotivecms_steam.gemspec +2 -0
- data/spec/fixtures/default/data/messages.yml +0 -0
- data/spec/integration/services/content_entry_service_spec.rb +110 -0
- data/spec/unit/adapters/filesystem_adapter_spec.rb +10 -0
- data/spec/unit/adapters/mongodb_adapter_spec.rb +18 -0
- data/spec/unit/entities/content_entry_spec.rb +34 -0
- data/spec/unit/entities/editable_element_spec.rb +19 -0
- data/spec/unit/entities/page_spec.rb +29 -0
- data/spec/unit/liquid/drops/content_entry_collection_spec.rb +4 -0
- data/spec/unit/liquid/drops/content_entry_spec.rb +5 -2
- data/spec/unit/liquid/tags/action_spec.rb +23 -0
- data/spec/unit/liquid/tags/link_to_spec.rb +12 -4
- data/spec/unit/liquid/tags/locale_switcher_spec.rb +15 -7
- data/spec/unit/liquid/tags/nav_spec.rb +19 -11
- data/spec/unit/liquid/tags/path_to_spec.rb +12 -4
- data/spec/unit/middlewares/helpers_spec.rb +29 -0
- data/spec/unit/middlewares/locale_redirection_spec.rb +11 -29
- data/spec/unit/middlewares/site_spec.rb +66 -13
- data/spec/unit/middlewares/sitemap_spec.rb +44 -0
- data/spec/unit/models/i18n_field_spec.rb +23 -0
- data/spec/unit/repositories/content_entry_repository_spec.rb +39 -7
- data/spec/unit/repositories/content_type_field_repository_spec.rb +10 -0
- data/spec/unit/services/action_service_spec.rb +173 -0
- data/spec/unit/services/content_entry_service_spec.rb +63 -0
- data/spec/unit/services/email_service_spec.rb +198 -0
- data/spec/unit/services/entry_submission_service_spec.rb +28 -112
- data/spec/unit/services/url_builder_service_spec.rb +14 -5
- metadata +50 -6
- data/spec/unit/middlewares/locale_spec.rb +0 -52
@@ -37,6 +37,14 @@ module Locomotive::Steam
|
|
37
37
|
path
|
38
38
|
end
|
39
39
|
|
40
|
+
# make sure the location passed in parameter doesn't
|
41
|
+
# include the "mounted_on" parameter.
|
42
|
+
# If so, returns the location without the "mounted_on" string.
|
43
|
+
def make_local_path(location)
|
44
|
+
return location if mounted_on.blank?
|
45
|
+
location.gsub(Regexp.new('^' + mounted_on), '')
|
46
|
+
end
|
47
|
+
|
40
48
|
def mounted_on
|
41
49
|
request.env['steam.mounted_on']
|
42
50
|
end
|
@@ -28,7 +28,7 @@ module Locomotive::Steam
|
|
28
28
|
protected
|
29
29
|
|
30
30
|
def extract_locale
|
31
|
-
_locale =
|
31
|
+
_locale = params[:locale] || default_locale
|
32
32
|
_path = request.path_info
|
33
33
|
|
34
34
|
if _path =~ /^\/(#{site.locales.join('|')})+(\/|$)/
|
@@ -44,10 +44,6 @@ module Locomotive::Steam
|
|
44
44
|
env['steam.locale'] = services.locale = _locale
|
45
45
|
end
|
46
46
|
|
47
|
-
def locale_from_params
|
48
|
-
locales.include?(params[:locale]) ? params[:locale] : nil
|
49
|
-
end
|
50
|
-
|
51
47
|
end
|
52
48
|
end
|
53
49
|
end
|
@@ -23,7 +23,7 @@ module Locomotive::Steam
|
|
23
23
|
if site.prefix_default_locale
|
24
24
|
path_with_default_locale if locale_not_mentioned_in_path?
|
25
25
|
else
|
26
|
-
|
26
|
+
env['steam.path'] if default_locale? && locale_mentioned_in_path?
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -50,12 +50,6 @@ module Locomotive::Steam
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def path_without_default_locale
|
54
|
-
modify_path do |segments|
|
55
|
-
segments.delete_at(1)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
53
|
end
|
60
54
|
end
|
61
55
|
|
@@ -20,7 +20,7 @@ module Locomotive::Steam
|
|
20
20
|
redirect_to(page.redirect_url, page.redirect_type)
|
21
21
|
else
|
22
22
|
content = parse_and_render_liquid
|
23
|
-
render_response(content, page.not_found? ? 404
|
23
|
+
render_response(content, page.not_found? ? 404: 200, page.response_type)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -53,7 +53,8 @@ module Locomotive::Steam
|
|
53
53
|
services: services,
|
54
54
|
repositories: services.repositories,
|
55
55
|
logger: Locomotive::Common::Logger,
|
56
|
-
live_editing: !!env['steam.live_editing']
|
56
|
+
live_editing: !!env['steam.live_editing'],
|
57
|
+
session: request.session
|
57
58
|
}
|
58
59
|
end
|
59
60
|
|
@@ -71,7 +72,8 @@ module Locomotive::Steam
|
|
71
72
|
'now' => Time.zone.now,
|
72
73
|
'today' => Date.today,
|
73
74
|
'mode' => Locomotive::Steam.configuration.mode,
|
74
|
-
'wagon' => Locomotive::Steam.configuration.mode == :test
|
75
|
+
'wagon' => Locomotive::Steam.configuration.mode == :test,
|
76
|
+
'live_editing' => !!env['steam.live_editing']
|
75
77
|
}
|
76
78
|
end
|
77
79
|
|
@@ -102,6 +104,7 @@ module Locomotive::Steam
|
|
102
104
|
'ip_address' => request.ip,
|
103
105
|
'post?' => request.post?,
|
104
106
|
'base_url' => request.base_url,
|
107
|
+
'user_agent' => request.user_agent,
|
105
108
|
'mounted_on' => mounted_on
|
106
109
|
}
|
107
110
|
end
|
@@ -16,7 +16,8 @@ module Locomotive::Steam
|
|
16
16
|
# log anyway
|
17
17
|
log_site(site)
|
18
18
|
|
19
|
-
|
19
|
+
# redirect to the first domain and/or HTTPS if defined by the site
|
20
|
+
redirect_if_required(site)
|
20
21
|
end
|
21
22
|
|
22
23
|
private
|
@@ -40,9 +41,11 @@ module Locomotive::Steam
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
def
|
44
|
-
if
|
45
|
-
|
44
|
+
def redirect_if_required(site)
|
45
|
+
return if env['steam.is_default_host']
|
46
|
+
|
47
|
+
if redirect_to_first_domain?(site) || redirect_to_https?(site)
|
48
|
+
klass = request.scheme == 'https' || redirect_to_https?(site) ? URI::HTTPS : URI::HTTP
|
46
49
|
redirect_to klass.build(
|
47
50
|
host: site.domains.first,
|
48
51
|
port: [80, 443].include?(request.port) ? nil : request.port,
|
@@ -54,11 +57,15 @@ module Locomotive::Steam
|
|
54
57
|
def redirect_to_first_domain?(site)
|
55
58
|
# the site parameter can be an instance of Locomotive::Steam::Services::Defer and
|
56
59
|
# so comparing just site may not be reliable.
|
57
|
-
!env['steam.is_default_host'] &&
|
58
60
|
site.try(:redirect_to_first_domain) &&
|
59
61
|
site.domains.first != request.host
|
60
62
|
end
|
61
63
|
|
64
|
+
def redirect_to_https?(site)
|
65
|
+
site.try(:redirect_to_https) &&
|
66
|
+
request.scheme != 'https'
|
67
|
+
end
|
68
|
+
|
62
69
|
def log_site(site)
|
63
70
|
if site.nil?
|
64
71
|
msg = "Unable to find a site, url asked: #{request.url} ".colorize(color: :light_white, background: :red)
|
@@ -27,8 +27,8 @@ module Locomotive::Steam
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def build_pages_to_xml
|
30
|
-
|
31
|
-
next if page.index? || page.not_found?
|
30
|
+
page_repository.published.map do |page|
|
31
|
+
next if page.index? || page.not_found? || page.layout?
|
32
32
|
|
33
33
|
build_page_xml(page)
|
34
34
|
end.flatten.join.strip
|
@@ -80,6 +80,10 @@ module Locomotive::Steam
|
|
80
80
|
services.repositories
|
81
81
|
end
|
82
82
|
|
83
|
+
def page_repository
|
84
|
+
repositories.page
|
85
|
+
end
|
86
|
+
|
83
87
|
def url_for(page, locale = nil)
|
84
88
|
services.url_builder.url_for(page, locale)
|
85
89
|
end
|
@@ -6,7 +6,7 @@ module Locomotive::Steam
|
|
6
6
|
def __load__
|
7
7
|
key = @repository.k(:_id, :in)
|
8
8
|
|
9
|
-
@repository.local_conditions[key] = @entity[__target_key__]
|
9
|
+
@repository.local_conditions[key] = @entity[__target_key__] || []
|
10
10
|
|
11
11
|
# use order_by from options as the default one for further queries
|
12
12
|
@repository.local_conditions[:order_by] = @options[:order_by] unless @options[:order_by].blank?
|
@@ -131,7 +131,7 @@ module Locomotive
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def prepare_conditions(*conditions)
|
134
|
-
_conditions = Conditions.new(conditions.first, self.content_type.fields).prepare
|
134
|
+
_conditions = Conditions.new(adapter, conditions.first, self.content_type.fields).prepare
|
135
135
|
|
136
136
|
super({ _visible: true }, _conditions)
|
137
137
|
end
|
@@ -185,8 +185,10 @@ module Locomotive
|
|
185
185
|
|
186
186
|
class Conditions
|
187
187
|
|
188
|
-
def initialize(conditions = {}, fields)
|
189
|
-
@
|
188
|
+
def initialize(adapter, conditions = {}, fields)
|
189
|
+
@adapter = adapter
|
190
|
+
@conditions = conditions.try(:with_indifferent_access) || {}
|
191
|
+
@fields, @operators = fields, {}
|
190
192
|
|
191
193
|
@conditions.each do |name, value|
|
192
194
|
_name, operator = name.to_s.split('.')
|
@@ -200,6 +202,9 @@ module Locomotive
|
|
200
202
|
field.select_options.by_name(value).try(:_id)
|
201
203
|
end
|
202
204
|
|
205
|
+
# date
|
206
|
+
_prepare(@fields.dates_and_date_times) { |field, value| value_to_date(value, field.type) }
|
207
|
+
|
203
208
|
# belongs_to
|
204
209
|
_prepare(@fields.belongs_to) { |field, value| value_to_id(value) }
|
205
210
|
|
@@ -233,11 +238,25 @@ module Locomotive
|
|
233
238
|
end
|
234
239
|
|
235
240
|
def value_to_id(value)
|
236
|
-
if value.
|
241
|
+
_value = if value.is_a?(Hash)
|
242
|
+
value['_id'] || value[:_id]
|
243
|
+
elsif value.respond_to?(:each) # array
|
237
244
|
values_to_ids(value)
|
238
245
|
else
|
239
246
|
value.respond_to?(:_id) ? value._id : value
|
240
247
|
end
|
248
|
+
|
249
|
+
@adapter.make_id(_value)
|
250
|
+
end
|
251
|
+
|
252
|
+
def value_to_date(value, type)
|
253
|
+
_value = if value.is_a?(String)
|
254
|
+
Chronic.time_class = Time.zone
|
255
|
+
Chronic.parse(value)
|
256
|
+
else
|
257
|
+
value
|
258
|
+
end
|
259
|
+
type == :date ? _value.to_date : _value.to_datetime
|
241
260
|
end
|
242
261
|
|
243
262
|
def values_to_ids(value)
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Force ExecJS to select the best engine based on the current configuration.
|
2
|
+
# It means that if, down the road, we load a different javascript engine,
|
3
|
+
# the ExecJS runtime won't be affected.
|
4
|
+
require 'duktape'
|
5
|
+
require 'execjs'
|
6
|
+
ExecJS.runtimes.delete_if { |mod| mod.is_a?(ExecJS::DuktapeRuntime) }
|
7
|
+
ExecJS.instance_variable_set(:@runtime, ExecJS::Runtimes.autodetect)
|
8
|
+
|
9
|
+
module Locomotive
|
10
|
+
module Steam
|
11
|
+
|
12
|
+
class ActionService
|
13
|
+
|
14
|
+
BUILT_IN_FUNCTIONS = %w(
|
15
|
+
getProp
|
16
|
+
setProp
|
17
|
+
getSessionProp
|
18
|
+
setSessionProp
|
19
|
+
sendEmail
|
20
|
+
allEntries
|
21
|
+
findEntry
|
22
|
+
createEntry
|
23
|
+
updateEntry)
|
24
|
+
|
25
|
+
attr_accessor_initialize :site, :email, :content_entry_service
|
26
|
+
|
27
|
+
def run(script, params = {}, liquid_context)
|
28
|
+
context = Duktape::Context.new
|
29
|
+
|
30
|
+
define_built_in_functions(context, liquid_context)
|
31
|
+
|
32
|
+
script = <<-JS
|
33
|
+
function locomotiveAction(site, params) {
|
34
|
+
#{script}
|
35
|
+
}
|
36
|
+
JS
|
37
|
+
|
38
|
+
# puts script.inspect # DEBUG
|
39
|
+
|
40
|
+
context.exec_string script
|
41
|
+
|
42
|
+
context.call_prop('locomotiveAction', site.as_json, params)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def define_built_in_functions(context, liquid_context)
|
48
|
+
BUILT_IN_FUNCTIONS.each do |name|
|
49
|
+
context.define_function name, &send(:"#{name.underscore}_lambda", liquid_context)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def send_email_lambda(liquid_context)
|
54
|
+
-> (options) { !!email.send_email(options, liquid_context) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_prop_lambda(liquid_context)
|
58
|
+
-> (name) { liquid_context[name].as_json }
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_prop_lambda(liquid_context)
|
62
|
+
-> (name, value) { liquid_context.scopes.last[name] = value }
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_session_prop_lambda(liquid_context)
|
66
|
+
-> (name) { liquid_context.registers[:session][name.to_sym].as_json }
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_session_prop_lambda(liquid_context)
|
70
|
+
-> (name, value) { liquid_context.registers[:session][name.to_sym] = value }
|
71
|
+
end
|
72
|
+
|
73
|
+
def all_entries_lambda(liquid_context)
|
74
|
+
-> (type, conditions) { content_entry_service.all(type, conditions, true) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_entry_lambda(liquid_context)
|
78
|
+
-> (type, id_or_slug) { content_entry_service.find(type, id_or_slug, true) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_entry_lambda(liquid_context)
|
82
|
+
-> (type, attributes) { content_entry_service.create(type, attributes, true) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def update_entry_lambda(liquid_context)
|
86
|
+
-> (type, id_or_slug, attributes) { content_entry_service.update(type, id_or_slug, attributes, true) }
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'sanitize'
|
2
|
+
|
3
|
+
module Locomotive
|
4
|
+
module Steam
|
5
|
+
|
6
|
+
class ContentEntryService
|
7
|
+
|
8
|
+
include Locomotive::Steam::Services::Concerns::Decorator
|
9
|
+
|
10
|
+
attr_accessor_initialize :content_type_repository, :repository, :locale
|
11
|
+
|
12
|
+
def all(type_slug, conditions = {}, as_json = false)
|
13
|
+
with_repository(type_slug) do |_repository|
|
14
|
+
_repository.all(conditions).map do |entry|
|
15
|
+
_decorate(entry, as_json)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def find(type_slug, id_or_slug, as_json = false)
|
21
|
+
with_repository(type_slug) do |_repository|
|
22
|
+
entry = _repository.by_slug(id_or_slug) || _repository.find(id_or_slug)
|
23
|
+
_decorate(entry, as_json)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Warning: do not work with localized and file fields
|
28
|
+
def create(type_slug, attributes, as_json = false)
|
29
|
+
with_repository(type_slug) do |_repository|
|
30
|
+
entry = _repository.build(clean_attributes(attributes))
|
31
|
+
decorated_entry = i18n_decorate { entry }
|
32
|
+
|
33
|
+
if validate(_repository, decorated_entry)
|
34
|
+
_repository.create(entry)
|
35
|
+
end
|
36
|
+
|
37
|
+
_json_decorate(decorated_entry, as_json)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Warning: do not work with localized and file fields
|
42
|
+
def update(type_slug, id_or_slug, attributes, as_json = false)
|
43
|
+
with_repository(type_slug) do |_repository|
|
44
|
+
entry = _repository.by_slug(id_or_slug) || _repository.find(id_or_slug)
|
45
|
+
decorated_entry = i18n_decorate { entry.change(clean_attributes(attributes)) }
|
46
|
+
|
47
|
+
if validate(_repository, decorated_entry)
|
48
|
+
_repository.update(entry)
|
49
|
+
end
|
50
|
+
|
51
|
+
_json_decorate(decorated_entry, as_json)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete(type_slug, id_or_slug)
|
56
|
+
with_repository(type_slug) do |_repository|
|
57
|
+
entry = _repository.by_slug(id_or_slug) || _repository.find(id_or_slug)
|
58
|
+
_repository.delete(entry)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_type(slug)
|
63
|
+
return nil if slug.blank?
|
64
|
+
|
65
|
+
content_type_repository.by_slug(slug)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def with_repository(type_or_slug)
|
71
|
+
type = type_or_slug.respond_to?(:fields) ? type_or_slug : get_type(type_or_slug)
|
72
|
+
|
73
|
+
return if type.nil?
|
74
|
+
|
75
|
+
yield(repository.with(type))
|
76
|
+
end
|
77
|
+
|
78
|
+
def _decorate(entry, as_json)
|
79
|
+
decorated_entry = i18n_decorate { entry }
|
80
|
+
_json_decorate(decorated_entry, as_json)
|
81
|
+
end
|
82
|
+
|
83
|
+
def _json_decorate(entry, as_json)
|
84
|
+
as_json ? entry.as_json : entry
|
85
|
+
end
|
86
|
+
|
87
|
+
def clean_attributes(attributes)
|
88
|
+
attributes.each do |key, value|
|
89
|
+
next unless value.is_a?(String)
|
90
|
+
attributes[key] = Sanitize.clean(value, Sanitize::Config::BASIC)
|
91
|
+
end
|
92
|
+
attributes
|
93
|
+
end
|
94
|
+
|
95
|
+
def validate(_repository, entry)
|
96
|
+
# simple validations (existence of values) first
|
97
|
+
entry.valid?
|
98
|
+
|
99
|
+
# check if the entry has unique values for its
|
100
|
+
# fields marked as unique
|
101
|
+
content_type_repository.look_for_unique_fields(entry.content_type).each do |name, _|
|
102
|
+
if _repository.exists?(name => entry.send(name))
|
103
|
+
entry.errors.add(name, :unique)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
entry.errors.empty?
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'pony'
|
2
|
+
|
3
|
+
module Locomotive
|
4
|
+
module Steam
|
5
|
+
|
6
|
+
class EmailService
|
7
|
+
|
8
|
+
attr_accessor_initialize :page_finder_service, :liquid_parser, :asset_host, :simulation
|
9
|
+
|
10
|
+
def send_email(options, context)
|
11
|
+
prepare_options(options, context)
|
12
|
+
|
13
|
+
log(options, simulation)
|
14
|
+
|
15
|
+
!simulation ? send_email!(options) : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_email!(options)
|
19
|
+
Pony.mail(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
Locomotive::Common::Logger
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def prepare_options(options, context)
|
29
|
+
build_body(options.symbolize_keys!, context, options.delete(:html))
|
30
|
+
|
31
|
+
extract_attachment(options)
|
32
|
+
|
33
|
+
options[:via] ||= :smtp
|
34
|
+
options[:via_options] ||= options.delete(:smtp).try(:symbolize_keys)
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_body(options, context, html = true)
|
38
|
+
key = html || html.nil? ? :html_body : :body
|
39
|
+
|
40
|
+
document = (if handle = options.delete(:page_handle)
|
41
|
+
parse_page(handle)
|
42
|
+
elsif body = options.delete(:body)
|
43
|
+
liquid_parser.parse_string(body)
|
44
|
+
else
|
45
|
+
raise "[EmailService] the body or page_handle options are missing."
|
46
|
+
end)
|
47
|
+
|
48
|
+
options[key] = document.render(context)
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_page(handle)
|
52
|
+
if page = page_finder_service.by_handle(handle, false)
|
53
|
+
liquid_parser.parse(page) # the liquid parser decorates the page (i18n)
|
54
|
+
else
|
55
|
+
raise "[EmailService] No page found with the following handle: #{handle}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def extract_attachment(options)
|
60
|
+
(options[:attachments] || {}).each do |filename, value|
|
61
|
+
options[:attachments][filename] = read_attachment(value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def read_attachment(value)
|
66
|
+
url = case value
|
67
|
+
when /^https?:\/\// then value
|
68
|
+
when /^\// then asset_host.compute(value, false)
|
69
|
+
else
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
url ? _read_http_attachment(url) : value
|
74
|
+
end
|
75
|
+
|
76
|
+
def _read_http_attachment(url)
|
77
|
+
begin
|
78
|
+
uri = URI(url)
|
79
|
+
Net::HTTP.get(uri)
|
80
|
+
rescue Exception => e
|
81
|
+
logger.error "[SendEmail] Unable to read the '#{url}' url, error: #{e.message}"
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def log(options, simulation)
|
87
|
+
message = ["[#{simulation ? 'Test' : 'Live'}] Sent email via #{options[:via]} (#{options[:via_options].inspect}):"]
|
88
|
+
message << "From: #{options[:from]}"
|
89
|
+
message << "To: #{options[:to]}"
|
90
|
+
message << "Subject: #{options[:subject]}"
|
91
|
+
message << "Attachments: #{options[:attachments]}"
|
92
|
+
message << "-----------"
|
93
|
+
message << (options[:body] || options[:html_body]).gsub("\n", "\n\t")
|
94
|
+
message << "-----------"
|
95
|
+
|
96
|
+
logger.info message.join("\n") + "\n\n"
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -1,76 +1,24 @@
|
|
1
|
-
require 'sanitize'
|
2
|
-
|
3
1
|
module Locomotive
|
4
2
|
module Steam
|
5
3
|
|
6
4
|
class EntrySubmissionService
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
attr_accessor_initialize :content_type_repository, :repository, :locale
|
6
|
+
attr_accessor_initialize :service
|
11
7
|
|
12
|
-
def submit(
|
13
|
-
type = get_type(
|
8
|
+
def submit(type_slug, attributes = {})
|
9
|
+
type = service.get_type(type_slug)
|
14
10
|
|
15
11
|
return nil if type.nil? || type.public_submission_enabled == false
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
build_entry(type, attributes) do |entry|
|
20
|
-
if validate(entry)
|
21
|
-
repository.create(entry)
|
22
|
-
end
|
23
|
-
end
|
13
|
+
service.create(type, attributes)
|
24
14
|
end
|
25
15
|
|
26
16
|
def find(type_slug, slug)
|
27
|
-
|
28
|
-
|
29
|
-
return nil if type.nil?
|
30
|
-
|
31
|
-
i18n_decorate { repository.with(type).by_slug(slug) }
|
17
|
+
service.find(type_slug, slug)
|
32
18
|
end
|
33
19
|
|
34
20
|
def to_json(entry)
|
35
|
-
|
36
|
-
|
37
|
-
entry.to_json
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def get_type(slug)
|
43
|
-
return nil if slug.blank?
|
44
|
-
|
45
|
-
content_type_repository.by_slug(slug)
|
46
|
-
end
|
47
|
-
|
48
|
-
def build_entry(type, attributes, &block)
|
49
|
-
i18n_decorate { repository.with(type).build(attributes) }.tap do |entry|
|
50
|
-
yield(entry)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def validate(entry)
|
55
|
-
# simple validations (existence of values) first
|
56
|
-
entry.valid?
|
57
|
-
|
58
|
-
# check if the entry has unique values for its
|
59
|
-
# fields marked as unique
|
60
|
-
content_type_repository.look_for_unique_fields(entry.content_type).each do |name, _|
|
61
|
-
if repository.with(entry.content_type).exists?(name => entry.send(name))
|
62
|
-
entry.errors.add(name, :unique)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
entry.errors.empty?
|
67
|
-
end
|
68
|
-
|
69
|
-
def clean_attributes(attributes)
|
70
|
-
attributes.each do |key, value|
|
71
|
-
next unless value.is_a?(String)
|
72
|
-
attributes[key] = Sanitize.clean(value, Sanitize::Config::BASIC)
|
73
|
-
end
|
21
|
+
entry.try(&:to_json)
|
74
22
|
end
|
75
23
|
|
76
24
|
end
|
@@ -14,6 +14,12 @@ module Locomotive
|
|
14
14
|
default_editable_content: {})
|
15
15
|
end
|
16
16
|
|
17
|
+
def parse_string(string)
|
18
|
+
Locomotive::Steam::Liquid::Template.parse(string,
|
19
|
+
snippet_finder: snippet_finder,
|
20
|
+
parser: self)
|
21
|
+
end
|
22
|
+
|
17
23
|
def _parse(object, options = {})
|
18
24
|
# Note: the template must not be parsed here
|
19
25
|
Locomotive::Steam::Liquid::Template.parse(object.liquid_source, options)
|