landable 1.7.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.
Files changed (310) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +15 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +56 -0
  7. data/Rakefile +22 -0
  8. data/app/controllers/concerns/landable/variables_concern.rb +38 -0
  9. data/app/controllers/landable/api/access_tokens_controller.rb +48 -0
  10. data/app/controllers/landable/api/assets_controller.rb +55 -0
  11. data/app/controllers/landable/api/categories_controller.rb +13 -0
  12. data/app/controllers/landable/api/directories_controller.rb +19 -0
  13. data/app/controllers/landable/api/page_revisions_controller.rb +38 -0
  14. data/app/controllers/landable/api/pages_controller.rb +96 -0
  15. data/app/controllers/landable/api/templates_controller.rb +33 -0
  16. data/app/controllers/landable/api/themes_controller.rb +57 -0
  17. data/app/controllers/landable/api_controller.rb +75 -0
  18. data/app/controllers/landable/application_controller.rb +4 -0
  19. data/app/controllers/landable/public/pages_controller.rb +25 -0
  20. data/app/controllers/landable/public/preview/page_revisions_controller.rb +16 -0
  21. data/app/controllers/landable/public/preview/pages_controller.rb +16 -0
  22. data/app/controllers/landable/public/sitemap_controller.rb +18 -0
  23. data/app/decorators/landable/null_page_decorator.rb +26 -0
  24. data/app/decorators/landable/page_decorator.rb +40 -0
  25. data/app/helpers/landable/application_helper.rb +13 -0
  26. data/app/helpers/landable/pages_helper.rb +20 -0
  27. data/app/models/concerns/landable/has_assets.rb +74 -0
  28. data/app/models/concerns/landable/table_name.rb +12 -0
  29. data/app/models/concerns/landable/traffic/table_name.rb +14 -0
  30. data/app/models/landable/access_token.rb +20 -0
  31. data/app/models/landable/asset.rb +63 -0
  32. data/app/models/landable/asset_search_engine.rb +20 -0
  33. data/app/models/landable/author.rb +12 -0
  34. data/app/models/landable/category.rb +27 -0
  35. data/app/models/landable/directory.rb +23 -0
  36. data/app/models/landable/page.rb +259 -0
  37. data/app/models/landable/page_revision.rb +74 -0
  38. data/app/models/landable/page_search_engine.rb +20 -0
  39. data/app/models/landable/search_engine.rb +39 -0
  40. data/app/models/landable/template.rb +24 -0
  41. data/app/models/landable/theme.rb +20 -0
  42. data/app/models/landable/traffic/access.rb +11 -0
  43. data/app/models/landable/traffic/ad_group.rb +11 -0
  44. data/app/models/landable/traffic/ad_type.rb +11 -0
  45. data/app/models/landable/traffic/attribution.rb +38 -0
  46. data/app/models/landable/traffic/bid_match_type.rb +11 -0
  47. data/app/models/landable/traffic/browser.rb +11 -0
  48. data/app/models/landable/traffic/campaign.rb +11 -0
  49. data/app/models/landable/traffic/city.rb +11 -0
  50. data/app/models/landable/traffic/content.rb +11 -0
  51. data/app/models/landable/traffic/cookie.rb +16 -0
  52. data/app/models/landable/traffic/country.rb +11 -0
  53. data/app/models/landable/traffic/creative.rb +11 -0
  54. data/app/models/landable/traffic/device.rb +11 -0
  55. data/app/models/landable/traffic/device_type.rb +11 -0
  56. data/app/models/landable/traffic/domain.rb +12 -0
  57. data/app/models/landable/traffic/event.rb +12 -0
  58. data/app/models/landable/traffic/event_type.rb +11 -0
  59. data/app/models/landable/traffic/experiment.rb +11 -0
  60. data/app/models/landable/traffic/http_method.rb +11 -0
  61. data/app/models/landable/traffic/ip_address.rb +11 -0
  62. data/app/models/landable/traffic/ip_lookup.rb +12 -0
  63. data/app/models/landable/traffic/keyword.rb +11 -0
  64. data/app/models/landable/traffic/location.rb +11 -0
  65. data/app/models/landable/traffic/match_type.rb +11 -0
  66. data/app/models/landable/traffic/medium.rb +11 -0
  67. data/app/models/landable/traffic/mime_type.rb +11 -0
  68. data/app/models/landable/traffic/network.rb +11 -0
  69. data/app/models/landable/traffic/owner.rb +10 -0
  70. data/app/models/landable/traffic/ownership.rb +10 -0
  71. data/app/models/landable/traffic/page_view.rb +24 -0
  72. data/app/models/landable/traffic/path.rb +13 -0
  73. data/app/models/landable/traffic/placement.rb +11 -0
  74. data/app/models/landable/traffic/platform.rb +11 -0
  75. data/app/models/landable/traffic/position.rb +11 -0
  76. data/app/models/landable/traffic/query_string.rb +12 -0
  77. data/app/models/landable/traffic/referer.rb +11 -0
  78. data/app/models/landable/traffic/region.rb +11 -0
  79. data/app/models/landable/traffic/search_term.rb +11 -0
  80. data/app/models/landable/traffic/source.rb +11 -0
  81. data/app/models/landable/traffic/target.rb +11 -0
  82. data/app/models/landable/traffic/user_agent.rb +28 -0
  83. data/app/models/landable/traffic/user_agent_type.rb +11 -0
  84. data/app/models/landable/traffic/visit.rb +15 -0
  85. data/app/models/landable/traffic/visitor.rb +13 -0
  86. data/app/responders/landable/api_responder.rb +76 -0
  87. data/app/responders/landable/page_render_responder.rb +15 -0
  88. data/app/serializers/landable/access_token_serializer.rb +6 -0
  89. data/app/serializers/landable/asset_serializer.rb +14 -0
  90. data/app/serializers/landable/author_serializer.rb +5 -0
  91. data/app/serializers/landable/category_serializer.rb +5 -0
  92. data/app/serializers/landable/directory_serializer.rb +8 -0
  93. data/app/serializers/landable/page_revision_serializer.rb +15 -0
  94. data/app/serializers/landable/page_serializer.rb +31 -0
  95. data/app/serializers/landable/template_serializer.rb +5 -0
  96. data/app/serializers/landable/theme_serializer.rb +7 -0
  97. data/app/services/landable/authentication_service.rb +44 -0
  98. data/app/services/landable/registration_service.rb +13 -0
  99. data/app/services/landable/render_service.rb +86 -0
  100. data/app/services/landable/tidy_service.rb +155 -0
  101. data/app/uploaders/landable/asset_uploader.rb +9 -0
  102. data/app/validators/path_validator.rb +12 -0
  103. data/app/validators/url_validator.rb +13 -0
  104. data/app/views/templates/preview.liquid +122 -0
  105. data/bin/rails +8 -0
  106. data/bin/redb +7 -0
  107. data/config.ru +7 -0
  108. data/config/cucumber.yml +5 -0
  109. data/config/routes.rb +62 -0
  110. data/db/migrate/20130510221424_create_landable_schema.rb +338 -0
  111. data/db/migrate/20130909182713_landable_pages__add_updated_by.rb +11 -0
  112. data/db/migrate/20130909182715_landable_page_revisions__break_out_snapshot.rb +72 -0
  113. data/db/migrate/20130909191153_landable_pages__add_lock_version.rb +5 -0
  114. data/db/migrate/20131002220041_file_based_themes.rb +12 -0
  115. data/db/migrate/20131008164204_create_head_tag_on_page.rb +19 -0
  116. data/db/migrate/20131008193544_drop_status_codes_model.rb +44 -0
  117. data/db/migrate/20131028145652_add_traffic_schema.rb +276 -0
  118. data/db/migrate/20131101213623_add_dnt_column_to_visits.rb +7 -0
  119. data/db/migrate/20131104224120_add_meta_on_events.rb +7 -0
  120. data/db/migrate/20131106185946_add_index_on_page_revisions_path.rb +6 -0
  121. data/db/migrate/20131106193021_page_revisisons__path_status_code_index.rb +9 -0
  122. data/db/migrate/20131108212501_traffic_owner_ids_are_serials.rb +20 -0
  123. data/db/migrate/20131121150902_add_attribution_id_to_unique_index.rb +10 -0
  124. data/db/migrate/20131216214027_drop_browser_screenshot_tables.rb +6 -0
  125. data/db/migrate/20140128170659_file_backed_templates.rb +8 -0
  126. data/db/migrate/20140205193757_fix_status_codes.rb +24 -0
  127. data/db/migrate/20140206211322_add_response_time_to_traffic_page_views.rb +7 -0
  128. data/db/migrate/20140220170324_add_slug_to_categories.rb +14 -0
  129. data/db/migrate/20140220174630_add_abstract_and_hero_asset_to_pages_and_page_revisions.rb +8 -0
  130. data/db/migrate/20140224205516_rename_traffic_schema.rb +40 -0
  131. data/db/pgtap/pgtap.sql +9034 -0
  132. data/db/test/landable.access_tokens.sql +13 -0
  133. data/db/test/landable.assets.sql +16 -0
  134. data/db/test/landable.authors.sql +22 -0
  135. data/db/test/landable.categories.sql +9 -0
  136. data/db/test/landable.page_revisions.sql +41 -0
  137. data/db/test/landable.pages.sql +19 -0
  138. data/db/test/landable.templates.sql +15 -0
  139. data/db/test/landable.themes.sql +25 -0
  140. data/doc/schema/access_token.json +22 -0
  141. data/doc/schema/asset.json +65 -0
  142. data/doc/schema/author.json +30 -0
  143. data/doc/schema/directory.json +24 -0
  144. data/doc/schema/page.json +95 -0
  145. data/doc/schema/page_revision.json +70 -0
  146. data/doc/schema/theme.json +37 -0
  147. data/doc/schema/uuid.json +6 -0
  148. data/features/api/access_tokens.feature +84 -0
  149. data/features/api/assets.feature +46 -0
  150. data/features/api/cors.feature +25 -0
  151. data/features/api/pages.feature +42 -0
  152. data/features/api/preview.feature +16 -0
  153. data/features/api/templates.feature +33 -0
  154. data/features/api/themes.feature +33 -0
  155. data/features/liquid/body.feature +35 -0
  156. data/features/liquid/drops/categories.feature +54 -0
  157. data/features/liquid/tags.feature +168 -0
  158. data/features/public/content_types.feature +17 -0
  159. data/features/public/publishing.feature +45 -0
  160. data/features/public/status_codes.feature +25 -0
  161. data/features/public/views.feature +17 -0
  162. data/features/step_definitions/asset_steps.rb +60 -0
  163. data/features/step_definitions/core_api_steps.rb +139 -0
  164. data/features/step_definitions/debug_steps.rb +3 -0
  165. data/features/step_definitions/factory_steps.rb +124 -0
  166. data/features/step_definitions/html_steps.rb +9 -0
  167. data/features/step_definitions/liquid_steps.rb +79 -0
  168. data/features/step_definitions/revision_steps.rb +5 -0
  169. data/features/step_definitions/theme_steps.rb +43 -0
  170. data/features/support/env.rb +66 -0
  171. data/features/support/usefulness.rb +13 -0
  172. data/landable.gemspec +54 -0
  173. data/lib/generators/landable/collection/collection_generator.rb +0 -0
  174. data/lib/generators/landable/collection/templates/stylesheets/landable/%file_name%.less +0 -0
  175. data/lib/generators/landable/collection/templates/stylesheets/landable/%file_name%/mixins.less +0 -0
  176. data/lib/generators/landable/collection/templates/stylesheets/landable/%file_name%/variables.less +0 -0
  177. data/lib/generators/landable/component/component_generator.rb +0 -0
  178. data/lib/generators/landable/component/templates/javascripts/landable/%file_name%.less +0 -0
  179. data/lib/generators/landable/component/templates/stylesheets/landable/%file_name%.less +0 -0
  180. data/lib/generators/landable/install_generator.rb +19 -0
  181. data/lib/generators/landable/landable_generator.rb +22 -0
  182. data/lib/generators/templates/landable.rb +34 -0
  183. data/lib/landable.rb +30 -0
  184. data/lib/landable/configuration.rb +115 -0
  185. data/lib/landable/core_ext/ipaddr.rb +18 -0
  186. data/lib/landable/engine.rb +69 -0
  187. data/lib/landable/error.rb +16 -0
  188. data/lib/landable/inflections.rb +4 -0
  189. data/lib/landable/layout.rb +60 -0
  190. data/lib/landable/liquid.rb +27 -0
  191. data/lib/landable/liquid/asset_tags.rb +76 -0
  192. data/lib/landable/liquid/drops.rb +46 -0
  193. data/lib/landable/liquid/filters.rb +11 -0
  194. data/lib/landable/liquid/tags.rb +91 -0
  195. data/lib/landable/migration.rb +40 -0
  196. data/lib/landable/mime_types.rb +15 -0
  197. data/lib/landable/partial.rb +46 -0
  198. data/lib/landable/seeds.rb +36 -0
  199. data/lib/landable/traffic.rb +34 -0
  200. data/lib/landable/traffic/crawl_tracker.rb +9 -0
  201. data/lib/landable/traffic/noop_tracker.rb +8 -0
  202. data/lib/landable/traffic/ping_tracker.rb +9 -0
  203. data/lib/landable/traffic/scan_tracker.rb +9 -0
  204. data/lib/landable/traffic/scrape_tracker.rb +9 -0
  205. data/lib/landable/traffic/tracker.rb +283 -0
  206. data/lib/landable/traffic/user_tracker.rb +65 -0
  207. data/lib/landable/version.rb +10 -0
  208. data/lib/tasks/landable/cucumber.rake +67 -0
  209. data/lib/tasks/landable/data.rake +166 -0
  210. data/lib/tasks/landable/pgtap.rake +26 -0
  211. data/lib/tasks/landable/rdoc.rake +11 -0
  212. data/lib/tasks/landable/seed.rake +16 -0
  213. data/lib/tasks/landable/spec.rake +15 -0
  214. data/script/cucumber +10 -0
  215. data/spec/concerns/landable/has_assets_spec.rb +75 -0
  216. data/spec/concerns/landable/table_name_spec.rb +15 -0
  217. data/spec/concerns/landable/traffic/table_name_spec.rb +16 -0
  218. data/spec/controllers/concerns/landable/variables_concern_spec.rb +66 -0
  219. data/spec/controllers/landable/api/assets_controller_spec.rb +24 -0
  220. data/spec/controllers/landable/api/categories_controller_spec.rb +45 -0
  221. data/spec/controllers/landable/api/directories_controller_spec.rb +56 -0
  222. data/spec/controllers/landable/api/page_revisions_controller_spec.rb +29 -0
  223. data/spec/controllers/landable/api/pages_controller_spec.rb +271 -0
  224. data/spec/controllers/landable/api_controller_spec.rb +189 -0
  225. data/spec/controllers/public/preview/page_revisions_controller_spec.rb +41 -0
  226. data/spec/controllers/public/preview/pages_controller_spec.rb +36 -0
  227. data/spec/controllers/public/sitemap_controller_spec.rb +25 -0
  228. data/spec/decorators/page_decorator_spec.rb +90 -0
  229. data/spec/dummy/README.rdoc +28 -0
  230. data/spec/dummy/Rakefile +6 -0
  231. data/spec/dummy/app/assets/images/foo.jpg +0 -0
  232. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  233. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  234. data/spec/dummy/app/controllers/application_controller.rb +10 -0
  235. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  236. data/spec/dummy/app/controllers/priority_controller.rb +7 -0
  237. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  238. data/spec/dummy/app/mailers/.keep +0 -0
  239. data/spec/dummy/app/models/.keep +0 -0
  240. data/spec/dummy/app/models/concerns/.keep +0 -0
  241. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  242. data/spec/dummy/app/views/layouts/priority.html.erb +18 -0
  243. data/spec/dummy/app/views/partials/_foobazz.html +1 -0
  244. data/spec/dummy/app/views/priority/show.html.erb +11 -0
  245. data/spec/dummy/bin/bundle +3 -0
  246. data/spec/dummy/bin/rails +4 -0
  247. data/spec/dummy/bin/rake +4 -0
  248. data/spec/dummy/config.ru +4 -0
  249. data/spec/dummy/config/application.rb +21 -0
  250. data/spec/dummy/config/boot.rb +5 -0
  251. data/spec/dummy/config/database.yml +60 -0
  252. data/spec/dummy/config/environment.rb +5 -0
  253. data/spec/dummy/config/environments/development.rb +29 -0
  254. data/spec/dummy/config/environments/production.rb +80 -0
  255. data/spec/dummy/config/environments/test.rb +42 -0
  256. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  257. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  258. data/spec/dummy/config/initializers/inflections.rb +16 -0
  259. data/spec/dummy/config/initializers/landable.rb +22 -0
  260. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  261. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  262. data/spec/dummy/config/initializers/session_store.rb +3 -0
  263. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  264. data/spec/dummy/config/locales/en.yml +23 -0
  265. data/spec/dummy/config/routes.rb +4 -0
  266. data/spec/dummy/db/structure.sql +3736 -0
  267. data/spec/dummy/lib/assets/.keep +0 -0
  268. data/spec/dummy/log/.keep +0 -0
  269. data/spec/dummy/public/404.html +58 -0
  270. data/spec/dummy/public/422.html +58 -0
  271. data/spec/dummy/public/500.html +57 -0
  272. data/spec/dummy/public/favicon.ico +0 -0
  273. data/spec/factories/asset.rb +29 -0
  274. data/spec/factories/authors.rb +12 -0
  275. data/spec/factories/category.rb +6 -0
  276. data/spec/factories/page_revision.rb +6 -0
  277. data/spec/factories/pages.rb +33 -0
  278. data/spec/factories/template.rb +13 -0
  279. data/spec/factories/theme.rb +14 -0
  280. data/spec/fixtures/assets/cthulhu.jpg +0 -0
  281. data/spec/fixtures/assets/panda.png +0 -0
  282. data/spec/fixtures/assets/sloth.png +0 -0
  283. data/spec/fixtures/assets/small.pdf +0 -0
  284. data/spec/helpers/pages_helper_spec.rb +35 -0
  285. data/spec/lib/landable/configuration_spec.rb +20 -0
  286. data/spec/lib/landable/layout_spec.rb +25 -0
  287. data/spec/lib/landable/liquid_spec.rb +24 -0
  288. data/spec/lib/landable/migration_spec.rb +51 -0
  289. data/spec/lib/landable/partial_spec.rb +84 -0
  290. data/spec/lib/landable/tracking_spec.rb +62 -0
  291. data/spec/lib/landable/traffic_spec.rb +45 -0
  292. data/spec/models/landable/access_token_spec.rb +13 -0
  293. data/spec/models/landable/asset_spec.rb +48 -0
  294. data/spec/models/landable/directory_spec.rb +36 -0
  295. data/spec/models/landable/page/errors_spec.rb +30 -0
  296. data/spec/models/landable/page_revision_spec.rb +75 -0
  297. data/spec/models/landable/page_spec.rb +377 -0
  298. data/spec/models/landable/template_spec.rb +47 -0
  299. data/spec/models/landable/theme_spec.rb +8 -0
  300. data/spec/responders/page_render_responder_spec.rb +43 -0
  301. data/spec/routing/public_page_route_spec.rb +36 -0
  302. data/spec/services/landable/authentication_service_spec.rb +61 -0
  303. data/spec/services/landable/render_service_spec.rb +103 -0
  304. data/spec/services/landable/tidy_service_spec.rb +157 -0
  305. data/spec/spec_helper.rb +38 -0
  306. data/spec/support/behaviors.rb +107 -0
  307. data/spec/support/carrier_wave.rb +17 -0
  308. data/spec/support/categories.yml +2 -0
  309. data/spec/support/helpers.rb +22 -0
  310. metadata +795 -0
