landable 1.13.2 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|