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,15 @@
1
+ module Landable
2
+ class PageRenderResponder < ActionController::Responder
3
+ def to_html
4
+ page = resource
5
+
6
+ case page.status_code
7
+ when 200 then render text: RenderService.call(page, preview: options[:preview], responder: self),
8
+ content_type: page.content_type,
9
+ layout: (page.theme.try(:file) || false)
10
+ when 301, 302 then redirect_to page.redirect_url, status: page.status_code
11
+ else raise page.error
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Landable
2
+ class AccessTokenSerializer < ActiveModel::Serializer
3
+ attributes :id, :expires_at
4
+ has_one :author, embed: :object
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ module Landable
2
+ class AssetSerializer < ActiveModel::Serializer
3
+ attributes :id, :name, :description
4
+ attributes :file_size, :mime_type, :md5sum
5
+ attributes :created_at, :updated_at
6
+ attributes :public_url
7
+
8
+ embed :ids
9
+
10
+ has_one :author, include: true, serializer: AuthorSerializer
11
+ has_many :pages
12
+ has_many :themes
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module Landable
2
+ class AuthorSerializer < ActiveModel::Serializer
3
+ attributes :id, :username, :email, :first_name, :last_name
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Landable
2
+ class CategorySerializer < ActiveModel::Serializer
3
+ attributes :id, :name, :description
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module Landable
2
+ class DirectorySerializer < ActiveModel::Serializer
3
+ attributes :id, :path
4
+
5
+ has_many :subdirectories, embed: :ids, embed_key: :path
6
+ has_many :pages, embed: :ids
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ require_dependency 'landable/author_serializer'
2
+ require_dependency 'landable/theme'
3
+
4
+ module Landable
5
+ class PageRevisionSerializer < ActiveModel::Serializer
6
+ attributes :id, :ordinal, :notes, :is_minor, :is_published
7
+ attributes :created_at, :updated_at
8
+ attributes :preview_path
9
+
10
+ embed :ids
11
+ has_one :page
12
+ has_one :author, include: true, serializer: AuthorSerializer
13
+
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module Landable
2
+ class PageSerializer < ActiveModel::Serializer
3
+ attributes :id
4
+ attributes :path
5
+ attributes :title
6
+ attributes :body
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
16
+
17
+ embed :ids
18
+ has_one :theme
19
+ has_one :published_revision
20
+ has_one :category
21
+ has_one :updated_by_author, root: :authors, include: true, serializer: AuthorSerializer
22
+
23
+ def category
24
+ object.category || Landable::Category.where(name: 'Uncategorized').first
25
+ end
26
+
27
+ def meta_tags
28
+ object.meta_tags || {}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module Landable
2
+ class TemplateSerializer < ActiveModel::Serializer
3
+ attributes :id, :name, :body, :description, :thumbnail_url, :slug, :is_layout, :editable, :file
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Landable
2
+ class ThemeSerializer < ActiveModel::Serializer
3
+ attributes :id, :name, :editable, :body, :description, :thumbnail_url
4
+
5
+ embed :ids
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ module Landable
2
+ AuthenticationFailedError = Class.new(StandardError)
3
+
4
+ module AuthenticationService
5
+ def self.call(username, password)
6
+ strategies = Landable.configuration.authenticators
7
+
8
+ strategies.each do |strategy|
9
+ ident = strategy.call username, password
10
+ return ident if ident
11
+ end
12
+
13
+ raise AuthenticationFailedError
14
+ end
15
+
16
+ class EchoAuthenticator
17
+ def self.call(username, password)
18
+ new(nil, nil).call(username, password)
19
+ end
20
+
21
+ def initialize(username, password)
22
+ @username = username
23
+ @password = password
24
+ end
25
+
26
+ def call(username, password)
27
+ return unless acceptable_environment?
28
+ return echo_author(username) if @username.nil? && password != 'fail'
29
+ return echo_author(username) if @username == username && @password == password
30
+ end
31
+
32
+ private
33
+
34
+ def acceptable_environment?
35
+ defined?(::Rails) && (Rails.env.development? || Rails.env.test?)
36
+ end
37
+
38
+ def echo_author(username)
39
+ { username: username, email: "#{username}@example.com",
40
+ first_name: 'Trogdor', last_name: 'McBurninator' }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ require_dependency "landable/author"
2
+
3
+ module Landable
4
+ class RegistrationService
5
+ def self.call(attributes)
6
+ if author = Author.where(username: attributes[:username]).first
7
+ author
8
+ else
9
+ Author.create!(attributes.slice(:username, :email, :first_name, :last_name))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,86 @@
1
+ # TODO Handle layouts-as-themes here
2
+
3
+ require_dependency 'landable/liquid'
4
+
5
+ module Landable
6
+ class RenderService
7
+ def self.call(page, options = nil)
8
+ new(page, page.theme, options).render!
9
+ end
10
+
11
+ def initialize(page, theme, options = nil)
12
+ @page = page
13
+ @theme = theme
14
+ @options = options || {}
15
+ end
16
+
17
+ def render!
18
+ variables = options[:responder].try(:controller).try(:fetch_landable_variables)
19
+ variables ||= {}
20
+
21
+ content = render_template(page.body, variables, registers: {
22
+ page: page,
23
+ assets: assets_for_page,
24
+ responder: options[:responder],
25
+ })
26
+
27
+ if layout?
28
+ content = render_template(theme.body, {'body' => content}, registers: {
29
+ page: page,
30
+ assets: assets_for_theme,
31
+ })
32
+ end
33
+
34
+ # not completely happy about this
35
+ if options[:preview]
36
+ if page.html?
37
+ # fancy!
38
+ preview_template = File.open(Landable::Engine.root.join('app', 'views', 'templates', 'preview.liquid')).read
39
+
40
+ content = render_template(preview_template, {
41
+ 'content' => content,
42
+ 'is_redirect' => page.redirect?,
43
+ 'is_html' => page.html?,
44
+ 'status_code' => page.status_code,
45
+ 'redirect_url' => page.redirect_url,
46
+ })
47
+ else
48
+ # non-html stuff just gets rendered as plaintext for a preview
49
+ content = '<pre>' + CGI::escapeHTML(content) + '</pre>'
50
+ end
51
+ end
52
+
53
+ content
54
+ end
55
+
56
+ private
57
+
58
+ attr_reader :page, :theme, :options
59
+
60
+ def layout?
61
+ theme && theme.body.present? && theme.file.blank? && page.html?
62
+ end
63
+
64
+ def parse(body)
65
+ ::Liquid::Template.parse(body)
66
+ end
67
+
68
+ def assets_for_page
69
+ @assets_for_page ||=
70
+ begin
71
+ from_theme = theme ? theme.assets_as_hash : {}
72
+ from_theme.merge page.assets_as_hash
73
+ end
74
+ end
75
+
76
+ def assets_for_theme
77
+ @assets_for_theme ||= theme ? theme.assets_as_hash : {}
78
+ end
79
+
80
+ def render_template template, variables = {}, liquid_options = {}
81
+ variables['categories'] = Liquid::CategoriesDrop.new
82
+
83
+ parse(template).render!(variables, liquid_options)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,155 @@
1
+ module Landable
2
+ module TidyService
3
+
4
+ class TidyError < StandardError; end
5
+
6
+ mattr_accessor :options
7
+ @@options = [
8
+ # is what we have
9
+ '-utf8',
10
+
11
+ # two-space soft indents
12
+ '-indent',
13
+
14
+ # no wrapping
15
+ '--wrap 0',
16
+
17
+ # make some guesses about how the code should look
18
+ '--clean true',
19
+
20
+ # kill microsoft word crap
21
+ '--bare true',
22
+
23
+ # quote 'em up
24
+ '--quote-ampersand true',
25
+
26
+ # whitespace niceness
27
+ '--break-before-br true',
28
+
29
+ # allow <div ...><div ...></div></div>
30
+ '--merge-divs false',
31
+
32
+ # silence will fall
33
+ '--quiet true',
34
+ '--show-warnings false',
35
+ ]
36
+
37
+ # list of liquid tags that also render tags - things that we should
38
+ # consider to be element-level, and therefore to be tidied along with the
39
+ # rest of the dom
40
+ mattr_accessor :liquid_elements
41
+ @@liquid_elements = [
42
+ 'template',
43
+ 'title_tag',
44
+ 'meta_tags',
45
+ 'img_tag',
46
+ ]
47
+
48
+
49
+ def self.call! input
50
+ self.call input, raise_on_error: true
51
+ end
52
+
53
+ def self.call input, runtime_options={}
54
+ if not tidyable?
55
+ raise TidyError, 'Your system doesn\'t seem to have tidy installed. Please see https://github.com/w3c/tidy-html5.'
56
+ end
57
+
58
+ # wrapping known liquid in a span to allow tidy to format them nicely
59
+ input = wrap_liquid input
60
+
61
+ # off to tidy
62
+ output = IO.popen("tidy #{options.join(' ')}", 'r+') do |io|
63
+ io.puts input
64
+ io.close_write
65
+ io.read
66
+ end
67
+
68
+ # 0: success
69
+ # 1: warning
70
+ # 2: error
71
+ # 3: ???
72
+ # 4: profit
73
+ if $?.exitstatus >= 2 and runtime_options[:raise_on_error]
74
+ raise TidyError, "Tidy exited with status #{$?} - check stderr."
75
+ end
76
+
77
+ # unnwrapping the liquid that we wrapped earlier
78
+ output = unwrap_liquid output
79
+
80
+ # create and return a Result, allowing access to specific bits of the output
81
+ Result.new output
82
+ end
83
+
84
+ def self.tidyable?
85
+ @@is_tidyable ||= Kernel.system('which tidy > /dev/null')
86
+ end
87
+
88
+ protected
89
+
90
+ def self.wrap_liquid input
91
+ output = input.dup
92
+
93
+ output.scan(/(\s*(\{% *(?:#{liquid_elements.join('|')}) *.*?%})\s*)/).each do |match, liquid|
94
+ # encode and stash in a div, inserted between newlines, to allow tidy
95
+ # to nudge this element around as appropriate
96
+ encoded = Base64.encode64(liquid).strip
97
+ output.gsub! match, " <div data-liquid=\"#{encoded}\"></div> "
98
+ end
99
+
100
+ output
101
+ end
102
+
103
+ def self.unwrap_liquid input
104
+ output = input.dup
105
+
106
+ output.scan(/(<div data-liquid="(.*?)"><\/div>)/).each do |match, liquid|
107
+ # ensure we match utf8 for utf8
108
+ decoded = Base64.decode64(liquid).force_encoding(match.encoding)
109
+ output.gsub! match, decoded
110
+ end
111
+
112
+ output
113
+ end
114
+
115
+
116
+ class Result < Object
117
+ def initialize source
118
+ @source = source
119
+ end
120
+
121
+ def to_s
122
+ @source
123
+ end
124
+
125
+ def body
126
+ if match = @source.match(/<body(?: [^>]*)?>(.*)<\/body>/m)
127
+ deindent match[1]
128
+ end
129
+ end
130
+
131
+ def head
132
+ if match = @source.match(/<head>(.*)<\/head>/m)
133
+ deindent match[1]
134
+ end
135
+ end
136
+
137
+ def css
138
+ links = head.try :scan, /<link [^>]*type=['"]text\/css['"][^>]*>/
139
+ styles = head.try :scan, /<style[^>]*>.*?<\/style>/m
140
+ [links.to_a, styles.to_a].flatten.join("\n\n")
141
+ end
142
+
143
+ protected
144
+
145
+ def deindent string
146
+ if match = string.match(/^([ \t]*)[^\s]/)
147
+ string.gsub(/^#{match[1]}/, '').strip
148
+ else
149
+ string.strip
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ require 'carrierwave'
3
+
4
+ module Landable
5
+ class AssetUploader < CarrierWave::Uploader::Base
6
+ include CarrierWave::MimeTypes
7
+ process :set_content_type
8
+ end
9
+ end