@@ -0,0 +1,33 @@
1
+ require_dependency "landable/api_controller"
2
+
3
+ module Landable
4
+ module Api
5
+ class TemplatesController < ApiController
6
+ def index
7
+ respond_with Template.all
8
+ end
9
+
10
+ def create
11
+ template = Template.new(template_params)
12
+ template.save!
13
+ respond_with template, status: :created, location: template_url(template)
14
+ end
15
+
16
+ def show
17
+ respond_with Template.find(params[:id])
18
+ end
19
+
20
+ def update
21
+ template = Template.find(params[:id])
22
+ template.update_attributes! template_params
23
+ respond_with template
24
+ end
25
+
26
+ private
27
+
28
+ def template_params
29
+ params.require(:template).permit(:id, :name, :body, :description, :thumbnail_url, :slug, :is_layout)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,57 @@
1
+ require_dependency "landable/api_controller"
2
+
3
+ module Landable
4
+ module Api
5
+ class ThemesController < ApiController
6
+ def index
7
+ respond_with Theme.all
8
+ end
9
+
10
+ def create
11
+ theme = Theme.new(theme_params)
12
+ theme.save!
13
+ respond_with theme, status: :created, location: theme_url(theme)
14
+ end
15
+
16
+ def show
17
+ respond_with Theme.find(params[:id])
18
+ end
19
+
20
+ def update
21
+ theme = Theme.find(params[:id])
22
+ theme.update_attributes! theme_params
23
+ respond_with theme
24
+ end
25
+
26
+ def preview
27
+ theme = Theme.new(theme_params)
28
+ page = Page.example(theme: theme)
29
+
30
+ params[:theme][:asset_ids].try(:each) do |asset_id|
31
+ theme.attachments.add Asset.find(asset_id)
32
+ end
33
+
34
+ content = render_to_string(
35
+ text: RenderService.call(page),
36
+ layout: page.theme.file || false
37
+ )
38
+
39
+ respond_to do |format|
40
+ format.html do
41
+ render text: content, layout: false, content_type: 'text/html'
42
+ end
43
+
44
+ format.json do
45
+ render json: {theme: {preview: content}}
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def theme_params
53
+ params.require(:theme).permit(:id, :name, :body, :description, :thumbnail_url)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,75 @@
1
+ require_dependency "landable/application_controller"
2
+ require_dependency "landable/api_responder"
3
+ require_dependency "landable/author"
4
+
5
+ module Landable
6
+ class ApiController < ApplicationController
7
+ # skip any of these that may have been inherited from ::ApplicationController
8
+ skip_before_filter :protect_from_forgery
9
+ skip_before_action :verify_authenticity_token
10
+
11
+ # tracking is not necessary for API calls
12
+ skip_around_action :track_with_landable!
13
+
14
+ before_filter :require_author!
15
+
16
+ respond_to :json
17
+ self.responder = Landable::ApiResponder
18
+
19
+ rescue_from ActiveRecord::RecordNotFound do |ex|
20
+ head 404
21
+ end
22
+
23
+ rescue_from ActiveRecord::RecordInvalid do |ex|
24
+ render json: { errors: ex.record.errors }, status: :unprocessable_entity
25
+ end
26
+
27
+ rescue_from ActionController::UnknownFormat do |ex|
28
+ head :not_acceptable
29
+ end
30
+
31
+ rescue_from ActiveRecord::StaleObjectError do |ex|
32
+ render json: { author: ex.record.updated_by_author }, status: 409
33
+ end
34
+
35
+ rescue_from PG::Error do |ex|
36
+ if ex.message =~ /invalid input syntax for uuid/
37
+ head :not_found
38
+ else
39
+ raise ex
40
+ end
41
+ end
42
+
43
+
44
+ # here's looking at you, http://developer.github.com/v3/media/
45
+ # mime type matching is still handled by rails - see lib/landable/mime_types.rb
46
+
47
+ API_MEDIA_REGEX = /^application\/vnd\.landable(\.v(?<version>[\w\-]+))?(\.(?<param>(?:[\w\-]+)))?(\+(?<format>[\w\-]+))?/
48
+
49
+ def api_media
50
+ @api_media ||= begin
51
+ accept = request.headers['Accept'].match(API_MEDIA_REGEX) || {}
52
+
53
+ {
54
+ version: Landable::VERSION::STRING,
55
+ format: request.format.symbol,
56
+ param: accept['param'].presence,
57
+ }
58
+ end
59
+ end
60
+
61
+ protected
62
+
63
+ def require_author!
64
+ head :unauthorized if current_author.nil?
65
+ end
66
+
67
+ def current_author
68
+ return @current_author if @current_author
69
+ authenticate_with_http_basic do |username, token|
70
+ @current_author = Author.authenticate!(username, token)
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,4 @@
1
+ module Landable
2
+ class ApplicationController < ::ApplicationController
3
+ end
4
+ end
@@ -0,0 +1,25 @@
1
+ require_dependency "landable/application_controller"
2
+
3
+ module Landable
4
+ module Public
5
+ class PagesController < ApplicationController
6
+ respond_to :html
7
+
8
+ self.responder = Landable::PageRenderResponder
9
+
10
+ def show
11
+ respond_with current_snapshot
12
+ end
13
+
14
+ private
15
+
16
+ def current_page
17
+ @current_page ||= Page.by_path(request.path)
18
+ end
19
+
20
+ def current_snapshot
21
+ @current_snapshot ||= current_page.published_revision.try(:snapshot) or Page.missing
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ require_dependency "landable/application_controller"
2
+
3
+ module Landable
4
+ module Public
5
+ module Preview
6
+ class PageRevisionsController < ApplicationController
7
+ respond_to :html
8
+
9
+ def show
10
+ revision = PageRevision.find params[:id]
11
+ respond_with revision.snapshot, responder: Landable::PageRenderResponder
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require_dependency "landable/application_controller"
2
+
3
+ module Landable
4
+ module Public
5
+ module Preview
6
+ class PagesController < ApplicationController
7
+ respond_to :html
8
+
9
+ def show
10
+ page = Page.find params[:id]
11
+ respond_with page, responder: Landable::PageRenderResponder, preview: true
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require_dependency "landable/application_controller"
2
+
3
+ module Landable
4
+ module Public
5
+ class SitemapController < ApplicationController
6
+ def index
7
+ sitemap = Landable::Page.generate_sitemap(
8
+ host: Landable.configuration.sitemap_host || request.host,
9
+ protocol: Landable.configuration.sitemap_protocol,
10
+ exclude_categories: Landable.configuration.sitemap_exclude_categories,
11
+ sitemap_additional_paths: Landable.configuration.sitemap_additional_paths,
12
+ )
13
+
14
+ render xml: sitemap
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module Landable
2
+ class NullPageDecorator < Landable::PageDecorator
3
+ def initialize
4
+ end
5
+
6
+ def title
7
+ # Obviously, this should instead be configured with Landable in some way,
8
+ # such that you can register the titles you want everywhere. Or, of course,
9
+ # a more reasonable way to bypass Landable entirely yet still use the
10
+ # `landable` helper. Just waiting to tease out what features we need.
11
+ content_tag('title', 'No current page; default title')
12
+ end
13
+
14
+ def meta_tags
15
+ ''
16
+ end
17
+
18
+ def path
19
+ ''
20
+ end
21
+
22
+ def body
23
+ ''
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ module Landable
2
+ class PageDecorator
3
+ include ActionView::Helpers::TagHelper
4
+
5
+ def initialize(page)
6
+ raise TypeError.new("Use Landable::NullPageDecorator") if page.nil?
7
+ @page = page
8
+ end
9
+
10
+ def title
11
+ content_tag('title', page.title) if page.title?
12
+ end
13
+
14
+ def path
15
+ page.path
16
+ end
17
+
18
+ def body
19
+ page.body.try(:html_safe)
20
+ end
21
+
22
+ def head_content
23
+ page.head_content.try(:html_safe)
24
+ end
25
+
26
+ def meta_tags
27
+ return unless tags = page.meta_tags
28
+ Rails.logger.info "Meta tags string: #{tags}" if tags.is_a? String
29
+ return if tags.empty? or !tags.is_a? Hash
30
+
31
+ tags.map { |name, value|
32
+ tag('meta', name: name, content: value) if value.present?
33
+ }.compact.join("\n").html_safe
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :page # Keeping it private until there's a compelling reason not to
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ module Landable
2
+ module ApplicationHelper
3
+ def method_missing(method, *args, &block)
4
+ return main_app.send(method, *args) if method =~ /_(path|url)$/ && main_app.respond_to?(method)
5
+ super
6
+ end
7
+
8
+ def respond_to?(method)
9
+ return true if method =~ /_(path|url)$/ && main_app.respond_to?(method)
10
+ super
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ module Landable
2
+ module PagesHelper
3
+ def landable(page = current_page)
4
+ return Landable::NullPageDecorator.new if page.nil?
5
+ @landable ||= Landable::PageDecorator.new(page)
6
+ end
7
+
8
+ def current_page
9
+ if params[:controller] == "landable/public/preview/page_revisions"
10
+ current_page = PageRevision.find(params[:id])
11
+ elsif params[:controller] == "landable/public/preview/pages"
12
+ current_page = Page.find(params[:id])
13
+ else
14
+ current_page = Page.by_path(request.path)
15
+ end
16
+
17
+ @current_page ||= current_page
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ # Pages, page revisions, and themes are all renderable. Rendering potentially
2
+ # involves assets. Rather than having to query for each asset as it's
3
+ # discovered, this concern allows retrieval of all asset names for a given
4
+ # body (#asset_names), and commits the habtm relation on save (#save_assets!;
5
+ # allows us to say "this asset belongs to 3 pages"). #assets is overridden to
6
+ # ensure that the assets returned /always/ reflect assets present in the Liquid
7
+ # template.
8
+
9
+ require_dependency 'landable/liquid'
10
+
11
+ module Landable
12
+ module HasAssets
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ has_and_belongs_to_many :assets, class_name: 'Landable::Asset', join_table: assets_join_table_name
17
+
18
+ before_save :save_assets!
19
+
20
+ def asset_names
21
+ # sticking with what we know about liquid, rather than doing regex.
22
+ # (though regex may be faster, should we need that optimization later.)
23
+ @asset_names ||= begin
24
+ template = ::Liquid::Template.parse(body)
25
+ asset_names_for_node template.root
26
+ end
27
+ end
28
+
29
+ def assets
30
+ Landable::Asset.where(name: asset_names)
31
+ end
32
+
33
+ # {asset_name: asset}
34
+ def assets_as_hash
35
+ Hash[assets.map { |asset| [asset.name, asset] }]
36
+ end
37
+
38
+ # passthrough for body=; clears the asset_names cache in the process
39
+ def body= body_val
40
+ @asset_names = nil
41
+ self[:body] = body_val
42
+ end
43
+
44
+ # this looks weird; I swear it works
45
+ def save_assets!
46
+ self.assets = self.assets
47
+ end
48
+
49
+
50
+ private
51
+
52
+ def asset_names_for_node node, names = []
53
+ # set up a recursing function to search for asset tags
54
+ if node.is_a? Landable::Liquid::AssetTag
55
+ names << node.asset_name unless names.include? node.asset_name
56
+ end
57
+
58
+ if node.respond_to? :nodelist and node.nodelist
59
+ node.nodelist.each { |node| asset_names_for_node node, names }
60
+ end
61
+
62
+ names
63
+ end
64
+
65
+ end
66
+
67
+ module ClassMethods
68
+ def assets_join_table_name
69
+ "#{Landable.configuration.database_schema_prefix}landable.#{self.name.underscore.split('/').last}_assets"
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,12 @@
1
+ module Landable
2
+ module TableName
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ model_name = self.model_name.element.pluralize
7
+ schema_name = "#{Landable.configuration.database_schema_prefix}landable"
8
+ self.table_name = "#{schema_name}.#{model_name}"
9
+ end
10
+
11
+ end
12
+ end