landable 1.13.2 → 1.14.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.
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +7 -1
- data/Gemfile +3 -0
- data/app/controllers/landable/api/access_tokens_controller.rb +19 -1
- data/app/controllers/landable/api/pages_controller.rb +1 -1
- data/app/controllers/landable/api/templates_controller.rb +3 -3
- data/app/models/landable/access_token.rb +25 -2
- data/app/models/landable/author.rb +16 -2
- data/app/models/landable/page.rb +1 -1
- data/app/models/landable/template.rb +4 -2
- data/app/models/landable/template_revision.rb +1 -0
- data/app/responders/landable/page_render_responder.rb +1 -3
- data/app/serializers/landable/access_token_serializer.rb +1 -1
- data/app/serializers/landable/author_serializer.rb +1 -1
- data/app/serializers/landable/template_serializer.rb +5 -0
- data/app/services/landable/authentication_service.rb +1 -1
- data/db/migrate/20130510221424_create_landable_schema.rb +10 -10
- data/db/migrate/20150610999999_add_permissions_to_access_tokens.rb +6 -0
- data/db/migrate/20150728195345_add_category_column_to_templates.rb +13 -0
- data/doc/schema/access_token.json +4 -0
- data/doc/schema/author.json +12 -0
- data/doc/schema/permissions.json +21 -0
- data/doc/schema/template.json +4 -0
- data/doc/schema/template_revision.json +4 -0
- data/features/api/access_tokens.feature +2 -2
- data/features/step_definitions/core_api_steps.rb +3 -3
- data/features/step_definitions/factory_steps.rb +4 -0
- data/features/support/env.rb +1 -1
- data/landable.gemspec +3 -2
- data/lib/landable.rb +4 -2
- data/lib/landable/configuration.rb +58 -1
- data/lib/landable/traffic/tracker.rb +17 -17
- data/lib/landable/version.rb +2 -2
- data/spec/controllers/landable/api/configuration_controller_spec.rb +6 -0
- data/spec/controllers/landable/api_controller_spec.rb +1 -1
- data/spec/dummy/bin/rails +1 -1
- data/spec/dummy/config.ru +1 -1
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/dummy/config/initializers/landable.rb +1 -1
- data/spec/dummy/etc/audit_flags.yml +1 -0
- data/spec/dummy/etc/ldap.yml +17 -0
- data/spec/dummy/etc/sandiego.yml +85 -0
- data/spec/dummy/etc/sitemap_extra.yml +12 -0
- data/spec/factories/authors.rb +18 -2
- data/spec/models/landable/access_token_spec.rb +2 -1
- data/spec/models/landable/page_spec.rb +1 -1
- data/spec/services/landable/authentication_service_spec.rb +1 -1
- data/spec/services/landable/render_service_spec.rb +1 -1
- metadata +31 -4
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,13 @@
|
|
2
2
|
|
3
3
|
See README.md before updating this file.
|
4
4
|
|
5
|
-
## Unreleased [#](https://github.com/enova/landable/compare/v1.
|
5
|
+
## Unreleased [#](https://github.com/enova/landable/compare/v1.14.0...master)
|
6
|
+
|
7
|
+
## 1.14.0 [#](https://github.com/enova/landable/compare/v1.13.2...v1.14.0)
|
8
|
+
* Feature: Support permissions for an author
|
9
|
+
* Feature: Support Figgy configuration options
|
10
|
+
* Add Figgy and Responders gems
|
11
|
+
* Database updates
|
6
12
|
|
7
13
|
## 1.13.2 [#](https://github.com/enova/landable/compare/v1.13.1...v1.13.2)
|
8
14
|
* Bugfix: Fix landable traffic errors
|
data/Gemfile
CHANGED
@@ -7,6 +7,9 @@ gemspec
|
|
7
7
|
# concerned only with compatibility (see bin/test)
|
8
8
|
gem 'rails', ENV['RAILS_VERSION'] if ENV.key? 'RAILS_VERSION'
|
9
9
|
|
10
|
+
# handle configurations!
|
11
|
+
gem 'figgy', '~> 1.1.0'
|
12
|
+
|
10
13
|
# development/test dependencies, and anything else that doesn't belong or fit
|
11
14
|
# in the gemspec
|
12
15
|
group :test do
|
@@ -11,9 +11,12 @@ module Landable
|
|
11
11
|
|
12
12
|
def create
|
13
13
|
ident = AuthenticationService.call(asset_token_params[:username], asset_token_params[:password])
|
14
|
+
|
14
15
|
author = RegistrationService.call(ident)
|
15
16
|
|
16
|
-
|
17
|
+
permissions = determine_permissions(ident[:groups])
|
18
|
+
|
19
|
+
respond_with AccessToken.create!(author: author, permissions: permissions), status: :created
|
17
20
|
rescue Landable::AuthenticationFailedError
|
18
21
|
head :unauthorized
|
19
22
|
end
|
@@ -42,6 +45,21 @@ module Landable
|
|
42
45
|
def asset_token_params
|
43
46
|
params.require(:access_token).permit(:username, :password)
|
44
47
|
end
|
48
|
+
|
49
|
+
def determine_permissions(user_groups)
|
50
|
+
yaml_groups = Landable.configuration['ldap'][:permissions]
|
51
|
+
permissions_groups = user_groups.select { |group| yaml_groups.include?(group) }
|
52
|
+
|
53
|
+
user_permissions = {}
|
54
|
+
permissions_groups.each do |group|
|
55
|
+
group_permissions = yaml_groups[group].keys
|
56
|
+
group_permissions.each do |perm|
|
57
|
+
user_permissions[perm] ||= yaml_groups[group][perm]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
user_permissions
|
62
|
+
end
|
45
63
|
end
|
46
64
|
end
|
47
65
|
end
|
@@ -51,9 +51,9 @@ module Landable
|
|
51
51
|
# custom methods
|
52
52
|
def preview
|
53
53
|
template = Template.new(template_params)
|
54
|
-
theme
|
54
|
+
theme = Theme.most_used_on_pages
|
55
55
|
|
56
|
-
page
|
56
|
+
page = Page.example(theme: theme, body: template.body)
|
57
57
|
|
58
58
|
content = generate_preview_for(page)
|
59
59
|
|
@@ -72,7 +72,7 @@ module Landable
|
|
72
72
|
|
73
73
|
def template_params
|
74
74
|
params.require(:template).permit(:id, :name, :body, :description, :thumbnail_url,
|
75
|
-
:slug, :is_layout, :is_publishable,
|
75
|
+
:slug, :is_layout, :is_publishable, :category_id,
|
76
76
|
audit_flags: [])
|
77
77
|
end
|
78
78
|
|
@@ -2,19 +2,42 @@ module Landable
|
|
2
2
|
class AccessToken < ActiveRecord::Base
|
3
3
|
include Landable::TableName
|
4
4
|
|
5
|
+
# Maximum token age, in hours
|
6
|
+
MAX_AGE = ((Landable.configuration['ldap'] &&
|
7
|
+
Landable.configuration['ldap'][:access_token_max_age]) || 8).hours
|
8
|
+
|
5
9
|
belongs_to :author
|
6
10
|
validates_presence_of :author_id
|
7
11
|
validates_presence_of :expires_at
|
12
|
+
validates_presence_of :permissions
|
8
13
|
|
9
14
|
before_validation do |token|
|
10
|
-
token.expires_at ||=
|
15
|
+
token.expires_at ||= expiration
|
11
16
|
end
|
12
17
|
|
13
18
|
scope :fresh, -> { where('expires_at > ?', Time.zone.now) }
|
14
19
|
scope :expired, -> { where('expires_at <= ?', Time.zone.now) }
|
15
20
|
|
16
21
|
def refresh!
|
17
|
-
update_column :expires_at,
|
22
|
+
update_column :expires_at, expiration
|
23
|
+
end
|
24
|
+
|
25
|
+
def can_publish?
|
26
|
+
permissions['publish'] == 'true'
|
27
|
+
end
|
28
|
+
|
29
|
+
def can_edit?
|
30
|
+
permissions['edit'] == 'true'
|
31
|
+
end
|
32
|
+
|
33
|
+
def can_read?
|
34
|
+
permissions['read'] == 'true'
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def expiration
|
40
|
+
MAX_AGE.from_now
|
18
41
|
end
|
19
42
|
end
|
20
43
|
end
|
@@ -5,9 +5,23 @@ module Landable
|
|
5
5
|
|
6
6
|
def self.authenticate!(username, token_id)
|
7
7
|
author = where(username: username).first
|
8
|
-
return unless author
|
9
|
-
return unless author.access_tokens.fresh.exists?(token_id)
|
8
|
+
return unless author && author.access_tokens.fresh.exists?(token_id)
|
10
9
|
author
|
11
10
|
end
|
11
|
+
|
12
|
+
def can_read
|
13
|
+
token = access_tokens.fresh.last
|
14
|
+
token.present? && token.can_read?
|
15
|
+
end
|
16
|
+
|
17
|
+
def can_edit
|
18
|
+
token = access_tokens.fresh.last
|
19
|
+
token.present? && token.can_edit?
|
20
|
+
end
|
21
|
+
|
22
|
+
def can_publish
|
23
|
+
token = access_tokens.fresh.last
|
24
|
+
token.present? && token.can_publish?
|
25
|
+
end
|
12
26
|
end
|
13
27
|
end
|
data/app/models/landable/page.rb
CHANGED
@@ -30,7 +30,7 @@ module Landable
|
|
30
30
|
validates :redirect_url, url: true, allow_blank: true
|
31
31
|
validate :hero_asset_existence
|
32
32
|
|
33
|
-
belongs_to :theme, class_name: 'Landable::Theme',
|
33
|
+
belongs_to :theme, class_name: 'Landable::Theme', inverse_of: :pages, counter_cache: true
|
34
34
|
belongs_to :published_revision, class_name: 'Landable::PageRevision'
|
35
35
|
belongs_to :category, class_name: 'Landable::Category'
|
36
36
|
belongs_to :updated_by_author, class_name: 'Landable::Author'
|
@@ -13,14 +13,15 @@ module Landable
|
|
13
13
|
before_save :slug_has_no_spaces
|
14
14
|
|
15
15
|
belongs_to :published_revision, class_name: 'Landable::TemplateRevision'
|
16
|
+
belongs_to :category, class_name: 'Landable::Category'
|
16
17
|
has_many :audits, class_name: 'Landable::Audit', as: :auditable
|
17
18
|
has_many :revisions, class_name: 'Landable::TemplateRevision'
|
18
19
|
|
19
|
-
has_and_belongs_to_many :pages,
|
20
|
+
has_and_belongs_to_many :pages, join_table: Page.templates_join_table_name
|
20
21
|
|
21
22
|
delegate :count, to: :pages, prefix: true # Returns how many Pages a Template lives in!
|
22
23
|
|
23
|
-
before_save lambda
|
24
|
+
before_save lambda { |template|
|
24
25
|
template.is_publishable = true unless template.published_revision_id_changed?
|
25
26
|
}
|
26
27
|
|
@@ -61,6 +62,7 @@ module Landable
|
|
61
62
|
self.name = revision.name
|
62
63
|
self.body = revision.body
|
63
64
|
self.description = revision.description
|
65
|
+
self.category_id = revision.category_id
|
64
66
|
self.slug = revision.slug
|
65
67
|
|
66
68
|
save!
|
@@ -4,9 +4,7 @@ module Landable
|
|
4
4
|
page = resource
|
5
5
|
|
6
6
|
case page.status_code
|
7
|
-
when 200
|
8
|
-
content_type: page.content_type,
|
9
|
-
layout: (page.theme.try(:file) || false)
|
7
|
+
when 200 then render text: RenderService.call(page, preview: options[:preview], responder: self), content_type: page.content_type, layout: (page.theme.try(:file) || false)
|
10
8
|
when 301, 302 then redirect_to page.redirect_url, status: page.status_code
|
11
9
|
else fail page.error
|
12
10
|
end
|
@@ -25,8 +25,8 @@ class CreateLandableSchema < Landable::Migration
|
|
25
25
|
|
26
26
|
create_table "#{Landable.configuration.database_schema_prefix}landable.status_codes", id: :uuid, primary_key: :status_code_id do |t|
|
27
27
|
t.uuid :status_code_category_id, null: false
|
28
|
-
t.integer :code,
|
29
|
-
t.text :description,
|
28
|
+
t.integer :code, null: false, limit: 2 # Creates as smallint
|
29
|
+
t.text :description, null: false
|
30
30
|
end
|
31
31
|
|
32
32
|
execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_status_codes__u_code ON #{Landable.configuration.database_schema_prefix}landable.status_codes(code)"
|
@@ -56,7 +56,7 @@ class CreateLandableSchema < Landable::Migration
|
|
56
56
|
t.text :body, null: false
|
57
57
|
t.text :description, null: false
|
58
58
|
t.text :thumbnail_url
|
59
|
-
t.boolean :is_layout,
|
59
|
+
t.boolean :is_layout, null: false, default: false
|
60
60
|
t.timestamps
|
61
61
|
end
|
62
62
|
|
@@ -123,7 +123,7 @@ class CreateLandableSchema < Landable::Migration
|
|
123
123
|
## access_tokens
|
124
124
|
|
125
125
|
create_table "#{Landable.configuration.database_schema_prefix}landable.access_tokens", id: :uuid, primary_key: :access_token_id do |t|
|
126
|
-
t.uuid :author_id,
|
126
|
+
t.uuid :author_id, null: false
|
127
127
|
t.timestamp :expires_at, null: false
|
128
128
|
t.timestamps
|
129
129
|
end
|
@@ -235,8 +235,8 @@ class CreateLandableSchema < Landable::Migration
|
|
235
235
|
## asset associations table
|
236
236
|
|
237
237
|
create_table "#{Landable.configuration.database_schema_prefix}landable.page_assets", id: :uuid, primary_key: :page_asset_id do |t|
|
238
|
-
t.uuid :page_id,
|
239
|
-
t.uuid :asset_id,
|
238
|
+
t.uuid :page_id, null: false
|
239
|
+
t.uuid :asset_id, null: false
|
240
240
|
end
|
241
241
|
|
242
242
|
execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_page_assets__u_page_id_asset_id ON #{Landable.configuration.database_schema_prefix}landable.page_assets (page_id, asset_id)"
|
@@ -244,8 +244,8 @@ class CreateLandableSchema < Landable::Migration
|
|
244
244
|
execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_assets ADD CONSTRAINT asset_id_fk FOREIGN KEY (asset_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.assets(asset_id)"
|
245
245
|
|
246
246
|
create_table "#{Landable.configuration.database_schema_prefix}landable.page_revision_assets", id: :uuid, primary_key: :page_revision_asset_id do |t|
|
247
|
-
t.uuid :page_revision_id,
|
248
|
-
t.uuid :asset_id,
|
247
|
+
t.uuid :page_revision_id, null: false
|
248
|
+
t.uuid :asset_id, null: false
|
249
249
|
end
|
250
250
|
|
251
251
|
execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_page_revision_assets__u_page_revision_id_asset_id ON #{Landable.configuration.database_schema_prefix}landable.page_revision_assets (page_revision_id, asset_id)"
|
@@ -253,8 +253,8 @@ class CreateLandableSchema < Landable::Migration
|
|
253
253
|
execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_revision_assets ADD CONSTRAINT asset_id_fk FOREIGN KEY (asset_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.assets(asset_id)"
|
254
254
|
|
255
255
|
create_table "#{Landable.configuration.database_schema_prefix}landable.theme_assets", id: :uuid, primary_key: :theme_asset_id do |t|
|
256
|
-
t.uuid :theme_id,
|
257
|
-
t.uuid :asset_id,
|
256
|
+
t.uuid :theme_id, null: false
|
257
|
+
t.uuid :asset_id, null: false
|
258
258
|
end
|
259
259
|
|
260
260
|
execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_theme_assets__u_theme_id_asset_id ON #{Landable.configuration.database_schema_prefix}landable.theme_assets (theme_id, asset_id)"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AddCategoryColumnToTemplates < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
schema_name = "#{Landable.configuration.database_schema_prefix}landable"
|
4
|
+
|
5
|
+
# add category_id to our templates table.
|
6
|
+
add_column "#{schema_name}.templates", :category_id, :uuid
|
7
|
+
execute "ALTER TABLE #{schema_name}.templates ADD FOREIGN KEY (category_id) REFERENCES #{schema_name}.categories(category_id)"
|
8
|
+
|
9
|
+
# add category_id to our template_revisions table.
|
10
|
+
add_column "#{schema_name}.template_revisions", :category_id, :uuid
|
11
|
+
execute "ALTER TABLE #{schema_name}.template_revisions ADD FOREIGN KEY (category_id) REFERENCES #{schema_name}.categories(category_id)"
|
12
|
+
end
|
13
|
+
end
|
data/doc/schema/author.json
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"title": "Permissions",
|
3
|
+
"description": "Permissions for authors",
|
4
|
+
"type": "object",
|
5
|
+
"additionalProperties": false,
|
6
|
+
"required": ["read", "edit", "publish"],
|
7
|
+
|
8
|
+
"properties": {
|
9
|
+
"read": {
|
10
|
+
"type": "string"
|
11
|
+
},
|
12
|
+
|
13
|
+
"edit": {
|
14
|
+
"type": "string"
|
15
|
+
},
|
16
|
+
|
17
|
+
"publish": {
|
18
|
+
"type": "string"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
data/doc/schema/template.json
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
Feature: Access Tokens API
|
3
3
|
|
4
4
|
Scenario: Responding with a fresh access token
|
5
|
-
Given an author "someone"
|
5
|
+
Given an author "someone" without access tokens
|
6
6
|
And "someone" has an unexpired access token
|
7
7
|
When I POST to "/api/access_tokens" with:
|
8
8
|
"""
|
@@ -29,7 +29,7 @@ Feature: Access Tokens API
|
|
29
29
|
And the author "someone" should have 1 access token
|
30
30
|
|
31
31
|
Scenario: Reusing a pre-existing author record
|
32
|
-
Given an author "someone"
|
32
|
+
Given an author "someone" without access tokens
|
33
33
|
When I POST to "/api/access_tokens" with:
|
34
34
|
"""
|
35
35
|
{ "access_token": { "username": "someone", "password": "anything" } }
|
@@ -15,7 +15,7 @@ module Landable
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def current_author
|
18
|
-
@current_author ||= create :
|
18
|
+
@current_author ||= create :author_without_access_tokens
|
19
19
|
end
|
20
20
|
|
21
21
|
def current_access_token
|
@@ -46,11 +46,11 @@ Before '@api', '~@no-api-auth' do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
Given 'I accept HTML' do
|
49
|
-
header 'Accept',
|
49
|
+
header 'Accept', 'text/html'
|
50
50
|
end
|
51
51
|
|
52
52
|
Given 'I accept JSON' do
|
53
|
-
header 'Accept',
|
53
|
+
header 'Accept', 'application/json'
|
54
54
|
end
|
55
55
|
|
56
56
|
Given 'my API requests include a valid access token' do
|
@@ -18,6 +18,10 @@ Given(/^an author "([^"]+)"$/) do |username|
|
|
18
18
|
create :author, username: username
|
19
19
|
end
|
20
20
|
|
21
|
+
Given(/^an author "([^"]+)" without access tokens$/) do |username|
|
22
|
+
create :author_without_access_tokens, username: username
|
23
|
+
end
|
24
|
+
|
21
25
|
Given '"$username" has an unexpired access token' do |username|
|
22
26
|
create :access_token, author: Landable::Author.where(username: username).first!
|
23
27
|
end
|
data/features/support/env.rb
CHANGED
@@ -8,7 +8,7 @@ ENV['RAILS_ENV'] ||= 'test'
|
|
8
8
|
require 'simplecov'
|
9
9
|
SimpleCov.start 'rails'
|
10
10
|
|
11
|
-
require File.expand_path('../../../spec/dummy/config/environment.rb',
|
11
|
+
require File.expand_path('../../../spec/dummy/config/environment.rb', __FILE__)
|
12
12
|
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '../../../spec/dummy'
|
13
13
|
|
14
14
|
require 'cucumber/rails'
|
data/landable.gemspec
CHANGED
@@ -31,19 +31,20 @@ Gem::Specification.new do |gem|
|
|
31
31
|
gem.add_dependency 'rack-cors', '>= 0.2.7'
|
32
32
|
gem.add_dependency 'active_model_serializers', '0.8.3'
|
33
33
|
gem.add_dependency 'carrierwave'
|
34
|
-
gem.add_dependency 'liquid',
|
34
|
+
gem.add_dependency 'liquid', '~> 2.6.1'
|
35
35
|
gem.add_dependency 'fog'
|
36
36
|
gem.add_dependency 'rest-client'
|
37
37
|
gem.add_dependency 'builder'
|
38
38
|
gem.add_dependency 'lookup_by', '> 0.4.0'
|
39
39
|
gem.add_dependency 'highline'
|
40
|
+
gem.add_dependency 'figgy', '~> 1.1.0'
|
40
41
|
|
41
42
|
gem.add_development_dependency 'pg'
|
42
43
|
gem.add_development_dependency 'rspec-rails', '~> 2.14.2'
|
43
44
|
gem.add_development_dependency 'factory_girl_rails', '~> 4.2.0'
|
44
45
|
gem.add_development_dependency 'json-schema', '= 2.1.3'
|
45
46
|
gem.add_development_dependency 'rack-schema'
|
46
|
-
gem.add_development_dependency 'cucumber',
|
47
|
+
gem.add_development_dependency 'cucumber', '= 1.3.14'
|
47
48
|
gem.add_development_dependency 'database_cleaner'
|
48
49
|
gem.add_development_dependency 'simplecov'
|
49
50
|
gem.add_development_dependency 'valid_attribute'
|
data/lib/landable.rb
CHANGED
@@ -20,10 +20,12 @@ module Landable
|
|
20
20
|
autoload :Seeds, 'landable/seeds'
|
21
21
|
|
22
22
|
def self.configuration
|
23
|
-
@configuration ||= Configuration.new
|
23
|
+
@configuration ||= Configuration.new(@file_path)
|
24
24
|
end
|
25
25
|
|
26
|
-
def self.configure
|
26
|
+
def self.configure(path = nil)
|
27
|
+
@file_path = path
|
28
|
+
|
27
29
|
yield configuration if block_given?
|
28
30
|
configuration
|
29
31
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'figgy'
|
2
|
+
|
1
3
|
module Landable
|
2
|
-
class Configuration
|
4
|
+
class Configuration < HashWithIndifferentAccess
|
3
5
|
attr_accessor :api_url, :public_url, :amqp_configuration, :sitemap_host
|
4
6
|
attr_writer :api_namespace, :public_namespace
|
5
7
|
attr_writer :api_host, :public_host
|
@@ -13,6 +15,24 @@ module Landable
|
|
13
15
|
attr_writer :dnt_enabled, :amqp_event_mapping, :amqp_site_segment
|
14
16
|
attr_writer :amqp_service_enabled, :amqp_messaging_service
|
15
17
|
|
18
|
+
def initialize(config_path = nil)
|
19
|
+
begin
|
20
|
+
# let's keep this feature optional. Not all apps
|
21
|
+
# will be using external configs for landable
|
22
|
+
app_config = Figgy.build do |config_data|
|
23
|
+
config_data.root = config_path
|
24
|
+
|
25
|
+
config_data.define_overlay :default, nil
|
26
|
+
config_data.define_overlay(:environment) { Rails.env }
|
27
|
+
end
|
28
|
+
|
29
|
+
# map our new configs into our local object.
|
30
|
+
config_keys(config_path).each do |key|
|
31
|
+
self[key] = app_config[key] unless app_config[key].nil?
|
32
|
+
end
|
33
|
+
end unless config_path.nil?
|
34
|
+
end
|
35
|
+
|
16
36
|
def amqp_configuration
|
17
37
|
@amqp_configuration ||= {}
|
18
38
|
end
|
@@ -172,5 +192,42 @@ module Landable
|
|
172
192
|
@autorun = true
|
173
193
|
end
|
174
194
|
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
DOTFILE_MATCHER_REGEXP = /^\.[[[:alnum:]]\.]*$/
|
199
|
+
EXPECTED_FILETYPES = ['yml', 'yaml', 'json']
|
200
|
+
EXPECTED_FILETYPES_REGEXP = /\.(#{ EXPECTED_FILETYPES.join('|') })\z/
|
201
|
+
|
202
|
+
def config_keys(base_path)
|
203
|
+
files = Dir.entries(base_path)
|
204
|
+
keys = []
|
205
|
+
|
206
|
+
files = remove_dotfiles(files)
|
207
|
+
|
208
|
+
files.each do |filename|
|
209
|
+
filename = File.join(base_path, filename)
|
210
|
+
new_key = filename_to_key(filename)
|
211
|
+
|
212
|
+
if File.file?(filename)
|
213
|
+
keys.push(new_key)
|
214
|
+
elsif File.directory?(filename) && new_key == Rails.env
|
215
|
+
# only folders matching our environment!
|
216
|
+
keys = keys.concat(config_keys(filename))
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
keys.uniq
|
221
|
+
end
|
222
|
+
|
223
|
+
def filename_to_key(filename)
|
224
|
+
File.basename(filename).sub(EXPECTED_FILETYPES_REGEXP, '')
|
225
|
+
end
|
226
|
+
|
227
|
+
def remove_dotfiles(filelist)
|
228
|
+
filelist.delete_if do |filename|
|
229
|
+
!DOTFILE_MATCHER_REGEXP.match(File.basename(filename)).nil?
|
230
|
+
end
|
231
|
+
end
|
175
232
|
end
|
176
233
|
end
|
@@ -29,29 +29,29 @@ module Landable
|
|
29
29
|
ATTRIBUTION_KEYS = TRACKING_PARAMS.except('click_id').keys
|
30
30
|
|
31
31
|
TRACKING_PARAMS_TRANSFORM = {
|
32
|
-
'ad_type'
|
33
|
-
|
32
|
+
'ad_type' => { 'pe' => 'product_extensions',
|
33
|
+
'pla' => 'product_listing' },
|
34
34
|
|
35
35
|
'bid_match_type' => { 'bb' => 'bidded broad',
|
36
36
|
'bc' => 'bidded content',
|
37
37
|
'be' => 'bidded exact',
|
38
38
|
'bp' => 'bidded phrase' },
|
39
39
|
|
40
|
-
'device_type'
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
'match_type'
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
'network'
|
53
|
-
|
54
|
-
|
40
|
+
'device_type' => { 'c' => 'computer',
|
41
|
+
'm' => 'mobile',
|
42
|
+
't' => 'tablet' },
|
43
|
+
|
44
|
+
'match_type' => { 'b' => 'broad',
|
45
|
+
'c' => 'content',
|
46
|
+
'e' => 'exact',
|
47
|
+
'p' => 'phrase',
|
48
|
+
'std' => 'standard',
|
49
|
+
'adv' => 'advanced',
|
50
|
+
'cnt' => 'content' },
|
51
|
+
|
52
|
+
'network' => { 'g' => 'google_search',
|
53
|
+
's' => 'search_partner',
|
54
|
+
'd' => 'display_network' }
|
55
55
|
}.freeze
|
56
56
|
|
57
57
|
UUID_REGEX = /\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\Z/
|
data/lib/landable/version.rb
CHANGED
@@ -13,6 +13,12 @@ module Landable
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'renders the page as JSON' do
|
16
|
+
# pending 'This broken test requires refactoring.'
|
17
|
+
# this test cannot possibly pass given the state of the configuration object and controller.
|
18
|
+
# * The controller returns a json version of an object that wasn't initially even a Hash.
|
19
|
+
# * The new configuration object inherits Hash but 'audit_flags' gets lost in conversion
|
20
|
+
# to a JSON object because it is a static attribute of the Landable.configuration object.
|
21
|
+
|
16
22
|
make_request
|
17
23
|
# defined in Landable Dummy Initalizer
|
18
24
|
last_json['configurations'][0]['audit_flags'].should eq %w(loans apr)
|
@@ -162,7 +162,7 @@ describe Landable::ApiController, json: true do
|
|
162
162
|
controller.instance_variable_set :@resource, resource
|
163
163
|
end
|
164
164
|
|
165
|
-
let(:resource) {
|
165
|
+
let(:resource) { create :author }
|
166
166
|
|
167
167
|
it 'should set X-Landable-Media-Type' do
|
168
168
|
get :responder
|
data/spec/dummy/bin/rails
CHANGED
data/spec/dummy/config.ru
CHANGED
@@ -13,7 +13,7 @@ Dummy::Application.configure do
|
|
13
13
|
config.eager_load = false
|
14
14
|
|
15
15
|
# Configure static asset server for tests with Cache-Control for performance.
|
16
|
-
config.serve_static_files
|
16
|
+
config.serve_static_files = true
|
17
17
|
config.static_cache_control = 'public, max-age=3600'
|
18
18
|
|
19
19
|
# Show full error reports and disable caching.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'landable'
|
2
2
|
require Rails.root.join('lib', 'bunny_messaging_service.rb')
|
3
3
|
|
4
|
-
Landable.configure do |config|
|
4
|
+
Landable.configure(File.join(File.dirname(__FILE__), '..', '..', 'etc')) do |config|
|
5
5
|
config.api_namespace = '/api'
|
6
6
|
config.cors.origins = ['http://cors.test']
|
7
7
|
|
@@ -0,0 +1 @@
|
|
1
|
+
['loans', 'apr']
|
@@ -0,0 +1,17 @@
|
|
1
|
+
:host: adds.enova.com
|
2
|
+
:port: 636
|
3
|
+
:encryption: :simple_tls
|
4
|
+
:base: 'DC=enova,DC=com'
|
5
|
+
:permissions:
|
6
|
+
Read-Only:
|
7
|
+
read: 'true'
|
8
|
+
edit: 'false'
|
9
|
+
publish: 'false'
|
10
|
+
Editor:
|
11
|
+
read: 'true'
|
12
|
+
edit: 'true'
|
13
|
+
publish: 'false'
|
14
|
+
Publisher:
|
15
|
+
read: 'true'
|
16
|
+
edit: 'true'
|
17
|
+
publish: 'true'
|
@@ -0,0 +1,85 @@
|
|
1
|
+
enabled: true
|
2
|
+
rescue_errors: true
|
3
|
+
brand_code: 'US'
|
4
|
+
|
5
|
+
clients:
|
6
|
+
cnuapp_proxy:
|
7
|
+
domain: "www-us-trogdor-cnuapp.dev.enova.com" # For Trogdor AWS box
|
8
|
+
secure: true
|
9
|
+
ping: true
|
10
|
+
session_cookies:
|
11
|
+
- cnuwww_session_id
|
12
|
+
- _us_account_home_session
|
13
|
+
cnuapp:
|
14
|
+
domain: "api-us-trogdor-cnuapp.dev.enova.com" # For Trogdor AWS box
|
15
|
+
secure: true
|
16
|
+
identity:
|
17
|
+
default_base_url: "http://portal-us-trogdor-cnuapp.dev.enova.com" # For Trogdor AWS box
|
18
|
+
portfolio:
|
19
|
+
default_base_url: "http://portal-us-trogdor-cnuapp.dev.enova.com" # For Trogdor AWS box
|
20
|
+
|
21
|
+
features:
|
22
|
+
registration:
|
23
|
+
enabled: true
|
24
|
+
redirects:
|
25
|
+
new:
|
26
|
+
"/registration-step1.html": "/registration"
|
27
|
+
"/secure/customers/new2": "/registration/step2"
|
28
|
+
old:
|
29
|
+
"/registration": "/registration-step1.html"
|
30
|
+
"/registration/step2": "/secure/customers/new2"
|
31
|
+
|
32
|
+
filter_errors:
|
33
|
+
"is invalid": "Unfortunately there seems to be an issue with the information you've provided. For assistance, please contact our customer support team at"
|
34
|
+
"Could not save customer. Potential fraud; lead email does not match form email": "Unfortunately there seems to be an issue with the information you've provided. For assistance, please contact our customer support team at"
|
35
|
+
"Could not save customer": "Unfortunately there seems to be an issue with the information you've provided. For assistance, please contact our customer support team at"
|
36
|
+
|
37
|
+
pings:
|
38
|
+
"/registration": "/registration-step1.html"
|
39
|
+
"/registration/step2": "/secure/customers/new2"
|
40
|
+
|
41
|
+
registration:
|
42
|
+
title_options:
|
43
|
+
mr: Mr.
|
44
|
+
mrs: Mrs.
|
45
|
+
miss: Miss
|
46
|
+
ms: Ms.
|
47
|
+
other: Other
|
48
|
+
|
49
|
+
payment_frequency_options:
|
50
|
+
weekly: Weekly (e.g. Every Friday)
|
51
|
+
biweekly: Biweekly (e.g. Every other Friday)
|
52
|
+
twice_monthly: Twice monthly (ex. The 1st and 15th of each month)
|
53
|
+
specific_date: Monthly on a specific date (ex. 1st of the Month)
|
54
|
+
last_working_day: Monthly last day (ex. Last business day or last calendar day)
|
55
|
+
specific_day: Monthly on a specific weekday (ex. 3rd Wednesday of each month)
|
56
|
+
last_day: Monthly last weekday (ex. Last Tuesday of each month)
|
57
|
+
|
58
|
+
repayment_options:
|
59
|
+
ach_debit: bank_account_ach
|
60
|
+
remotely_created_checks: ecld
|
61
|
+
|
62
|
+
acquisition_source_options:
|
63
|
+
- TV Advert
|
64
|
+
- Radio Advert
|
65
|
+
- Moneysupermarket, Gocompare or Similar
|
66
|
+
- Google Results
|
67
|
+
- Friends/Family
|
68
|
+
- Facebook/Twitter
|
69
|
+
- Online Image/Video Ad
|
70
|
+
- Football Stadium
|
71
|
+
- Email
|
72
|
+
- SMS
|
73
|
+
- Other...
|
74
|
+
|
75
|
+
website_message:
|
76
|
+
header: "message"
|
77
|
+
body: "Due to the upcoming banking holiday, all requests to make changes for loans due on <span class='nobreak'>Nov 28 2014</span> must be received by 3:00 PM CST on <span class='nobreak'>Nov 25 2014.</span><br />All loans approved on Nov 26 2014 will generally be funded on Nov 28 2014."
|
78
|
+
start_date: 2014-11-20 00:00:01 -0600
|
79
|
+
end_date: 2014-11-27 23:59:59 -0600
|
80
|
+
|
81
|
+
ldap:
|
82
|
+
host: ldap.cashnetusa.com
|
83
|
+
port: 389
|
84
|
+
ssl: start_tls
|
85
|
+
base: 'ou=user,ou=jabber,ou=auth,dc=cashnetusa,dc=com'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Add extra URLs which aren't in publicist but should be included in sitemap.xml
|
2
|
+
# This file is replaced from cnu_config overlay so make changes there
|
3
|
+
|
4
|
+
- /
|
5
|
+
- /blog
|
6
|
+
- /forgot_password.html
|
7
|
+
- /login
|
8
|
+
- /new-customer-registration
|
9
|
+
- /newsroom
|
10
|
+
- /registration-step1.html
|
11
|
+
- /secure/auth/forgot_email
|
12
|
+
- /secure/auth/forgot_password
|
data/spec/factories/authors.rb
CHANGED
@@ -1,12 +1,28 @@
|
|
1
1
|
FactoryGirl.define do
|
2
|
+
factory :access_token, class: 'Landable::AccessToken' do
|
3
|
+
association :author, strategy: :create
|
4
|
+
permissions { { 'read' => 'true', 'edit' => 'true', 'publish' => 'true' } }
|
5
|
+
end
|
6
|
+
|
2
7
|
factory :author, class: 'Landable::Author' do
|
3
8
|
sequence(:username) { |n| "trogdor#{n}" }
|
4
9
|
sequence(:email) { |n| "trogdor#{n}@example.com" }
|
5
10
|
first_name 'Marley'
|
6
11
|
last_name 'Pants'
|
12
|
+
|
13
|
+
ignore do
|
14
|
+
tokens_count 1
|
15
|
+
end
|
16
|
+
|
17
|
+
after(:create) do |author, evaluator|
|
18
|
+
create_list(:access_token, evaluator.tokens_count, author: author)
|
19
|
+
end
|
7
20
|
end
|
8
21
|
|
9
|
-
factory :
|
10
|
-
|
22
|
+
factory :author_without_access_tokens, class: 'Landable::Author' do
|
23
|
+
sequence(:username) { |n| "trogdor#{n}" }
|
24
|
+
sequence(:email) { |n| "trogdor#{n}@example.com" }
|
25
|
+
first_name 'Marley'
|
26
|
+
last_name 'Pants'
|
11
27
|
end
|
12
28
|
end
|
@@ -6,7 +6,8 @@ module Landable
|
|
6
6
|
|
7
7
|
it 'generates an expiration timestamp before creation' do
|
8
8
|
author = create :author
|
9
|
-
|
9
|
+
permissions = { 'read' => 'true', 'edit' => 'true', 'publish' => 'true' }
|
10
|
+
token = AccessToken.create!(author: author, permissions: permissions)
|
10
11
|
expect(token.expires_at).not_to be_nil
|
11
12
|
end
|
12
13
|
end
|
@@ -4,7 +4,7 @@ describe Landable::AuthenticationService do
|
|
4
4
|
let(:simple_auth) do
|
5
5
|
proc do |username, password|
|
6
6
|
if username == 'simple' && password == 'authenticator'
|
7
|
-
{ username: 'simple', email: 'simple@example.com', first_name: 'Simple', last_name: 'Ton' }
|
7
|
+
{ username: 'simple', email: 'simple@example.com', first_name: 'Simple', last_name: 'Ton', groups: ['CreditMe Read-only', 'QuickQuid Editor', 'Netcredit Publisher'] }
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: landable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.14.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-08-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -171,6 +171,22 @@ dependencies:
|
|
171
171
|
- - ! '>='
|
172
172
|
- !ruby/object:Gem::Version
|
173
173
|
version: '0'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: figgy
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ~>
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: 1.1.0
|
182
|
+
type: :runtime
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ~>
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: 1.1.0
|
174
190
|
- !ruby/object:Gem::Dependency
|
175
191
|
name: pg
|
176
192
|
requirement: !ruby/object:Gem::Requirement
|
@@ -510,6 +526,8 @@ files:
|
|
510
526
|
- db/migrate/20140602213937_path_response_time_view.rb
|
511
527
|
- db/migrate/20141211200012_add_page_name_to_page.rb
|
512
528
|
- db/migrate/20141217171816_add_counter_for_themes_pages.rb
|
529
|
+
- db/migrate/20150610999999_add_permissions_to_access_tokens.rb
|
530
|
+
- db/migrate/20150728195345_add_category_column_to_templates.rb
|
513
531
|
- db/test/landable.access_tokens.sql
|
514
532
|
- db/test/landable.assets.sql
|
515
533
|
- db/test/landable.authors.sql
|
@@ -526,6 +544,7 @@ files:
|
|
526
544
|
- doc/schema/directory.json
|
527
545
|
- doc/schema/page.json
|
528
546
|
- doc/schema/page_revision.json
|
547
|
+
- doc/schema/permissions.json
|
529
548
|
- doc/schema/template.json
|
530
549
|
- doc/schema/template_revision.json
|
531
550
|
- doc/schema/theme.json
|
@@ -664,6 +683,10 @@ files:
|
|
664
683
|
- spec/dummy/config/routes.rb
|
665
684
|
- spec/dummy/db/.keep
|
666
685
|
- spec/dummy/db/structure.sql
|
686
|
+
- spec/dummy/etc/audit_flags.yml
|
687
|
+
- spec/dummy/etc/ldap.yml
|
688
|
+
- spec/dummy/etc/sandiego.yml
|
689
|
+
- spec/dummy/etc/sitemap_extra.yml
|
667
690
|
- spec/dummy/lib/assets/.keep
|
668
691
|
- spec/dummy/lib/bunny_messaging_service.rb
|
669
692
|
- spec/dummy/log/.keep
|
@@ -730,7 +753,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
730
753
|
version: '0'
|
731
754
|
segments:
|
732
755
|
- 0
|
733
|
-
hash:
|
756
|
+
hash: -154968153976918238
|
734
757
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
735
758
|
none: false
|
736
759
|
requirements:
|
@@ -739,7 +762,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
739
762
|
version: '0'
|
740
763
|
segments:
|
741
764
|
- 0
|
742
|
-
hash:
|
765
|
+
hash: -154968153976918238
|
743
766
|
requirements: []
|
744
767
|
rubyforge_project:
|
745
768
|
rubygems_version: 1.8.23
|
@@ -832,6 +855,10 @@ test_files:
|
|
832
855
|
- spec/dummy/config/routes.rb
|
833
856
|
- spec/dummy/db/.keep
|
834
857
|
- spec/dummy/db/structure.sql
|
858
|
+
- spec/dummy/etc/audit_flags.yml
|
859
|
+
- spec/dummy/etc/ldap.yml
|
860
|
+
- spec/dummy/etc/sandiego.yml
|
861
|
+
- spec/dummy/etc/sitemap_extra.yml
|
835
862
|
- spec/dummy/lib/assets/.keep
|
836
863
|
- spec/dummy/lib/bunny_messaging_service.rb
|
837
864
|
- spec/dummy/log/.keep
|