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,12 @@
1
+ class PathValidator < ActiveModel::Validator
2
+ def validate(record)
3
+ if match?(record.path)
4
+ record.errors[:path] << "is Reserved!"
5
+ end
6
+ end
7
+
8
+ def match?(path)
9
+ # See if the applying path matches any reserved_paths via a Regex
10
+ Landable.configuration.reserved_paths.any? { |reserved| Regexp.new("^#{reserved}$", 'i').match(path) }
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class UrlValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ valid = begin
5
+ value =~ /^[a-z]+\:\/\// or value =~ /^\//
6
+ end
7
+
8
+ unless valid
9
+ record.errors[attribute] << ("Invalid URL! Make sure it starts with http:// or /")
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,122 @@
1
+ {% if is_redirect %}
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <style type="text/css">
6
+ body {
7
+ font-family: sans-serif;
8
+ margin: 0;
9
+ background: #eee;
10
+ }
11
+
12
+ .message-wrapper, iframe {
13
+ position: absolute;
14
+ border: 0;
15
+ top: 0;
16
+ right: 0;
17
+ bottom: 0;
18
+ left: 0;
19
+ width: 100%;
20
+ height: 100%;
21
+ }
22
+
23
+ iframe {
24
+ z-index: 100;
25
+ -webkit-filter: blur(10px);
26
+ -moz-filter: blur(10px);
27
+ filter: blur(10px);
28
+ background: transparent;
29
+ }
30
+
31
+ .message-wrapper {
32
+ z-index: 200;
33
+ }
34
+
35
+ .message {
36
+ background: #fff;
37
+ width: 80%;
38
+ max-width: 400px;
39
+ padding: 1em;
40
+ margin: 10% auto auto auto;
41
+ text-align: center;
42
+ -moz-border-radius: 2px;
43
+ -webkit-border-radius: 2px;
44
+ border-radius: 2px;
45
+ border: 1px #ccc solid;
46
+ border-bottom-color: #aaa;
47
+ }
48
+
49
+ .status-code {
50
+ font-weight: bold;
51
+ }
52
+
53
+ .redirect-url {
54
+ display: block;
55
+ margin-top: 0.8em;
56
+ font-size: 1.2em;
57
+ }
58
+
59
+ .redirect-url a {
60
+ color: #466cd2;
61
+ }
62
+
63
+ .preview-mode {
64
+ font-size: 0.9em;
65
+ color: #777;
66
+ }
67
+ </style>
68
+ </head>
69
+ <body>
70
+ <div class="message-wrapper">
71
+ <div class="message">
72
+ <p>
73
+ This page will redirect (<span class="status-code">{{ status_code }}</span>) to:
74
+ <span class="redirect-url">
75
+ <a href="{{ redirect_url }}">{{ redirect_url }}</a>
76
+ </span>
77
+ </p>
78
+ <p class="preview-mode">(preview mode)</p>
79
+ </div>
80
+ </div>
81
+ <iframe src="{{ redirect_url }}" seamless="seamless">
82
+ </body>
83
+ </html>
84
+ {% else %}
85
+ <!-- pretty invalid, this is -->
86
+ <style type="text/css">
87
+ body {
88
+ padding-top: 40px;
89
+ }
90
+
91
+ body:before {
92
+ text-align: center;
93
+ font-weight: bold;
94
+ background-color: #FFDA73;
95
+ font-family: Roboto;
96
+ width: 100%;
97
+ position: absolute;
98
+ top: 0;
99
+ 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
+ box-sizing: border-box;
106
+ height: 40px;
107
+ }
108
+
109
+ body.publicist-preview {
110
+ padding-top: 0;
111
+ }
112
+
113
+ body.publicist-preview:before {
114
+ display: none;
115
+ }
116
+ </style>
117
+ <!-- Body Tag for handling Preview Message -->
118
+ <body>
119
+ {{ content }}
120
+ </body>
121
+
122
+ {% endif %}
data/bin/rails ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/landable/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'
data/bin/redb ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+ rm spec/dummy/db/structure.sql
3
+
4
+ bundle exec rake app:db:drop:all
5
+ bundle exec rake app:db:create:all
6
+ bundle exec rake app:db:migrate
7
+ bundle exec rake app:db:migrate RAILS_ENV=test
data/config.ru ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+ run Combustion::Application
@@ -0,0 +1,5 @@
1
+ <%
2
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --guess"
3
+ %>
4
+ default: <%= std_opts %> features
5
+ wip: --tags @wip:3 --wip features
data/config/routes.rb ADDED
@@ -0,0 +1,62 @@
1
+ Landable::Engine.routes.draw do
2
+ scope path: Landable.configuration.api_namespace, module: 'api' do
3
+ resources :access_tokens, only: [:create, :update, :destroy]
4
+ resources :categories, only: [:index, :show]
5
+ resources :status_codes, only: [:index]
6
+
7
+ resources :directories, only: [:index, :show], constraints: {
8
+ id: /[%a-zA-Z0-9\/_.~-]*/
9
+ }
10
+
11
+ resources :assets, only: [:index, :show, :create, :update]
12
+
13
+ concern :has_assets do
14
+ resources :assets, only: [:index, :update, :destroy]
15
+ end
16
+
17
+ concern :has_screenshots do
18
+ post 'screenshots', on: :member
19
+ end
20
+
21
+ resources :themes, only: [:index, :show, :create, :update], concerns: :has_assets do
22
+ post 'preview', on: :collection
23
+ end
24
+
25
+ resources :templates, only: [:index, :show, :create, :update]
26
+
27
+ resources :pages, concerns: [:has_assets, :has_screenshots] do
28
+ post 'preview', on: :collection
29
+ post 'publish', on: :member
30
+ end
31
+
32
+ resources :page_revisions, only: [:index, :show], concerns: [:has_screenshots] do
33
+ post 'revert_to', on: :member
34
+ end
35
+
36
+ resources :access_tokens, only: [:create, :destroy, :show]
37
+
38
+
39
+ # coming soon: screenshots!
40
+
41
+ # resources :screenshots, only: [:index, :show, :create] do
42
+ # post 'callback', on: :collection
43
+ # post 'resubmit', on: :member
44
+ # end
45
+
46
+ # resources :browsers, only: [:index, :show]
47
+ end
48
+
49
+ scope module: 'public', as: :public do
50
+ scope '-', module: 'preview', as: :preview do
51
+ resources :pages, path: 'p', only: [:show]
52
+ resources :page_revisions, path: 'pr', only: [:show]
53
+ end
54
+
55
+ get '/sitemap.xml' => 'sitemap#index', as: :sitemap
56
+
57
+ get '*url' => 'pages#show', as: :page, format: false, constraints: lambda { |request|
58
+ # Published Landable Page
59
+ Landable::PageRevision.table_exists? && Landable::PageRevision.where(path: request.path, is_published: true).any?
60
+ }
61
+ end
62
+ end
@@ -0,0 +1,338 @@
1
+ class CreateLandableSchema < Landable::Migration
2
+ def change
3
+ # This really should not be in this migration, but it's a convenient location
4
+ # while everything's still under development.
5
+ #
6
+ # TODO extract to a separate migration, check if it exists, maybe check if we
7
+ # actually have permission to do it, etc.
8
+ enable_extension "uuid-ossp"
9
+ enable_extension "hstore"
10
+ enable_extension "pg_trgm"
11
+
12
+ execute "CREATE SCHEMA #{Landable.configuration.database_schema_prefix}landable;"
13
+
14
+
15
+ ## status_codes
16
+
17
+ create_table "#{Landable.configuration.database_schema_prefix}landable.status_code_categories", id: :uuid, primary_key: :status_code_category_id do |t|
18
+ t.text :name, null: false
19
+ end
20
+
21
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_status_code_categories__u_name ON #{Landable.configuration.database_schema_prefix}landable.status_code_categories(lower(name))"
22
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.status_code_categories IS
23
+ $$Categories that status codes belong to. Used to affect behavior when viewing a page.$$"
24
+
25
+ create_table "#{Landable.configuration.database_schema_prefix}landable.status_codes", id: :uuid, primary_key: :status_code_id do |t|
26
+ t.uuid :status_code_category_id, null: false
27
+ t.integer :code, null: false, limit: 2 # Creates as smallint
28
+ t.text :description, null: false
29
+ end
30
+
31
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_status_codes__u_code ON #{Landable.configuration.database_schema_prefix}landable.status_codes(code)"
32
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.status_codes ADD CONSTRAINT status_code_category_fk FOREIGN KEY(status_code_category_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.status_code_categories(status_code_category_id)"
33
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.status_codes IS
34
+ $$Allowed status codes that pages can be set to.$$"
35
+
36
+
37
+ ## themes
38
+
39
+ create_table "#{Landable.configuration.database_schema_prefix}landable.themes", id: :uuid, primary_key: :theme_id do |t|
40
+ t.text :name, null: false
41
+ t.text :body, null: false
42
+ t.text :description, null: false
43
+ t.text :thumbnail_url
44
+ t.timestamps
45
+ end
46
+
47
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_themes__u_name ON #{Landable.configuration.database_schema_prefix}landable.themes(lower(name))"
48
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.themes IS
49
+ $$Created themes to be consumed by pages. Themes supply formatting (css) rules and can supply header/footer content as well.$$"
50
+
51
+
52
+ ## templates
53
+
54
+ create_table "#{Landable.configuration.database_schema_prefix}landable.templates", id: :uuid, primary_key: :template_id do |t|
55
+ t.text :name, null: false
56
+ t.text :slug, null: false
57
+ t.text :body, null: false
58
+ t.text :description, null: false
59
+ t.text :thumbnail_url
60
+ t.boolean :is_layout, null: false, default: false
61
+ t.timestamps
62
+ end
63
+
64
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_templates__u_name ON #{Landable.configuration.database_schema_prefix}landable.templates(lower(name))"
65
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.templates IS
66
+ $$Created templates to be consumed by pages.
67
+ A template can supply 'starter' code for a page.
68
+ A template can also supply code to create elements on a page (sidebars, for example).$$"
69
+
70
+ ## pages
71
+
72
+ create_table "#{Landable.configuration.database_schema_prefix}landable.pages", id: :uuid, primary_key: :page_id do |t|
73
+ t.uuid :published_revision_id
74
+ t.boolean :is_publishable, null: false, default: true
75
+
76
+ t.uuid :theme_id
77
+ t.uuid :category_id
78
+ t.uuid :status_code_id, null: false
79
+
80
+ t.text :path, null: false
81
+
82
+ t.text :title
83
+ t.text :body
84
+
85
+ t.text :redirect_url
86
+
87
+ t.hstore :meta_tags
88
+
89
+ t.timestamp :imported_at
90
+ t.timestamps
91
+ end
92
+
93
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_pages__u_path ON #{Landable.configuration.database_schema_prefix}landable.pages(lower(path))"
94
+ execute "CREATE INDEX #{Landable.configuration.database_schema_prefix}landable_pages__trgm_path ON #{Landable.configuration.database_schema_prefix}landable.pages USING gin(path gin_trgm_ops)"
95
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.pages IS
96
+ $$Pages serve as a draft, where you can make changes, preview and save those changes without having to update the live page on the website.
97
+ Pages also point to their published version, where applicable.$$"
98
+
99
+ ## head_tags
100
+
101
+ create_table "#{Landable.configuration.database_schema_prefix}landable.head_tags", id: :uuid, primary_key: :head_tag_id do |t|
102
+ t.uuid :page_id
103
+ t.text :content, null: false
104
+ t.timestamps
105
+ end
106
+
107
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.head_tags ADD CONSTRAINT page_id_fk FOREIGN KEY (page_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.pages(page_id)"
108
+
109
+ ## authors
110
+
111
+ create_table "#{Landable.configuration.database_schema_prefix}landable.authors", id: :uuid, primary_key: :author_id do |t|
112
+ t.text :email, null: false
113
+ t.text :username, null: false
114
+ t.text :first_name, null: false
115
+ t.text :last_name, null: false
116
+ t.timestamps
117
+ end
118
+
119
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_authors__u_email ON #{Landable.configuration.database_schema_prefix}landable.authors(lower(email))"
120
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_authors__u_username ON #{Landable.configuration.database_schema_prefix}landable.authors(username)"
121
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.authors IS
122
+ $$A list of authors that have accessed the website. Feeds foreign keys so we know which authors have published pages and updated assets.$$"
123
+
124
+
125
+ ## access_tokens
126
+
127
+ create_table "#{Landable.configuration.database_schema_prefix}landable.access_tokens", id: :uuid, primary_key: :access_token_id do |t|
128
+ t.uuid :author_id, null: false
129
+ t.timestamp :expires_at, null: false
130
+ t.timestamps
131
+ end
132
+
133
+ execute "CREATE INDEX #{Landable.configuration.database_schema_prefix}landable_access_tokens__author_id ON #{Landable.configuration.database_schema_prefix}landable.access_tokens(author_id)"
134
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.access_tokens ADD CONSTRAINT author_id_fk FOREIGN KEY (author_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.authors(author_id)"
135
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.access_tokens IS
136
+ $$Access tokens provide authentication information for specific users.$$"
137
+
138
+
139
+ ## page_revisions
140
+
141
+ create_table "#{Landable.configuration.database_schema_prefix}landable.page_revisions", id: :uuid, primary_key: :page_revision_id do |t|
142
+ t.integer :ordinal
143
+ t.text :notes
144
+ t.boolean :is_minor, default: false
145
+ t.boolean :is_published, default: true
146
+
147
+ t.uuid :page_id, null: false
148
+ t.uuid :author_id, null: false
149
+
150
+ t.text :snapshot_attributes, null: false
151
+
152
+ t.timestamps
153
+ end
154
+
155
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.page_revisions IS
156
+ $$Page revisions serve as a historical reference to pages as they were published.
157
+ The attributes of the page at the time of publishing are stored in snapshot_attributes, as essentially a text representation of a hash.
158
+ The current/active/live revision can be identified by referring to its corresponding PAGES record, OR by looking for the max(ordinal) for a given page_id.$$"
159
+
160
+
161
+ ## categories
162
+
163
+ create_table "#{Landable.configuration.database_schema_prefix}landable.categories", id: :uuid, primary_key: :category_id do |t|
164
+ t.text :name
165
+ t.text :description
166
+ end
167
+
168
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_categories__u_name ON #{Landable.configuration.database_schema_prefix}landable.categories(lower(name))"
169
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.categories IS
170
+ $$Categories are used to sort pages.
171
+ Examples could include SEO, PPC.$$"
172
+
173
+
174
+ ## assets
175
+
176
+ create_table "#{Landable.configuration.database_schema_prefix}landable.assets", id: :uuid, primary_key: :asset_id do |t|
177
+ t.uuid :author_id, null: false
178
+ t.text :name, null: false
179
+ t.text :description
180
+ t.text :data, null: false
181
+ t.text :md5sum, null: false, length: 32
182
+ t.text :mime_type, null: false
183
+ t.integer :file_size
184
+ t.timestamps
185
+ end
186
+
187
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_assets__u_lower_name ON #{Landable.configuration.database_schema_prefix}landable.assets(lower(name))"
188
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_assets__u_data ON #{Landable.configuration.database_schema_prefix}landable.assets(data)"
189
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_assets__u_md5sum ON #{Landable.configuration.database_schema_prefix}landable.assets(md5sum)"
190
+ execute "CREATE INDEX #{Landable.configuration.database_schema_prefix}landable_assets__author_id ON #{Landable.configuration.database_schema_prefix}landable.assets(author_id)"
191
+
192
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.assets ADD CONSTRAINT author_id_fk FOREIGN KEY (author_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.authors(author_id)"
193
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.assets IS
194
+ $$List of all assets uploaded.
195
+ Examples of assets include images (jpg, png, gif) and documents (PDF).
196
+ data, md5sum, mime_type, file_size are populated via the rails gem CarrierWave when a record is created.$$"
197
+
198
+
199
+ ## browsers
200
+
201
+ create_table "#{Landable.configuration.database_schema_prefix}landable.browsers", id: :uuid, primary_key: :browser_id do |t|
202
+ t.text :device
203
+ t.text :os, null: false
204
+ t.text :os_version, null: false
205
+ t.text :browser
206
+ t.text :browser_version
207
+
208
+ t.boolean :screenshots_supported, null: false, default: false
209
+ t.boolean :is_primary, null: false, default: false
210
+
211
+ t.timestamps
212
+ end
213
+
214
+ execute "CREATE INDEX #{Landable.configuration.database_schema_prefix}landable_screenshots__device_browser_browser_version ON #{Landable.configuration.database_schema_prefix}landable.browsers(device, browser, browser_version)"
215
+
216
+
217
+ ## screenshots
218
+
219
+ create_table "#{Landable.configuration.database_schema_prefix}landable.screenshots", id: :uuid, primary_key: :screenshot_id do |t|
220
+ t.uuid :screenshotable_id, null: false
221
+ t.text :screenshotable_type, null: false
222
+
223
+ t.uuid :browser_id
224
+
225
+ t.text :state
226
+ t.text :thumb_url
227
+ t.text :image_url
228
+
229
+ t.text :browserstack_id
230
+ t.text :browserstack_job_id
231
+
232
+ t.timestamps
233
+ end
234
+
235
+ execute "CREATE INDEX #{Landable.configuration.database_schema_prefix}landable_screenshots__screenshotable_id_screenshotable_type_state ON #{Landable.configuration.database_schema_prefix}landable.screenshots(screenshotable_id, screenshotable_type, state)"
236
+ execute "CREATE INDEX #{Landable.configuration.database_schema_prefix}landable_screenshots__state ON #{Landable.configuration.database_schema_prefix}landable.screenshots(state)"
237
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_screenshots__u_browserstack_id ON #{Landable.configuration.database_schema_prefix}landable.screenshots(browserstack_id)"
238
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.screenshots ADD CONSTRAINT browser_id_fk FOREIGN KEY (browser_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.browsers(browser_id)"
239
+ execute "COMMENT ON TABLE #{Landable.configuration.database_schema_prefix}landable.screenshots IS
240
+ $$Stores saved screenshots (taken of pages) and the URLs to retrieve the actual image.$$"
241
+
242
+
243
+ ## asset associations table
244
+
245
+ create_table "#{Landable.configuration.database_schema_prefix}landable.page_assets", id: :uuid, primary_key: :page_asset_id do |t|
246
+ t.uuid :page_id, null: false
247
+ t.uuid :asset_id, null: false
248
+ end
249
+
250
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_page_assets__u_page_id_asset_id ON #{Landable.configuration.database_schema_prefix}landable.page_assets (page_id, asset_id)"
251
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_assets ADD CONSTRAINT page_id_fk FOREIGN KEY (page_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.pages(page_id)"
252
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_assets ADD CONSTRAINT asset_id_fk FOREIGN KEY (asset_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.assets(asset_id)"
253
+
254
+ create_table "#{Landable.configuration.database_schema_prefix}landable.page_revision_assets", id: :uuid, primary_key: :page_revision_asset_id do |t|
255
+ t.uuid :page_revision_id, null: false
256
+ t.uuid :asset_id, null: false
257
+ end
258
+
259
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_page_revision_assets__u_page_revision_id_asset_id ON #{Landable.configuration.database_schema_prefix}landable.page_revision_assets (page_revision_id, asset_id)"
260
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_revision_assets ADD CONSTRAINT page_revision_id_fk FOREIGN KEY (page_revision_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.page_revisions(page_revision_id)"
261
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_revision_assets ADD CONSTRAINT asset_id_fk FOREIGN KEY (asset_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.assets(asset_id)"
262
+
263
+ create_table "#{Landable.configuration.database_schema_prefix}landable.theme_assets", id: :uuid, primary_key: :theme_asset_id do |t|
264
+ t.uuid :theme_id, null: false
265
+ t.uuid :asset_id, null: false
266
+ end
267
+
268
+ execute "CREATE UNIQUE INDEX #{Landable.configuration.database_schema_prefix}landable_theme_assets__u_theme_id_asset_id ON #{Landable.configuration.database_schema_prefix}landable.theme_assets (theme_id, asset_id)"
269
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.theme_assets ADD CONSTRAINT theme_id_fk FOREIGN KEY (theme_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.themes(theme_id)"
270
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.theme_assets ADD CONSTRAINT asset_id_fk FOREIGN KEY (asset_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.assets(asset_id)"
271
+
272
+ ## other stuff
273
+
274
+ # Constraints for page_revisions
275
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_revisions ADD CONSTRAINT page_id_fk FOREIGN KEY (page_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.pages(page_id)"
276
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.page_revisions ADD CONSTRAINT author_id_fk FOREIGN KEY (author_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.authors(author_id)"
277
+
278
+ # Constraints for pages
279
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.pages ADD CONSTRAINT revision_id_fk FOREIGN KEY (published_revision_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.page_revisions(page_revision_id)"
280
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.pages ADD CONSTRAINT theme_id_fk FOREIGN KEY (theme_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.themes(theme_id)"
281
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.pages ADD CONSTRAINT category_id_fk FOREIGN KEY (category_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.categories(category_id)"
282
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.pages ADD CONSTRAINT status_code_fk FOREIGN KEY (status_code_id) REFERENCES #{Landable.configuration.database_schema_prefix}landable.status_codes(status_code_id)"
283
+ execute "ALTER TABLE #{Landable.configuration.database_schema_prefix}landable.pages ADD CONSTRAINT only_valid_paths CHECK (path ~ '^/[a-zA-Z0-9/_.~-]*$');"
284
+
285
+ # Revision-tracking trigger to automatically update ordinal
286
+ execute "CREATE FUNCTION #{Landable.configuration.database_schema_prefix}landable.pages_revision_ordinal()
287
+ RETURNS TRIGGER
288
+ AS
289
+ $TRIGGER$
290
+ BEGIN
291
+
292
+ IF NEW.ordinal IS NOT NULL THEN
293
+ RAISE EXCEPTION $$Must not supply ordinal value manually.$$;
294
+ END IF;
295
+
296
+ NEW.ordinal = (SELECT COALESCE(MAX(ordinal)+1,1)
297
+ FROM #{Landable.configuration.database_schema_prefix}landable.page_revisions
298
+ WHERE page_id = NEW.page_id);
299
+
300
+ RETURN NEW;
301
+
302
+ END
303
+ $TRIGGER$
304
+ LANGUAGE plpgsql;"
305
+
306
+ execute "CREATE TRIGGER #{Landable.configuration.database_schema_prefix}landable_page_revisions__bfr_insert
307
+ BEFORE INSERT ON #{Landable.configuration.database_schema_prefix}landable.page_revisions
308
+ FOR EACH ROW EXECUTE PROCEDURE #{Landable.configuration.database_schema_prefix}landable.pages_revision_ordinal();"
309
+
310
+ # Trigger disallowing deletes on page_revisions
311
+ execute "CREATE FUNCTION #{Landable.configuration.database_schema_prefix}landable.tg_disallow()
312
+ RETURNS TRIGGER
313
+ AS
314
+ $TRIGGER$
315
+ BEGIN
316
+
317
+ IF TG_LEVEL <> 'STATEMENT' THEN
318
+ RAISE EXCEPTION $$You should use a statement-level trigger (trigger %, table %)$$, TG_NAME, TG_RELID::regclass;
319
+ END IF;
320
+
321
+ RAISE EXCEPTION $$%s are not allowed on table %$$, TG_OP, TG_RELNAME;
322
+
323
+ RETURN NULL;
324
+
325
+ END
326
+ $TRIGGER$
327
+ LANGUAGE plpgsql;"
328
+
329
+ execute "CREATE TRIGGER #{Landable.configuration.database_schema_prefix}landable_page_revisions__no_delete
330
+ BEFORE DELETE ON #{Landable.configuration.database_schema_prefix}landable.page_revisions
331
+ FOR EACH STATEMENT EXECUTE PROCEDURE #{Landable.configuration.database_schema_prefix}landable.tg_disallow();"
332
+
333
+ execute "CREATE TRIGGER #{Landable.configuration.database_schema_prefix}landable_page_revisions__no_update
334
+ BEFORE UPDATE OF notes, is_minor, page_id, author_id, created_at, ordinal ON #{Landable.configuration.database_schema_prefix}landable.page_revisions
335
+ FOR EACH STATEMENT EXECUTE PROCEDURE #{Landable.configuration.database_schema_prefix}landable.tg_disallow();"
336
+
337
+ end
338
+ end