landable 1.7.1.rc1 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rbenv-gemsets +1 -0
- data/.travis.yml +20 -2
- data/CHANGELOG.md +8 -1
- data/Gemfile +14 -13
- data/Rakefile +0 -1
- data/app/controllers/landable/api/assets_controller.rb +49 -31
- data/app/controllers/landable/api/pages_controller.rb +64 -42
- data/app/controllers/landable/api/templates_controller.rb +37 -13
- data/app/controllers/landable/api/themes_controller.rb +35 -14
- data/app/models/concerns/landable/librarian.rb +36 -0
- data/app/models/landable/asset.rb +1 -0
- data/app/models/landable/page.rb +9 -0
- data/app/models/landable/page_revision.rb +52 -9
- data/app/models/landable/search_engine.rb +1 -1
- data/app/models/landable/template.rb +10 -0
- data/app/models/landable/template_revision.rb +1 -0
- data/app/models/landable/theme.rb +1 -0
- data/app/responders/landable/api_responder.rb +1 -1
- data/app/serializers/landable/asset_serializer.rb +1 -0
- data/app/serializers/landable/page_revision_serializer.rb +1 -0
- data/app/serializers/landable/page_serializer.rb +4 -13
- data/app/serializers/landable/template_serializer.rb +3 -3
- data/app/serializers/landable/theme_serializer.rb +1 -1
- data/app/services/landable/screenshot_service.rb +32 -0
- data/app/views/templates/preview.liquid +13 -11
- data/config/routes.rb +6 -3
- data/db/migrate/20140501171345_add_deleted_at_to_pages.rb +5 -0
- data/db/migrate/20140501171352_add_deleted_at_to_themes.rb +5 -0
- data/db/migrate/20140501171359_add_deleted_at_to_assets.rb +5 -0
- data/db/migrate/20140501171406_add_deleted_at_to_templates.rb +5 -0
- data/db/migrate/20140515164543_add_screenshot_to_page_revisions.rb +5 -0
- data/db/test/landable.general.sql +9 -0
- data/db/test/landable.page_revisions.sql +5 -3
- data/db/test/landable.templates.sql +29 -2
- data/db/test/landable.themes.sql +5 -2
- data/doc/schema/asset.json +5 -0
- data/doc/schema/page.json +5 -0
- data/doc/schema/page_revision.json +6 -1
- data/doc/schema/template.json +5 -0
- data/doc/schema/template_revision.json +5 -0
- data/doc/schema/theme.json +5 -0
- data/landable.gemspec +31 -33
- data/lib/generators/templates/landable.rb +6 -0
- data/lib/landable/configuration.rb +39 -6
- data/lib/landable/version.rb +3 -3
- data/lib/tasks/landable/pgtap.rake +1 -2
- data/script/pgtap +10 -0
- data/script/redb +0 -2
- data/spec/concerns/landable/librarian.rb +45 -0
- data/spec/controllers/public/preview/pages_controller_spec.rb +1 -1
- data/spec/dummy/db/.keep +0 -0
- data/spec/models/landable/page_revision_spec.rb +60 -2
- data/spec/models/landable/page_spec.rb +3 -1
- data/spec/services/landable/authentication_service_spec.rb +1 -1
- data/spec/services/landable/screenshot_service_spec.rb +43 -0
- data/spec/services/landable/tidy_service_spec.rb +3 -2
- metadata +67 -82
- data/landable-1.7.0.gem +0 -0
- data/spec/dummy/db/structure.sql +0 -3837
@@ -1,28 +1,46 @@
|
|
1
|
-
require_dependency
|
1
|
+
require_dependency 'landable/api_controller'
|
2
2
|
|
3
3
|
module Landable
|
4
4
|
module Api
|
5
5
|
class ThemesController < ApiController
|
6
|
-
|
7
|
-
|
8
|
-
end
|
6
|
+
# filters
|
7
|
+
before_filter :load_theme, except: [:create, :index, :preview]
|
9
8
|
|
9
|
+
# RESTful methods
|
10
10
|
def create
|
11
11
|
theme = Theme.new(theme_params)
|
12
12
|
theme.save!
|
13
|
+
|
13
14
|
respond_with theme, status: :created, location: theme_url(theme)
|
14
15
|
end
|
15
16
|
|
17
|
+
def destroy
|
18
|
+
@theme.try(:deactivate)
|
19
|
+
|
20
|
+
respond_with @theme
|
21
|
+
end
|
22
|
+
|
23
|
+
def index
|
24
|
+
respond_with Theme.all
|
25
|
+
end
|
26
|
+
|
27
|
+
def reactivate
|
28
|
+
@theme.try(:reactivate)
|
29
|
+
|
30
|
+
respond_with @theme
|
31
|
+
end
|
32
|
+
|
16
33
|
def show
|
17
|
-
respond_with
|
34
|
+
respond_with @theme
|
18
35
|
end
|
19
36
|
|
20
37
|
def update
|
21
|
-
theme
|
22
|
-
|
23
|
-
respond_with theme
|
38
|
+
@theme.update_attributes!(theme_params)
|
39
|
+
|
40
|
+
respond_with @theme
|
24
41
|
end
|
25
42
|
|
43
|
+
# custom methods
|
26
44
|
def preview
|
27
45
|
theme = Theme.new(theme_params)
|
28
46
|
page = Page.example(theme: theme)
|
@@ -30,17 +48,17 @@ module Landable
|
|
30
48
|
params[:theme][:asset_ids].try(:each) do |asset_id|
|
31
49
|
theme.attachments.add Asset.find(asset_id)
|
32
50
|
end
|
33
|
-
|
51
|
+
|
34
52
|
content = render_to_string(
|
35
53
|
text: RenderService.call(page),
|
36
54
|
layout: page.theme.file || false
|
37
55
|
)
|
38
|
-
|
56
|
+
|
39
57
|
respond_to do |format|
|
40
58
|
format.html do
|
41
59
|
render text: content, layout: false, content_type: 'text/html'
|
42
60
|
end
|
43
|
-
|
61
|
+
|
44
62
|
format.json do
|
45
63
|
render json: {theme: {preview: content}}
|
46
64
|
end
|
@@ -48,10 +66,13 @@ module Landable
|
|
48
66
|
end
|
49
67
|
|
50
68
|
private
|
69
|
+
def load_theme
|
70
|
+
@theme = Theme.find(params[:id])
|
71
|
+
end
|
51
72
|
|
52
|
-
|
53
|
-
|
54
|
-
|
73
|
+
def theme_params
|
74
|
+
params.require(:theme).permit(:id, :name, :body, :description, :thumbnail_url)
|
75
|
+
end
|
55
76
|
end
|
56
77
|
end
|
57
78
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Landable
|
2
|
+
# modules
|
3
|
+
module Librarian
|
4
|
+
# The original name for this module was Landable::JamesCole, but Isaac said 'no.'
|
5
|
+
# if this name confuses you, go watch "12 Monkeys" you class-less savage.
|
6
|
+
# Wait, where were you in 95? Prison? The womb? Ohmygawd, that was a great film.
|
7
|
+
|
8
|
+
# extensions
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
# includes
|
12
|
+
included do
|
13
|
+
end
|
14
|
+
|
15
|
+
# validations
|
16
|
+
|
17
|
+
# standard methods
|
18
|
+
def deactivate
|
19
|
+
self.update_attribute(:deleted_at, Time.now)
|
20
|
+
end
|
21
|
+
|
22
|
+
# custom methods
|
23
|
+
def nuke!
|
24
|
+
self.destroy
|
25
|
+
end
|
26
|
+
|
27
|
+
def reactivate
|
28
|
+
self.update_attribute(:deleted_at, nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
# end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Live Long the Army of the 12 Monkeys!
|
35
|
+
# end
|
36
|
+
end
|
data/app/models/landable/page.rb
CHANGED
@@ -10,6 +10,7 @@ module Landable
|
|
10
10
|
include Landable::HasAssets
|
11
11
|
include Landable::Engine.routes.url_helpers
|
12
12
|
include Landable::TableName
|
13
|
+
include Landable::Librarian
|
13
14
|
|
14
15
|
validates_presence_of :path, :status_code
|
15
16
|
validates_presence_of :redirect_url, if: -> page { page.redirect? }
|
@@ -124,6 +125,14 @@ module Landable
|
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
128
|
+
def deactivate
|
129
|
+
self.update_attribute(:status_code, 410)
|
130
|
+
|
131
|
+
publish!(author_id: updated_by_author.id, notes: "This page has been trashed")
|
132
|
+
|
133
|
+
super
|
134
|
+
end
|
135
|
+
|
127
136
|
def html?
|
128
137
|
content_type == 'text/html'
|
129
138
|
end
|
@@ -10,6 +10,7 @@ module Landable
|
|
10
10
|
'page_id',
|
11
11
|
'imported_at',
|
12
12
|
'created_at',
|
13
|
+
'deleted_at',
|
13
14
|
'updated_at',
|
14
15
|
'published_revision_id',
|
15
16
|
'is_publishable',
|
@@ -21,7 +22,8 @@ module Landable
|
|
21
22
|
|
22
23
|
belongs_to :author
|
23
24
|
belongs_to :page, inverse_of: :revisions
|
24
|
-
|
25
|
+
|
26
|
+
after_commit :add_screenshot!, on: :create
|
25
27
|
|
26
28
|
def page_id=(id)
|
27
29
|
# set the value
|
@@ -42,14 +44,14 @@ module Landable
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def snapshot
|
45
|
-
Page.new(title: self.title,
|
46
|
-
meta_tags: page.meta_tags,
|
47
|
+
Page.new(title: self.title,
|
48
|
+
meta_tags: page.meta_tags,
|
47
49
|
head_content: page.head_content,
|
48
|
-
body: self.body,
|
49
|
-
path: self.path,
|
50
|
-
redirect_url: self.redirect_url,
|
51
|
-
status_code: self.status_code,
|
52
|
-
theme_id: self.theme_id,
|
50
|
+
body: self.body,
|
51
|
+
path: self.path,
|
52
|
+
redirect_url: self.redirect_url,
|
53
|
+
status_code: self.status_code,
|
54
|
+
theme_id: self.theme_id,
|
53
55
|
category_id: self.category_id,
|
54
56
|
abstract: self.abstract,
|
55
57
|
hero_asset_id: self.hero_asset_id)
|
@@ -64,11 +66,52 @@ module Landable
|
|
64
66
|
end
|
65
67
|
|
66
68
|
def preview_url
|
67
|
-
|
69
|
+
begin
|
70
|
+
public_preview_page_revision_url(self, host: Landable.configuration.public_host)
|
71
|
+
rescue ArgumentError
|
72
|
+
Rails.logger.warn "Failed to generate preview url for page revision #{id} - missing Landable.configuration.public_host"
|
73
|
+
nil
|
74
|
+
end
|
68
75
|
end
|
69
76
|
|
70
77
|
def preview_path
|
71
78
|
public_preview_page_revision_path(self)
|
72
79
|
end
|
80
|
+
|
81
|
+
mount_uploader :screenshot, Landable::AssetUploader
|
82
|
+
|
83
|
+
def screenshot_url
|
84
|
+
screenshot.try(:url)
|
85
|
+
end
|
86
|
+
|
87
|
+
def add_screenshot!
|
88
|
+
return nil if preview_url.blank?
|
89
|
+
|
90
|
+
unless Landable.configuration.screenshots_enabled
|
91
|
+
Rails.logger.info "Screenshots disabled; skipping for #{path}"
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
95
|
+
attempts_left = 3
|
96
|
+
|
97
|
+
begin
|
98
|
+
attempts_left -= 1
|
99
|
+
|
100
|
+
self.screenshot = ScreenshotService.capture(preview_url)
|
101
|
+
|
102
|
+
# we've got a trigger preventing updates to other columns, so! muck
|
103
|
+
# about under the hood to commit the asset, and explicitly only update
|
104
|
+
# this column.
|
105
|
+
store_screenshot!
|
106
|
+
write_screenshot_identifier
|
107
|
+
update_column :screenshot, self[:screenshot]
|
108
|
+
|
109
|
+
rescue ScreenshotService::Error => error
|
110
|
+
Rails.logger.warn "Failed to generate screenshot (#{attempts_left} attempt(s) left) for #{path}: #{error.inspect}"
|
111
|
+
|
112
|
+
retry if attempts_left > 0
|
113
|
+
end
|
114
|
+
end
|
73
115
|
end
|
116
|
+
|
74
117
|
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Landable
|
2
2
|
class Template < ActiveRecord::Base
|
3
3
|
include Landable::TableName
|
4
|
+
include Landable::Librarian
|
5
|
+
|
6
|
+
# attributes
|
7
|
+
attr_accessor :temp_author
|
4
8
|
|
5
9
|
validates_presence_of :name, :slug, :description
|
6
10
|
validates_uniqueness_of :name, case_sensitive: false
|
@@ -14,6 +18,12 @@ module Landable
|
|
14
18
|
template.is_publishable = true unless template.published_revision_id_changed?
|
15
19
|
}
|
16
20
|
|
21
|
+
def deactivate
|
22
|
+
publish!(author_id: temp_author.id, notes: "This template has been trashed")
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
17
27
|
def name= val
|
18
28
|
self[:name] = val
|
19
29
|
self[:slug] ||= (val && val.underscore.gsub(/[^\w_]/, '_').gsub(/_{2,}/, '_'))
|
@@ -18,7 +18,7 @@ module Landable
|
|
18
18
|
# For updates, rails defaults to returning 204 No Content;
|
19
19
|
# we would actually prefer that the updated record be returned,
|
20
20
|
# in case an update to one key necessitates an automatic update to another.
|
21
|
-
if patch? || put?
|
21
|
+
if patch? || put? || delete?
|
22
22
|
display resource
|
23
23
|
else
|
24
24
|
super
|
@@ -1,18 +1,9 @@
|
|
1
1
|
module Landable
|
2
2
|
class PageSerializer < ActiveModel::Serializer
|
3
|
-
|
4
|
-
attributes :
|
5
|
-
|
6
|
-
|
7
|
-
attributes :head_content
|
8
|
-
attributes :redirect_url
|
9
|
-
attributes :meta_tags
|
10
|
-
attributes :is_publishable
|
11
|
-
attributes :preview_path
|
12
|
-
attributes :lock_version
|
13
|
-
attributes :status_code
|
14
|
-
attributes :abstract
|
15
|
-
attributes :hero_asset_name
|
3
|
+
|
4
|
+
attributes :abstract, :body, :deleted_at, :head_content, :hero_asset_name,
|
5
|
+
:id, :is_publishable, :lock_version, :meta_tags, :path,
|
6
|
+
:preview_path, :redirect_url, :status_code, :title
|
16
7
|
|
17
8
|
embed :ids
|
18
9
|
has_one :theme
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Landable
|
2
2
|
class TemplateSerializer < ActiveModel::Serializer
|
3
|
-
|
4
|
-
attributes :
|
5
|
-
|
3
|
+
|
4
|
+
attributes :body, :deleted_at, :description, :editable, :file, :id,
|
5
|
+
:is_layout, :is_publishable, :name, :slug, :thumbnail_url
|
6
6
|
|
7
7
|
embed :ids
|
8
8
|
has_one :published_revision
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Landable
|
4
|
+
class ScreenshotService
|
5
|
+
class Error < StandardError; end
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def capture url
|
9
|
+
if not Landable.configuration.publicist_url
|
10
|
+
Rails.logger.warn "Couldn't generate screenshot for #{url}; no Landable.configuration.publicist_url configured"
|
11
|
+
else
|
12
|
+
screenshots_uri = URI(Landable.configuration.publicist_url)
|
13
|
+
screenshots_uri.path = '/api/services/screenshots'
|
14
|
+
|
15
|
+
response = Net::HTTP.post_form screenshots_uri, 'screenshot[url]' => url
|
16
|
+
|
17
|
+
if response.code == '200'
|
18
|
+
file = Tempfile.new ['screenshot-', '.png']
|
19
|
+
file.binmode
|
20
|
+
file.write response.body
|
21
|
+
file.rewind
|
22
|
+
|
23
|
+
file
|
24
|
+
else
|
25
|
+
raise Error, "Received #{response.code} back from #{screenshots_uri.to_s}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -85,25 +85,27 @@
|
|
85
85
|
<!-- pretty invalid, this is -->
|
86
86
|
<style type="text/css">
|
87
87
|
body {
|
88
|
-
padding-top:
|
88
|
+
padding-top: 30px;
|
89
89
|
}
|
90
90
|
|
91
91
|
body:before {
|
92
|
-
text-align: center;
|
93
|
-
font-weight: bold;
|
94
|
-
background-color: #FFDA73;
|
95
|
-
font-family: Roboto;
|
96
92
|
width: 100%;
|
97
93
|
position: absolute;
|
98
94
|
top: 0;
|
99
95
|
left: 0;
|
100
|
-
font-size: 20px;
|
101
|
-
padding: 5px 0;
|
102
|
-
line-height: 30px;
|
103
|
-
border-bottom: 1px #e2bd56 solid;
|
104
|
-
content: "Preview Mode (Test your unpublished changes with this page. Share this URL!)";
|
105
96
|
box-sizing: border-box;
|
106
|
-
|
97
|
+
box-shadow: inset 0 -10px 5px -10px rgba(0, 0, 0, 0.5);
|
98
|
+
height: 30px;
|
99
|
+
padding: 5px 0;
|
100
|
+
background-color: #FFDA73;
|
101
|
+
line-height: 20px;
|
102
|
+
font-size: 14px;
|
103
|
+
font-family: sans-serif;
|
104
|
+
font-weight: normal;
|
105
|
+
text-align: center;
|
106
|
+
color: #7e592d;
|
107
|
+
content: "Preview Mode";
|
108
|
+
text-transform: uppercase;
|
107
109
|
}
|
108
110
|
|
109
111
|
body.publicist-preview {
|