locomotive_cms 2.5.6 → 2.5.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +7 -3
- data/app/assets/javascripts/locomotive/utils/tinymce_settings.js.coffee +4 -3
- data/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee +2 -2
- data/app/assets/stylesheets/locomotive/backoffice/application.css.scss +34 -1
- data/app/controllers/locomotive/api/base_controller.rb +8 -0
- data/app/controllers/locomotive/api/content_entries_controller.rb +15 -2
- data/app/controllers/locomotive/api/my_account_controller.rb +15 -0
- data/app/controllers/locomotive/api/version_controller.rb +17 -0
- data/app/controllers/locomotive/base_controller.rb +1 -1
- data/app/controllers/locomotive/content_entries_controller.rb +9 -10
- data/app/helpers/locomotive/content_types_helper.rb +16 -1
- data/app/helpers/locomotive/pages_helper.rb +13 -1
- data/app/models/locomotive/content_type.rb +15 -8
- data/app/models/locomotive/extensions/page/layout.rb +42 -0
- data/app/models/locomotive/extensions/page/templatized.rb +1 -1
- data/app/models/locomotive/page.rb +1 -0
- data/app/presenters/locomotive/content_entry_presenter.rb +5 -1
- data/app/presenters/locomotive/page_presenter.rb +1 -1
- data/app/services/locomotive/content_entry_service.rb +81 -0
- data/app/uploaders/locomotive/theme_asset_uploader.rb +1 -1
- data/app/views/locomotive/content_entries/index.html.haml +8 -0
- data/app/views/locomotive/content_types/_form.html.haml +2 -0
- data/app/views/locomotive/notifications/new_content_entry.html.haml +2 -2
- data/app/views/locomotive/pages/_form.html.haml +8 -1
- data/config/locales/admin_ui.en.yml +2 -0
- data/config/locales/admin_ui.fr.yml +1 -0
- data/config/locales/formtastic.en.yml +3 -0
- data/config/routes.rb +6 -2
- data/features/api/content_entries.feature +22 -9
- data/features/backoffice/site.feature +1 -1
- data/features/public/content_entries.feature +20 -5
- data/features/step_definitions/content_types_steps.rb +6 -0
- data/lib/generators/locomotive/install/templates/devise.rb +0 -2
- data/lib/locomotive/action_controller/responder.rb +1 -1
- data/lib/locomotive/carrierwave.rb +1 -0
- data/lib/locomotive/carrierwave/asset.rb +1 -1
- data/lib/locomotive/httparty/webservice.rb +17 -11
- data/lib/locomotive/liquid/drops/content_types.rb +7 -1
- data/lib/locomotive/liquid/drops/page.rb +51 -3
- data/lib/locomotive/liquid/tags/consume.rb +15 -10
- data/lib/locomotive/liquid/tags/editable/base.rb +1 -1
- data/lib/locomotive/liquid/tags/with_scope.rb +6 -1
- data/lib/locomotive/presentable.rb +1 -1
- data/lib/locomotive/regexps.rb +1 -1
- data/lib/locomotive/version.rb +1 -1
- data/lib/tasks/locomotive.rake +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/mongoid.yml +2 -2
- data/spec/lib/locomotive/httparty/webservice_spec.rb +8 -3
- data/spec/lib/locomotive/liquid/drops/page_spec.rb +20 -5
- data/spec/lib/locomotive/liquid/tags/consume_spec.rb +66 -48
- data/spec/lib/locomotive/liquid/tags/with_scope_spec.rb +6 -0
- data/spec/mailers/locomotive/notifications_spec.rb +15 -8
- data/spec/models/locomotive/content_entry_spec.rb +1 -1
- data/spec/models/locomotive/editable_control_spec.rb +2 -2
- data/spec/models/locomotive/extensions/page/layout_spec.rb +50 -0
- data/spec/models/locomotive/site_spec.rb +1 -1
- metadata +26 -7
@@ -94,7 +94,11 @@ module Locomotive
|
|
94
94
|
{}.tap do |hash|
|
95
95
|
(self.__source.has_many_custom_fields + self.__source.many_to_many_custom_fields).each do |name, _|
|
96
96
|
if self.__depth == 0
|
97
|
-
|
97
|
+
field = self.__source.content_type.find_entries_custom_field(name.to_s)
|
98
|
+
|
99
|
+
next if self.html_view? && !field.ui_enabled?
|
100
|
+
|
101
|
+
list = self.__source.send(name.to_sym).ordered
|
98
102
|
hash[name.to_s] = list.map do |entry|
|
99
103
|
if self.html_view?
|
100
104
|
entry.to_presenter(depth: self.__depth + 1, html_view: true).as_json
|
@@ -16,7 +16,7 @@ module Locomotive
|
|
16
16
|
property :redirect, type: 'Boolean'
|
17
17
|
properties :redirect_url, :redirect_type
|
18
18
|
|
19
|
-
properties :listed, :published, :templatized, type: 'Boolean'
|
19
|
+
properties :listed, :published, :templatized, :is_layout, :allow_layout, type: 'Boolean'
|
20
20
|
|
21
21
|
property :templatized_from_parent, type: 'Boolean', only_getter: true
|
22
22
|
property :target_klass_slug, alias: [:target_klass_name, :target_entry_name]
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Locomotive
|
2
|
+
class ContentEntryService < Struct.new(:content_type)
|
3
|
+
|
4
|
+
# List all the entries of a content type.
|
5
|
+
#
|
6
|
+
# If the content type allows the pagination, in other words, if the entries are not
|
7
|
+
# ordered by the position column), then this method will return
|
8
|
+
# a paginated list of entries.
|
9
|
+
#
|
10
|
+
# This list can also be filtered by the _label attribute, by setting the "q" key in the options.
|
11
|
+
#
|
12
|
+
# For a more powerful search, you can use the "where" key which accepts a JSON string or a Hash.
|
13
|
+
#
|
14
|
+
# @param [ Hash ] options The options for the pagination and the filtering
|
15
|
+
#
|
16
|
+
# @return [ Object ] a paginated list of content entries
|
17
|
+
#
|
18
|
+
def all(options = {})
|
19
|
+
_options = prepare_options_for_all(options)
|
20
|
+
|
21
|
+
if _options[:grouping]
|
22
|
+
content_type.list_or_group_entries(_options)
|
23
|
+
else
|
24
|
+
content_type.ordered_entries(_options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Destroy all the entries of a content type.
|
29
|
+
# Runs each entry's destroy callbacks.
|
30
|
+
#
|
31
|
+
def destroy_all
|
32
|
+
content_type.entries.destroy_all
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def prepare_options_for_all(options)
|
38
|
+
where = prepare_where_statement(options)
|
39
|
+
|
40
|
+
{
|
41
|
+
page: options[:page] || 1,
|
42
|
+
per_page: options[:per_page] || Locomotive.config.ui[:per_page],
|
43
|
+
grouping: options[:grouping] || options[:q].blank?,
|
44
|
+
where: where
|
45
|
+
}.tap do |_options|
|
46
|
+
_options[:order_by] = options[:order_by] if options[:order_by]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def prepare_where_statement(options)
|
51
|
+
where = (case options[:where]
|
52
|
+
when String then options[:where].blank? ? {} : JSON.parse(options[:where])
|
53
|
+
when Hash then options[:where]
|
54
|
+
else {}
|
55
|
+
end).with_indifferent_access
|
56
|
+
|
57
|
+
if options[:q]
|
58
|
+
where.merge!(prepare_query_statement(options[:q]))
|
59
|
+
end
|
60
|
+
|
61
|
+
where
|
62
|
+
end
|
63
|
+
|
64
|
+
def prepare_query_statement(query)
|
65
|
+
regexp = /.*#{query.split.map { |q| Regexp.escape(q) }.join('.*')}.*/i
|
66
|
+
|
67
|
+
{}.tap do |where|
|
68
|
+
if self.content_type.filter_fields.blank?
|
69
|
+
where[content_type.label_field_name.to_sym] = regexp
|
70
|
+
else
|
71
|
+
where['$or'] = []
|
72
|
+
self.content_type.filter_fields.each do |field_id|
|
73
|
+
field = self.content_type.entries_custom_fields.find(field_id)
|
74
|
+
where['$or'] << { field.name => regexp }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -11,9 +11,17 @@
|
|
11
11
|
|
12
12
|
= local_action_button :new, new_content_entry_path(@content_type.slug), icon: 'icon-plus'
|
13
13
|
|
14
|
+
- if @content_type.filter_fields.present?
|
15
|
+
.search-box
|
16
|
+
= form_tag content_entries_path(@content_type.slug), method: :get do
|
17
|
+
%i.icon-search
|
18
|
+
= text_field_tag :q, params[:q], placeholder: t('.search_placeholder')
|
19
|
+
|
14
20
|
- if @content_type.description.present?
|
15
21
|
%p= @content_type.description
|
16
22
|
|
23
|
+
.clear
|
24
|
+
|
17
25
|
- if @content_type.groupable?
|
18
26
|
- @content_entries.each do |group|
|
19
27
|
.box
|
@@ -34,6 +34,8 @@
|
|
34
34
|
|
35
35
|
= f.input :order_direction, as: :select, collection: options_for_order_direction, include_blank: false, wrapper_html: { style: "#{'display: none' if @content_type.order_manually?}" }
|
36
36
|
|
37
|
+
= f.input :filter_fields, as: :select, collection: options_for_filter_fields(@content_type), include_blank: false, multiple: true, wrapper_html: { class: 'multiple' }
|
38
|
+
|
37
39
|
= f.input :public_submission_enabled, as: :'Locomotive::Toggle'
|
38
40
|
|
39
41
|
= f.input :public_submission_accounts, as: :select, collection: options_for_account, include_blank: false, multiple: true, wrapper_html: { class: 'multiple', style: (@content_type.public_submission_enabled? ? '' : 'display: none') }
|
@@ -1,4 +1,4 @@
|
|
1
|
-
%p= t('.title', name: @account.name, domain: @domain, date: I18n.l(Time.
|
1
|
+
%p= t('.title', name: @account.name, domain: @domain, date: I18n.l(Time.now.in_time_zone), locale: @account.locale).html_safe
|
2
2
|
|
3
3
|
%p
|
4
4
|
%b= t('.type', type: @type.name, locale: @account.locale)
|
@@ -28,4 +28,4 @@
|
|
28
28
|
- when 'tags'
|
29
29
|
= value.join(', ')
|
30
30
|
- else
|
31
|
-
= value
|
31
|
+
= value
|
@@ -16,6 +16,9 @@
|
|
16
16
|
|
17
17
|
= f.input :slug, required: false, hint: @page.slug.blank? ? t('.empty_slug') : public_page_url(@page, locale: current_content_locale), input_html: { :'data-url' => get_path_pages_path, disabled: @page.index? || @page.not_found? }, wrapper_html: { style: "#{'display: none' if @page.templatized? && !@page.templatized_from_parent?};", class: 'em-inline-hints' }
|
18
18
|
|
19
|
+
- if display_page_layouts?
|
20
|
+
= f.input :layout, as: :select, collection: options_for_page_layouts, include_blank: false
|
21
|
+
|
19
22
|
= f.inputs name: :seo, class: "inputs foldable #{'folded' if inputs_folded?(@page)}" do
|
20
23
|
|
21
24
|
= f.input :seo_title
|
@@ -29,6 +32,10 @@
|
|
29
32
|
- if can?(:customize, @page)
|
30
33
|
= f.input :handle
|
31
34
|
|
35
|
+
= f.input :is_layout, as: :'Locomotive::Toggle', input_html: { class: 'simple-toggle' }
|
36
|
+
|
37
|
+
= f.input :allow_layout, as: :'Locomotive::Toggle', input_html: { class: 'simple-toggle' }
|
38
|
+
|
32
39
|
= f.input :response_type, as: :select, collection: options_for_page_response_type, include_blank: false
|
33
40
|
|
34
41
|
= f.input :templatized, as: :'Locomotive::Toggle', style: "#{'display: none' if @page.redirect? || @page.templatized_from_parent?}"
|
@@ -51,7 +58,7 @@
|
|
51
58
|
|
52
59
|
= f.input :cache_strategy, as: :select, collection: options_for_page_cache_strategy, include_blank: false, wrapper_html: { style: "#{'display: none' if @page.redirect?}" }
|
53
60
|
|
54
|
-
- if can?(:customize, @page)
|
61
|
+
- if can?(:customize, @page) && @page.layout.nil?
|
55
62
|
= f.inputs name: :raw_template, class: "inputs foldable #{'folded' if inputs_folded?(@page)}" do
|
56
63
|
|
57
64
|
= f.input :raw_template, as: :'Locomotive::Code', main_locale_template_url: page_main_template_path(@page)
|
@@ -155,6 +155,7 @@ en:
|
|
155
155
|
delete_file: delete
|
156
156
|
cancel: cancel
|
157
157
|
default_block: Default
|
158
|
+
no_layout: Do not use a layout
|
158
159
|
cache_strategy:
|
159
160
|
none: None
|
160
161
|
simple: Simple
|
@@ -303,6 +304,7 @@ en:
|
|
303
304
|
category_noname: "No name"
|
304
305
|
latest_entries: "Latest entries"
|
305
306
|
updated_at: "Updated at"
|
307
|
+
search_placeholder: "Enter your search keywords here"
|
306
308
|
list:
|
307
309
|
no_items: "There are no entries for now. Just click <a href=\"%{url}\">here</a> to create the first one."
|
308
310
|
new:
|
@@ -304,6 +304,7 @@ fr:
|
|
304
304
|
category_noname: "Pas de nom"
|
305
305
|
latest_entries: "Eléments récents"
|
306
306
|
updated_at: "Mis à jour le"
|
307
|
+
search_placeholder: "Tapez votre recherche ici"
|
307
308
|
list:
|
308
309
|
no_entries: "Il n'existe pas d'éléments. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>"
|
309
310
|
new:
|
@@ -68,6 +68,8 @@ en:
|
|
68
68
|
seo_title: "Define a page title which should be used as the value for the title tag in the head section. Leave it empty if you want to use the default value from the site settings."
|
69
69
|
meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma."
|
70
70
|
meta_description: "Overrides the site's meta description used within the head tag of the page."
|
71
|
+
is_layout: "If true, this page can used as a layout for other pages."
|
72
|
+
allow_layout: "Let authors change or not the layout of that page."
|
71
73
|
snippet:
|
72
74
|
slug: "You need to know it in order to insert the snippet inside a page"
|
73
75
|
site:
|
@@ -105,6 +107,7 @@ en:
|
|
105
107
|
name: "We suggest you to type the plural form of the model. Ex: Projects, Recipes, Posts, Articles, ...etc"
|
106
108
|
slug: "It will be used as the name of the collection in the liquid templates. Ex: <span class='code'>{{ contents.my_projects }}</span>"
|
107
109
|
raw_item_template: "You can customize the text displayed for each item in the list. Simply use Liquid. Ex: <span class='code'>{{ entry.name }})</span>"
|
110
|
+
filter_fields: "If not empty, a filter bar will be displayed on the page listing the entries. The entries will be then filtered by the field(s) selected in the select box above."
|
108
111
|
public_submission_enabled: "It is used to let people from outside to create new entries (example: messages in a contact form)"
|
109
112
|
public_submission_accounts: "If the public submission option is enabled and for each entry created, sends a notification email to the accounts listed above."
|
110
113
|
"custom_fields/field":
|
data/config/routes.rb
CHANGED
@@ -67,13 +67,15 @@ Rails.application.routes.draw do
|
|
67
67
|
|
68
68
|
match 'documentation' => 'documentation#show'
|
69
69
|
|
70
|
+
match 'version' => 'version#show'
|
71
|
+
|
70
72
|
resources :tokens, only: [:create, :destroy]
|
71
73
|
|
72
74
|
resource :current_site, controller: 'current_site', only: [:show, :update, :destroy]
|
73
75
|
|
74
76
|
resources :memberships, only: [:index, :show, :create, :update, :destroy]
|
75
77
|
|
76
|
-
resource :my_account, controller: 'my_account', only: :show
|
78
|
+
resource :my_account, controller: 'my_account', only: [:show, :create, :update]
|
77
79
|
|
78
80
|
with_options only: [:index, :show, :create, :update, :destroy] do |api|
|
79
81
|
|
@@ -87,7 +89,9 @@ Rails.application.routes.draw do
|
|
87
89
|
|
88
90
|
api.resources :content_types
|
89
91
|
|
90
|
-
api.resources :content_entries, path: 'content_types/:slug/entries'
|
92
|
+
api.resources :content_entries, path: 'content_types/:slug/entries' do
|
93
|
+
delete :index, on: :collection, action: :destroy_all
|
94
|
+
end
|
91
95
|
|
92
96
|
api.resources :theme_assets
|
93
97
|
|
@@ -19,6 +19,7 @@ Feature: Content Entries
|
|
19
19
|
| Logo | file | false | |
|
20
20
|
| Client | belongs_to | false | Clients |
|
21
21
|
And I have "code, design" as "Type" values of the "Projects" model
|
22
|
+
And I have the "Projects" entries ordered by the "Name" field
|
22
23
|
And I have a custom model named "Workers" with
|
23
24
|
| label | type | required |
|
24
25
|
| Name | string | true |
|
@@ -48,6 +49,18 @@ Feature: Content Entries
|
|
48
49
|
| 4f832c2cb0d86d3f42fffff0 | p1 | first | code | false | 2012-07-01 | logo1.jpg |
|
49
50
|
| 4f832c2cb0d86d3f42fffff1 | p2 | 2nd | design | true | 2012-11-30 | logo1.jpg |
|
50
51
|
|
52
|
+
# paginating the content entries
|
53
|
+
Scenario: Paginating content entries
|
54
|
+
When I do an API GET request to content_types/projects/entries.json with:
|
55
|
+
"""
|
56
|
+
{
|
57
|
+
"page": 1,
|
58
|
+
"per_page": 1
|
59
|
+
}
|
60
|
+
"""
|
61
|
+
Then the JSON response should be an array
|
62
|
+
And the JSON response should have 1 entries
|
63
|
+
|
51
64
|
# create content entry
|
52
65
|
|
53
66
|
Scenario: Creating new project
|
@@ -71,15 +84,15 @@ Feature: Content Entries
|
|
71
84
|
Then the JSON response should be an array
|
72
85
|
And the JSON response should have 3 entries
|
73
86
|
And the JSON should have the following:
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
And the JSON at "
|
87
|
+
| 0/name | "Project 3" |
|
88
|
+
| 0/desc | "The third" |
|
89
|
+
| 0/type | "code" |
|
90
|
+
| 0/started | false |
|
91
|
+
| 0/due | "06/01/2012" |
|
92
|
+
| 0/workers/0 | "w1" |
|
93
|
+
| 0/workers/1 | "w3" |
|
94
|
+
| 0/client | "c1" |
|
95
|
+
And the JSON at "0/logo" should match /logo2.jpg$/
|
83
96
|
And the response content type should match /application\/json/
|
84
97
|
|
85
98
|
Scenario: Updating existing project
|
@@ -35,7 +35,7 @@ Scenario: Add a new site with chosen locale
|
|
35
35
|
Scenario: Change timezone of site
|
36
36
|
Given I am an authenticated user
|
37
37
|
When I go to the site settings
|
38
|
-
And I select "(GMT+
|
38
|
+
And I select "(GMT+03:00) Moscow" from "Timezone"
|
39
39
|
Then I press "Save"
|
40
40
|
Then I should see "My site was successfully updated." in the html code
|
41
41
|
|
@@ -12,11 +12,13 @@ Background:
|
|
12
12
|
| Body | string | false |
|
13
13
|
| Hidden | boolean | false |
|
14
14
|
| Published at | date | false |
|
15
|
+
| Category | select | false |
|
16
|
+
And I have "Design, Development" as "Category" values of the "Articles" model
|
15
17
|
And I have entries for "Articles" with
|
16
|
-
| title | body | published_at | hidden |
|
17
|
-
| Hello world | Lorem ipsum | 2015-01-01 | false |
|
18
|
-
| Lorem ipsum | Lorem ipsum... | 2013-03-23 | false |
|
19
|
-
| Yadi Yada | Lorem ipsum... | 2013-03-23 | true |
|
18
|
+
| title | body | published_at | category | hidden |
|
19
|
+
| Hello world | Lorem ipsum | 2015-01-01 | Development | false |
|
20
|
+
| Lorem ipsum | Lorem ipsum... | 2013-03-23 | Development | false |
|
21
|
+
| Yadi Yada | Lorem ipsum... | 2013-03-23 | Design | true |
|
20
22
|
|
21
23
|
Scenario: List all of them
|
22
24
|
Given a page named "my-articles" with the template:
|
@@ -29,6 +31,19 @@ Scenario: List all of them
|
|
29
31
|
Hello world, Lorem ipsum, Yadi Yada
|
30
32
|
"""
|
31
33
|
|
34
|
+
Scenario: Filter by a select field
|
35
|
+
Given a page named "my-articles" with the template:
|
36
|
+
"""
|
37
|
+
{% with_scope category: 'Development' %}
|
38
|
+
{% for article in contents.articles %}{{ article.title }}, {% endfor %}
|
39
|
+
{% endwith_scope %}
|
40
|
+
"""
|
41
|
+
When I view the rendered page at "/my-articles"
|
42
|
+
Then the rendered output should look like:
|
43
|
+
"""
|
44
|
+
Hello world, Lorem ipsum
|
45
|
+
"""
|
46
|
+
|
32
47
|
Scenario: Filter by a boolean
|
33
48
|
Given a page named "my-articles" with the template:
|
34
49
|
"""
|
@@ -66,4 +81,4 @@ Scenario: Filter with regexp
|
|
66
81
|
Then the rendered output should look like:
|
67
82
|
"""
|
68
83
|
Hello world, Yadi Yada
|
69
|
-
"""
|
84
|
+
"""
|
@@ -126,4 +126,10 @@ end
|
|
126
126
|
Given(/^I click on the (\d+)[a-z]+ required flag$/) do |nth|
|
127
127
|
find(".custom-field:nth-child(#{nth}) .required-input .switchHandle").click
|
128
128
|
sleep(0.1)
|
129
|
+
end
|
130
|
+
|
131
|
+
Given(/^I have the "(.*?)" entries ordered by the "(.*?)" field$/) do |name, field|
|
132
|
+
content_type = Locomotive::ContentType.where(name: name).first
|
133
|
+
field = content_type.entries_custom_fields.detect { |f| f.label == field }
|
134
|
+
content_type.update_attribute :order_by, field.name
|
129
135
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# Use this hook to configure devise mailer, warden hooks and so forth. The first
|
2
2
|
# four configuration values can also be set straight in your models.
|
3
3
|
Devise.setup do |config|
|
4
|
-
config.secret_key = "d9eb5171c59a4c817f68b0de27b8c1e340c2341b52cdbc60d3083d4e8958532" \
|
5
|
-
"18dcc5f589cafde048faec956b61f864b9b5513ff9ce29bf9e5d58b0f234f8e3b"
|
6
4
|
|
7
5
|
# ==> Mailer Configuration
|
8
6
|
# Configure the e-mail address which will be shown in Devise::Mailer,
|
@@ -7,6 +7,7 @@ require 'locomotive/carrierwave/patches'
|
|
7
7
|
# register missing mime types
|
8
8
|
EXTENSIONS[:eot] = 'application/vnd.ms-fontobject'
|
9
9
|
EXTENSIONS[:woff] = 'application/x-woff'
|
10
|
+
EXTENSIONS[:woff2] = 'application/x-woff2'
|
10
11
|
EXTENSIONS[:otf] = 'application/octet-stream'
|
11
12
|
|
12
13
|
# Allow retina images
|
@@ -25,7 +25,7 @@ module Locomotive
|
|
25
25
|
pdf: ['application/pdf', 'application/x-pdf'],
|
26
26
|
stylesheet: ['text/css'],
|
27
27
|
javascript: ['text/javascript', 'text/js', 'application/x-javascript', 'application/javascript', 'text/x-component'],
|
28
|
-
font: [/^application\/.*font/, 'application/x-font-ttf', 'application/vnd.ms-fontobject', 'image/svg+xml', 'application/x-woff', 'application/x-font-truetype', 'application/x-font-woff']
|
28
|
+
font: [/^application\/.*font/, 'application/x-font-ttf', 'application/vnd.ms-fontobject', 'image/svg+xml', 'application/x-woff', 'application/x-woff2', 'application/x-font-truetype', 'application/x-font-woff', 'application/x-font-woff2']
|
29
29
|
}
|
30
30
|
end
|
31
31
|
|
@@ -7,10 +7,12 @@ module Locomotive
|
|
7
7
|
include ::HTTParty
|
8
8
|
|
9
9
|
def self.consume(url, options = {})
|
10
|
-
options[:
|
10
|
+
options[:method] = :get if options[:method].nil?
|
11
11
|
|
12
12
|
options.delete(:format) if options[:format] == 'default'
|
13
13
|
|
14
|
+
path = extract_path(url, options)
|
15
|
+
|
14
16
|
# auth ?
|
15
17
|
username, password = options.delete(:username), options.delete(:password)
|
16
18
|
options[:basic_auth] = { username: username, password: password } if username
|
@@ -18,25 +20,29 @@ module Locomotive
|
|
18
20
|
self.perform_request_to(path, options)
|
19
21
|
end
|
20
22
|
|
21
|
-
def self.
|
22
|
-
url
|
23
|
+
def self.extract_path(url, options)
|
24
|
+
url = HTTParty.normalize_base_uri(url)
|
25
|
+
uri = URI.parse(url)
|
26
|
+
params = Rack::Utils.parse_nested_query(uri.query)
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
base_uri = "#{uri.scheme}://#{uri.host}"
|
27
|
-
base_uri += ":#{uri.port}" if uri.port != 80
|
28
|
+
key = options[:method].to_sym == :post ? :body : :query
|
29
|
+
options[key] = params unless params.blank?
|
28
30
|
|
29
|
-
|
31
|
+
(uri.path.blank? ? '/' : uri.path).tap do
|
32
|
+
uri.query = nil; uri.path = ''
|
33
|
+
options[:base_uri] = uri.to_s
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def self.perform_request_to(path, options)
|
33
|
-
# [DEBUG]
|
38
|
+
# [DEBUG]
|
39
|
+
# puts "[WebService] consuming #{path}, #{options.inspect}"
|
34
40
|
|
35
41
|
# sanitize the options
|
36
42
|
options[:format] = options[:format].gsub(/[\'\"]/, '').to_sym if options.has_key?(:format)
|
37
43
|
options[:headers] = { 'User-Agent' => 'LocomotiveCMS' } if options[:with_user_agent]
|
38
44
|
|
39
|
-
response = self.
|
45
|
+
response = self.send(options.delete(:method), path, options)
|
40
46
|
parsed_response = response.parsed_response
|
41
47
|
|
42
48
|
if response.code == 200
|
@@ -52,4 +58,4 @@ module Locomotive
|
|
52
58
|
|
53
59
|
end
|
54
60
|
end
|
55
|
-
end
|
61
|
+
end
|