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
+ require 'spec_helper'
2
+
3
+ module Landable
4
+ describe TableName do
5
+
6
+ describe '#table_name' do
7
+ it 'should generate the correct table name' do
8
+ Page.send(:table_name).should == "#{Landable.configuration.database_schema_prefix}landable.pages"
9
+ PageRevision.send(:table_name).should == "#{Landable.configuration.database_schema_prefix}landable.page_revisions"
10
+ Theme.send(:table_name).should == "#{Landable.configuration.database_schema_prefix}landable.themes"
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable
4
+ module Traffic
5
+ describe TableName do
6
+
7
+ describe '#table_name' do
8
+ it 'should generate the correct table name' do
9
+ Visit.send(:table_name).should == "#{Landable.configuration.database_schema_prefix}landable_traffic.visits"
10
+ PageView.send(:table_name).should == "#{Landable.configuration.database_schema_prefix}landable_traffic.page_views"
11
+ end
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable
4
+ # descriptions
5
+ describe VariablesConcern, type: :controller do
6
+ # setup
7
+ controller(ApplicationController) do
8
+ protected
9
+ def hello_world
10
+ "i live in a giant bucket."
11
+ end
12
+
13
+ def hello_cleveland
14
+ "i am a banana."
15
+ end
16
+ end
17
+
18
+ after(:each) do
19
+ controller.class.imported_variables.clear
20
+ end
21
+
22
+ before(:each) do
23
+ controller.class.instance_exec do
24
+ register_landable_variable :hello_world
25
+ register_landable_variable :is_rejected, :hello_cleveland
26
+ end
27
+ end
28
+
29
+ # tests
30
+ it "should include the VariablesConcern module" do
31
+ # setup
32
+ # actions
33
+ # expectations
34
+ expect(controller).to be_a Landable::VariablesConcern
35
+ # end
36
+ end
37
+
38
+ it "should use the #register_landable_variable with a similarly named method" do
39
+ # setup
40
+ # actions
41
+ # expectations
42
+ expect(controller.fetch_landable_variables[:hello_world]).to eql("i live in a giant bucket.")
43
+ # end
44
+ end
45
+
46
+ it "should use the #register_landable_variable with a custom named method" do
47
+ # setup
48
+ # actions
49
+ # expectations
50
+ expect(controller.fetch_landable_variables[:is_rejected]).to eql("i am a banana.")
51
+ # end
52
+ end
53
+
54
+ it "should use the #register_landable_variable with a string-based name" do
55
+ # setup
56
+ # actions
57
+ # expectations
58
+ expect(controller.fetch_landable_variables['is_rejected']).to eql("i am a banana.")
59
+ # end
60
+ end
61
+
62
+ # end
63
+ end
64
+
65
+ # end
66
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable::Api
4
+ describe AssetsController, json: true do
5
+ routes { Landable::Engine.routes }
6
+
7
+ describe '#update' do
8
+ include_examples 'Authenticated API controller', :make_request
9
+
10
+ let(:asset) { create :asset, description: "Not updated" }
11
+
12
+ def make_request
13
+ put :update, id: asset.id, asset: { description: "Updated" }
14
+ end
15
+
16
+ it "updates the asset description" do
17
+ make_request
18
+ asset.reload
19
+ asset.description.should == "Updated"
20
+ end
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable::Api
4
+ describe CategoriesController, json: true do
5
+ routes { Landable::Engine.routes }
6
+
7
+ describe '#show' do
8
+ include_examples 'Authenticated API controller', :make_request
9
+
10
+ let(:category) { create :category }
11
+
12
+ def make_request(id = category.id)
13
+ get :show, id: id
14
+ end
15
+
16
+ it 'returns the selected category' do
17
+ make_request
18
+ response.status.should == 200
19
+ last_json['category']['id'].should == category.id
20
+ end
21
+
22
+ it '404s on page not found' do
23
+ make_request random_uuid
24
+ response.status.should == 404
25
+ end
26
+ end
27
+
28
+ describe '#index' do
29
+ include_examples 'Authenticated API controller', :make_request
30
+
31
+ def make_request
32
+ get :index
33
+ end
34
+
35
+ it 'returns all categories' do
36
+ Landable::Category.delete_all
37
+ create_list :category, 5
38
+
39
+ make_request
40
+ response.status.should == 200
41
+ last_json['categories'].size.should == 5
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable::Api
4
+ describe DirectoriesController, json: true do
5
+ routes { Landable::Engine.routes }
6
+
7
+ describe '#index' do
8
+ include_examples 'Authenticated API controller', :make_request
9
+
10
+ def make_request(ids = nil)
11
+ get :index, ids: ids
12
+ end
13
+
14
+ def dirs
15
+ last_json['directories']
16
+ end
17
+
18
+ def dir(path)
19
+ dirs.find { |dir| dir['id'] == path }
20
+ end
21
+
22
+ def subdirs(path)
23
+ dir(path)['subdirectory_ids']
24
+ end
25
+
26
+ def pages(path)
27
+ dir(path)['page_ids']
28
+ end
29
+
30
+ it 'defaults to the root path' do
31
+ pages = ['/a', '/b/c', '/b/d'].map { |path| create :page, path: path }
32
+ make_request
33
+ response.status.should == 200
34
+
35
+ dirs.length.should == 1
36
+ dirs.first['id'].should == '/'
37
+
38
+ subdirs('/').length.should == 1
39
+ pages('/').length.should == 1
40
+ end
41
+
42
+ it 'returns multiple directory listings' do
43
+ pages = ['/a', '/b/c', '/b/d', '/c/e', '/c/f/g'].map { |path| create :page, path: path }
44
+ make_request ['/b', '/c']
45
+ response.status.should == 200
46
+ dirs.length.should == 2
47
+
48
+ pages('/b').length.should == 2
49
+ pages('/c').length.should == 1
50
+
51
+ subdirs('/b').length.should == 0
52
+ subdirs('/c').length.should == 1
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable::Api
4
+ describe PageRevisionsController, json: true do
5
+ routes { Landable::Engine.routes }
6
+
7
+ describe '#index' do
8
+ include_examples 'Authenticated API controller', :make_request
9
+
10
+ let(:page) { create :page }
11
+
12
+ def make_request(page_id = page.id)
13
+ get :index, page_id: page_id
14
+ end
15
+
16
+ it "returns all of a page's revisions" do
17
+ page.publish! author: current_author
18
+ make_request
19
+ response.status.should == 200
20
+ last_json['page_revisions'].length.should == 1
21
+ end
22
+
23
+ it "404s on page not found" do
24
+ make_request random_uuid
25
+ response.status.should == 404
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,271 @@
1
+ require 'spec_helper'
2
+
3
+ module Landable::Api
4
+ describe PagesController, json: true do
5
+ routes { Landable::Engine.routes }
6
+
7
+ describe '#create' do
8
+ include_examples 'Authenticated API controller', :make_request
9
+
10
+ let(:default_params) do
11
+ { page: attributes_for(:page) }
12
+ end
13
+
14
+ let(:page) do
15
+ Landable::Page.where(path: default_params[:page][:path]).first
16
+ end
17
+
18
+ def make_request(params = {})
19
+ post :create, default_params.deep_merge(page: params)
20
+ end
21
+
22
+ context 'success' do
23
+ it 'returns 201 Created' do
24
+ make_request
25
+ response.status.should == 201
26
+ end
27
+
28
+ it 'returns header Location with the page URL' do
29
+ make_request
30
+ response.headers['Location'].should == page_url(page)
31
+ end
32
+
33
+ it 'renders the page as JSON' do
34
+ make_request
35
+ path, body = default_params[:page].values_at(:path, :body)
36
+ last_json['page'].should include('path' => path, 'body' => body)
37
+ end
38
+ end
39
+
40
+ context 'invalid' do
41
+ it 'returns 422 Unprocessable Entity' do
42
+ make_request path: nil
43
+ response.status.should == 422
44
+ end
45
+
46
+ it 'includes the errors in the JSON response' do
47
+ make_request status_code: 302, redirect_url: nil
48
+ last_json['errors'].should have_key('redirect_url')
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#index' do
54
+ include_examples 'Authenticated API controller', :make_request
55
+
56
+ let(:pages) { @pages ||= create_list(:page, 5) }
57
+ before(:each) { pages }
58
+
59
+ def make_request(params = {})
60
+ get :index, params
61
+ end
62
+
63
+ it 'renders pages as json' do
64
+ make_request
65
+ last_json['pages'].collect { |p| p['id'] }.sort.should == pages.map(&:id).sort
66
+ end
67
+
68
+ it 'filters pages according to requested ids' do
69
+ filtered_for_pages = pages[0..2]
70
+
71
+ make_request ids: filtered_for_pages.map(&:id)
72
+ last_json['pages'].collect { |p| p['id'] }.sort.should == filtered_for_pages.map(&:id).sort
73
+ end
74
+
75
+ describe 'search' do
76
+ describe 'by path' do
77
+ before(:each) do
78
+ ['/foo', '/foo/bar', '/foo/bar/baz', '/bar'].each do |path|
79
+ create :page, path: path
80
+ end
81
+ end
82
+
83
+ it 'filters by starting path fragment' do
84
+ make_request search: {path: '/foo/ba'}
85
+ last_json['pages'].collect { |p| p['path'] }.should == ['/foo/bar', '/foo/bar/baz']
86
+ end
87
+
88
+ it 'matches all paths with the search term in them' do
89
+ make_request search: {path: 'ba'}
90
+ last_json['pages'].collect { |p| p['path'] }.should == ['/bar', '/foo/bar', '/foo/bar/baz']
91
+ end
92
+ end
93
+ end
94
+
95
+ it 'only include 100 results, and include the total result count as meta data' do
96
+ create_list :page, (100 - pages.size)
97
+ make_request search: {path: '/'}
98
+
99
+ last_json['pages'].size.should == 100
100
+ last_json['meta']['search']['total_results'].should == 100
101
+ end
102
+ end
103
+
104
+ describe '#show' do
105
+ include_examples 'Authenticated API controller', :make_request
106
+ let(:page) { @page || create(:page) }
107
+
108
+ def make_request(id = page.id)
109
+ get :show, id: id
110
+ end
111
+
112
+ it 'renders the page as JSON' do
113
+ make_request
114
+ last_json['page']['body'].should == page.body
115
+ end
116
+
117
+ it 'includes an empty meta_tags hash instead of a null' do
118
+ page.update_attributes meta_tags: nil
119
+ make_request
120
+ last_json['page']['meta_tags'].should == {}
121
+ end
122
+
123
+
124
+ context 'no such page' do
125
+ it 'returns 404' do
126
+ make_request random_uuid
127
+ response.status.should == 404
128
+ end
129
+ end
130
+ end
131
+
132
+ describe '#update' do
133
+ include_examples 'Authenticated API controller', :make_request
134
+
135
+ let(:page) { @page || create(:page) }
136
+ let(:default_params) do
137
+ { page: { body: 'Different body content' } }
138
+ end
139
+
140
+ def make_request(changes = {})
141
+ id = changes.delete(:id) || page.id
142
+ patch :update, default_params.deep_merge(id: id, page: changes)
143
+ end
144
+
145
+ it 'saves the changes' do
146
+ make_request body: 'updated body!'
147
+ response.status.should == 200
148
+ page.reload.body.should == 'updated body!'
149
+ page.reload.updated_by_author.should == current_author
150
+ end
151
+
152
+ it 'renders the page as JSON' do
153
+ make_request body: 'also updated'
154
+ last_json['page']['body'].should == 'also updated'
155
+ end
156
+
157
+ context 'invalid' do
158
+ it 'returns 422 Unprocessable Entity' do
159
+ make_request path: nil
160
+ response.status.should == 422
161
+ end
162
+
163
+ it 'includes the errors in the JSON response' do
164
+ make_request status_code: 302, redirect_url: nil
165
+ end
166
+ end
167
+
168
+ context 'no such page' do
169
+ it 'returns 404' do
170
+ make_request id: random_uuid
171
+ response.status.should == 404
172
+ end
173
+ end
174
+
175
+ context 'stale page' do
176
+ it 'throws error when stale body update' do
177
+ page.save!
178
+ page1 = Landable::Page.first
179
+ page2 = Landable::Page.first
180
+
181
+ page1.body = "duh"
182
+ expect{ page1.save! }.to_not raise_error
183
+ page2.body = "something"
184
+ expect{ page2.save! }.to raise_error(ActiveRecord::StaleObjectError)
185
+ end
186
+
187
+ it 'throws error when stale meta_tags update' do
188
+ page.save!
189
+ page1 = Landable::Page.first
190
+ page2 = Landable::Page.first
191
+
192
+ page1.meta_tags = "duh"
193
+ expect{ page1.save! }.to_not raise_error
194
+ page2.meta_tags = "something"
195
+ expect{ page2.save! }.to raise_error(ActiveRecord::StaleObjectError)
196
+ end
197
+
198
+ it 'throws error when stale path update' do
199
+ page.save!
200
+ page1 = Landable::Page.first
201
+ page2 = Landable::Page.first
202
+
203
+ page1.body = "duh"
204
+ expect{ page1.save! }.to_not raise_error
205
+ page2.body = "something"
206
+ expect{ page2.save! }.to raise_error(ActiveRecord::StaleObjectError)
207
+ end
208
+
209
+ it 'throws error when stale multi-column update' do
210
+ page.save!
211
+ page1 = Landable::Page.first
212
+ page2 = Landable::Page.first
213
+ page1.body = "duh"
214
+ expect{ page1.save! }.to_not raise_error
215
+ page2.body = "something"
216
+ expect{ page2.save! }.to raise_error(ActiveRecord::StaleObjectError)
217
+ end
218
+ end
219
+ end
220
+
221
+ describe '#preview', json: false do
222
+ include_examples 'Authenticated API controller', :make_request
223
+ render_views
224
+
225
+ let(:theme) { create :theme, body: '<html><head>{% head_content %}</head><body>Theme content; page content: {{body}}</body></html>' }
226
+
227
+ before do
228
+ request.env['HTTP_ACCEPT'] = 'text/html'
229
+ end
230
+
231
+ def make_request(attributes = attributes_for(:page, theme_id: theme.id))
232
+ post :preview, page: attributes
233
+ end
234
+
235
+ it 'renders JSON' do
236
+ request.env['HTTP_ACCEPT'] = 'application/json'
237
+ make_request
238
+ response.status.should == 200
239
+ last_json['page']['preview'].should be_present
240
+ end
241
+
242
+ it 'renders the layout without content if the body is not present' do
243
+ request.env['HTTP_ACCEPT'] = 'application/json'
244
+ make_request attributes_for(:page, body: nil, theme_id: theme.id)
245
+ response.status.should == 200
246
+ last_json['page']['preview'].should include('Theme content')
247
+ end
248
+
249
+ it 'renders without a layout if no theme is present' do
250
+ request.env['HTTP_ACCEPT'] = 'application/json'
251
+ make_request attributes_for(:page, body: 'raw content', theme_id: nil)
252
+ response.status.should == 200
253
+ last_json['page']['preview'].should include('raw content')
254
+ end
255
+
256
+ it 'renders 30x pages with a link to the real thing' do
257
+ request.env['HTTP_ACCEPT'] = 'application/json'
258
+ make_request attributes_for(:page, :redirect, body: 'still here', theme_id: theme.id)
259
+ response.status.should == 200
260
+ last_json['page']['preview'].should include('301')
261
+ end
262
+
263
+ it 'renders 404 pages as if they were 200s' do
264
+ request.env['HTTP_ACCEPT'] = 'application/json'
265
+ make_request attributes_for(:page, :gone, body: 'still here', theme_id: theme.id)
266
+ response.status.should == 200
267
+ last_json['page']['preview'].should match(/still here/)
268
+ end
269
+ end
270
+ end
271
+ end