storytime 2.1.6 → 2.1.7

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 (236) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +54 -0
  3. data/.gitignore +2 -1
  4. data/.ruby-version +1 -1
  5. data/.tool-versions +1 -0
  6. data/Gemfile +5 -3
  7. data/Gemfile.lock +414 -425
  8. data/Guardfile +1 -1
  9. data/app/assets/fonts/storytime-icons.eot +0 -0
  10. data/app/assets/fonts/storytime-icons.svg +23 -0
  11. data/app/assets/fonts/storytime-icons.ttf +0 -0
  12. data/app/assets/fonts/storytime-icons.woff +0 -0
  13. data/app/assets/javascripts/storytime/application.js +1 -8
  14. data/app/assets/javascripts/storytime/off_canvas.coffee +16 -0
  15. data/app/assets/javascripts/storytime/wysiwyg.js.coffee +9 -7
  16. data/app/assets/stylesheets/storytime/_buttons.scss +33 -0
  17. data/app/assets/stylesheets/storytime/_list-group.scss +1 -1
  18. data/app/assets/stylesheets/storytime/application.scss +14 -2
  19. data/app/assets/stylesheets/storytime/icons.scss +5 -5
  20. data/app/assets/stylesheets/storytime/leather/_buttons.scss +31 -0
  21. data/app/assets/stylesheets/storytime/leather/_devise.scss +72 -0
  22. data/app/assets/stylesheets/storytime/leather/_grid.scss +19 -0
  23. data/app/assets/stylesheets/storytime/leather/_list_groups.scss +33 -0
  24. data/app/assets/stylesheets/storytime/leather/_nav_menus.scss +125 -0
  25. data/app/assets/stylesheets/storytime/leather/_navbar_transparent.scss +23 -0
  26. data/app/assets/stylesheets/storytime/leather/_off_canvas.scss +109 -0
  27. data/app/assets/stylesheets/storytime/leather/_scroll_panels.scss +85 -0
  28. data/app/assets/stylesheets/storytime/leather/_toggle_columns.scss +23 -0
  29. data/app/assets/stylesheets/storytime/leather/_typography.scss +12 -0
  30. data/app/assets/stylesheets/storytime/leather/_utilities.scss +54 -0
  31. data/app/assets/stylesheets/storytime/leather/_variables.scss +8 -0
  32. data/app/assets/stylesheets/storytime/posts.scss +9 -1
  33. data/app/controllers/storytime/application_controller.rb +1 -1
  34. data/app/controllers/storytime/dashboard/blog_posts_controller.rb +5 -3
  35. data/app/controllers/storytime/dashboard/blogs_controller.rb +1 -1
  36. data/app/controllers/storytime/dashboard/media_controller.rb +4 -4
  37. data/app/controllers/storytime/dashboard/memberships_controller.rb +1 -1
  38. data/app/controllers/storytime/dashboard/pages_controller.rb +26 -6
  39. data/app/controllers/storytime/dashboard/posts_controller.rb +30 -5
  40. data/app/controllers/storytime/dashboard/subscriptions_controller.rb +1 -1
  41. data/app/controllers/storytime/pages_controller.rb +31 -1
  42. data/app/controllers/storytime/posts_controller.rb +1 -1
  43. data/app/controllers/storytime/subscriptions_controller.rb +5 -1
  44. data/app/helpers/storytime/application_helper.rb +0 -4
  45. data/app/models/concerns/storytime/post_featured_images.rb +2 -2
  46. data/app/models/concerns/storytime/post_partial_inheritance.rb +2 -2
  47. data/app/models/storytime/autosave.rb +1 -1
  48. data/app/models/storytime/comment.rb +1 -1
  49. data/app/models/storytime/media.rb +1 -1
  50. data/app/models/storytime/membership.rb +2 -2
  51. data/app/models/storytime/post.rb +7 -3
  52. data/app/models/storytime/site.rb +4 -6
  53. data/app/models/storytime/snippet.rb +12 -1
  54. data/app/models/storytime/subscription.rb +2 -2
  55. data/app/models/storytime/version.rb +1 -1
  56. data/app/policies/storytime/post_policy.rb +1 -1
  57. data/app/views/storytime/dashboard/_navigation.html.erb +0 -9
  58. data/app/views/storytime/dashboard/blog_posts/_form.html.erb +5 -1
  59. data/app/views/storytime/dashboard/blogs/edit.json.jbuilder +1 -1
  60. data/app/views/storytime/dashboard/blogs/index.json.jbuilder +1 -1
  61. data/app/views/storytime/dashboard/blogs/new.json.jbuilder +1 -1
  62. data/app/views/storytime/dashboard/media/_gallery.html.erb +1 -1
  63. data/app/views/storytime/dashboard/media/_modal.html.erb +2 -2
  64. data/app/views/storytime/dashboard/media/show.json.jbuilder +1 -1
  65. data/app/views/storytime/dashboard/memberships/_edit.html.erb +1 -1
  66. data/app/views/storytime/dashboard/memberships/_index.html.erb +3 -3
  67. data/app/views/storytime/dashboard/memberships/_new.html.erb +1 -1
  68. data/app/views/storytime/dashboard/memberships/edit.json.jbuilder +1 -1
  69. data/app/views/storytime/dashboard/memberships/index.json.jbuilder +1 -1
  70. data/app/views/storytime/dashboard/memberships/new.json.jbuilder +1 -1
  71. data/app/views/storytime/dashboard/memberships/save.json.jbuilder +1 -1
  72. data/app/views/storytime/dashboard/pages/_form.html.erb +1 -1
  73. data/app/views/storytime/dashboard/posts/_directory.html.erb +18 -0
  74. data/app/views/storytime/dashboard/posts/_form.html.erb +1 -1
  75. data/app/views/storytime/dashboard/posts/_list.html.erb +2 -26
  76. data/app/views/storytime/dashboard/posts/_new_button.html.erb +1 -1
  77. data/app/views/storytime/dashboard/posts/_post.html.erb +28 -0
  78. data/app/views/storytime/dashboard/posts/_sorts.html.erb +21 -0
  79. data/app/views/storytime/dashboard/posts/index.html.erb +5 -3
  80. data/app/views/storytime/dashboard/roles/_form.html.erb +1 -1
  81. data/app/views/storytime/dashboard/roles/edit.json.jbuilder +1 -1
  82. data/app/views/storytime/dashboard/sites/_form.html.erb +1 -1
  83. data/app/views/storytime/dashboard/sites/site.json.jbuilder +1 -1
  84. data/app/views/storytime/dashboard/snippets/_index.html.erb +1 -1
  85. data/app/views/storytime/dashboard/snippets/edit.json.jbuilder +1 -1
  86. data/app/views/storytime/dashboard/snippets/index.json.jbuilder +1 -1
  87. data/app/views/storytime/dashboard/snippets/new.json.jbuilder +1 -1
  88. data/app/views/storytime/dashboard/subscriptions/_form.html.erb +1 -1
  89. data/app/views/storytime/dashboard/subscriptions/_index.html.erb +2 -2
  90. data/app/views/storytime/dashboard/subscriptions/form.json.jbuilder +1 -1
  91. data/app/views/storytime/dashboard/subscriptions/index.json.jbuilder +1 -1
  92. data/app/views/storytime/dashboard/versions/_versions_info.html.erb +1 -1
  93. data/app/views/storytime/posts/show.html.erb +6 -0
  94. data/app/views/storytime/sites/_google_analytics_code.html.erb +5 -8
  95. data/config/initializers/assets.rb +2 -1
  96. data/config/initializers/friendly_id.rb +1 -1
  97. data/config/initializers/url_for_patch.rb +19 -8
  98. data/config/locales/devise.zh-CN.yml +59 -0
  99. data/config/locales/kaminari.zh-CN.yml +17 -0
  100. data/config/locales/simple_form.zh-CN.yml +26 -0
  101. data/config/locales/zh-CN.yml +141 -0
  102. data/config/routes.rb +2 -4
  103. data/db/migrate/20140501174341_create_storytime_posts.rb +1 -1
  104. data/db/migrate/20140509191309_create_friendly_id_slugs.rb +1 -1
  105. data/db/migrate/20140511200849_create_storytime_media.rb +1 -1
  106. data/db/migrate/20140513161233_create_storytime_sites.rb +1 -1
  107. data/db/migrate/20140514200234_create_storytime_tags.rb +1 -1
  108. data/db/migrate/20140514200304_create_storytime_taggings.rb +1 -1
  109. data/db/migrate/20140516141252_create_storytime_versions.rb +1 -1
  110. data/db/migrate/20140521190606_create_storytime_roles.rb +1 -1
  111. data/db/migrate/20140521191048_add_storytime_role_id_to_users.rb +1 -1
  112. data/db/migrate/20140521191728_create_storytime_permissions.rb +1 -1
  113. data/db/migrate/20140521191744_create_storytime_actions.rb +1 -1
  114. data/db/migrate/20140813014447_create_storytime_comments.rb +1 -1
  115. data/db/migrate/20140813130534_add_storytime_name_to_users.rb +1 -1
  116. data/db/migrate/20140916183056_create_storytime_autosaves.rb +1 -1
  117. data/db/migrate/20141020213343_add_secondary_media_id_to_storytime_post.rb +1 -1
  118. data/db/migrate/20141021073356_create_storytime_snippets.rb +1 -1
  119. data/db/migrate/20141111164439_create_storytime_subscriptions.rb +1 -1
  120. data/db/migrate/20150122200805_add_title_and_content_index_to_storytime_post.rb +1 -1
  121. data/db/migrate/20150128185746_seed_new_actions_and_permissions.rb +1 -1
  122. data/db/migrate/20150129215308_add_site_id_to_storytime_subscription.rb +1 -1
  123. data/db/migrate/20150206201847_add_site_id_to_storytime_post.rb +1 -1
  124. data/db/migrate/20150206201919_add_site_id_to_storytime_snippet.rb +1 -1
  125. data/db/migrate/20150206201931_add_site_id_to_storytime_tag.rb +1 -1
  126. data/db/migrate/20150206205256_add_notification_fields_to_storytime_post.rb +1 -1
  127. data/db/migrate/20150216211257_add_subdomain_to_storytime_sites.rb +1 -1
  128. data/db/migrate/20150216225045_add_site_to_storytime_media.rb +1 -1
  129. data/db/migrate/20150219210528_remove_root_page_content_from_storytime_sites.rb +1 -1
  130. data/db/migrate/20150220184902_add_blog_id_to_posts.rb +1 -1
  131. data/db/migrate/20150224192138_add_homepage_path_to_storytime_sites.rb +1 -1
  132. data/db/migrate/20150224193151_add_subscription_email_from_to_storytime_sites.rb +1 -1
  133. data/db/migrate/20150224193551_add_layout_to_storytime_sites.rb +1 -1
  134. data/db/migrate/20150224194559_add_disqus_forum_shortname_to_storytime_sites.rb +1 -1
  135. data/db/migrate/20150224212453_remove_homepage_path_from_storytime_sites.rb +1 -1
  136. data/db/migrate/20150225143516_add_site_id_to_storytime_autosaves.rb +1 -1
  137. data/db/migrate/20150225143826_add_site_id_to_storytime_comments.rb +1 -1
  138. data/db/migrate/20150225145119_add_site_id_to_storytime_versions.rb +1 -1
  139. data/db/migrate/20150225145316_add_site_id_to_storytime_taggings.rb +1 -1
  140. data/db/migrate/20150225145608_update_storytime_site_id_columns.rb +1 -1
  141. data/db/migrate/20150225164232_add_site_id_to_storytime_permissions.rb +1 -1
  142. data/db/migrate/20150225212917_create_storytime_memberships.rb +1 -1
  143. data/db/migrate/20150225213535_create_memberships_for_storytime_users.rb +1 -1
  144. data/db/migrate/20150226201739_add_custom_domain_to_storytime_sites.rb +1 -1
  145. data/db/migrate/20150302171500_add_site_id_to_storytime_media.rb +1 -1
  146. data/db/migrate/20150302171722_set_site_layout.rb +1 -1
  147. data/db/migrate/20150302185138_remove_storytime_role_id_from_users.rb +1 -1
  148. data/db/migrate/20150302192525_transfer_posts_to_blogs.rb +1 -1
  149. data/db/migrate/20150302192759_seed_permissions.rb +1 -1
  150. data/db/migrate/20150331162329_add_discourse_name_to_storytime_sites.rb +1 -1
  151. data/db/migrate/20150402161427_remove_subdomain_from_storytime_site.rb +1 -1
  152. data/db/migrate/20150520181115_create_storytime_navigations.rb +1 -1
  153. data/db/migrate/20150520185227_create_storytime_links.rb +1 -1
  154. data/db/migrate/20150520190700_add_position_to_storytime_links.rb +1 -1
  155. data/db/migrate/20150529192058_add_url_to_storytime_links.rb +1 -1
  156. data/db/migrate/20260408001637_add_canonical_url_to_storytime_posts.rb +5 -0
  157. data/db/migrate/20260701000000_sanitize_existing_storytime_snippets.rb +22 -0
  158. data/lib/storytime/cli/install.rb +2 -20
  159. data/lib/storytime/concerns/action_controller_extension.rb +36 -0
  160. data/lib/storytime/constraints/page_constraint.rb +8 -2
  161. data/lib/storytime/engine.rb +3 -5
  162. data/lib/storytime/migrators/v1.rb +3 -3
  163. data/lib/storytime/post_notifier.rb +1 -1
  164. data/lib/storytime/post_url_handler.rb +18 -5
  165. data/lib/storytime/storytime_helpers.rb +4 -0
  166. data/lib/storytime/version.rb +1 -1
  167. data/lib/storytime.rb +1 -1
  168. data/spec/controllers/dashboard_controller_spec.rb +5 -6
  169. data/spec/dummy/app/assets/config/manifest.js +3 -0
  170. data/spec/dummy/config/database.yml +3 -3
  171. data/spec/dummy/config/initializers/devise.rb +1 -1
  172. data/spec/dummy/db/migrate/20140530185250_devise_create_users.rb +1 -1
  173. data/spec/dummy/db/migrate/20150127172846_create_widgets.rb +1 -1
  174. data/spec/dummy/db/migrate/20150206203824_add_video_url_to_storytime_posts.rb +1 -1
  175. data/spec/dummy/db/schema.rb +226 -244
  176. data/spec/factories/action_factories.rb +3 -3
  177. data/spec/factories/comment_factories.rb +1 -1
  178. data/spec/factories/media_factories.rb +1 -1
  179. data/spec/factories/membership_factories.rb +1 -1
  180. data/spec/factories/navigation_factories.rb +3 -3
  181. data/spec/factories/permission_factories.rb +1 -1
  182. data/spec/factories/post_factories.rb +2 -2
  183. data/spec/factories/role_factories.rb +11 -11
  184. data/spec/factories/site_factories.rb +3 -3
  185. data/spec/factories/snippet_factories.rb +1 -1
  186. data/spec/factories/subscription_factories.rb +1 -1
  187. data/spec/factories/user_factories.rb +2 -2
  188. data/spec/factories/widget_factories.rb +2 -2
  189. data/spec/features/blogs_spec.rb +7 -7
  190. data/spec/features/comments_spec.rb +11 -11
  191. data/spec/features/dashboard/media_spec.rb +17 -11
  192. data/spec/features/dashboard/memberships_spec.rb +13 -19
  193. data/spec/features/dashboard/navigations_spec.rb +1 -1
  194. data/spec/features/dashboard/pages_spec.rb +8 -8
  195. data/spec/features/dashboard/posts_spec.rb +19 -19
  196. data/spec/features/dashboard/sites_spec.rb +1 -1
  197. data/spec/features/dashboard/snippets_spec.rb +3 -3
  198. data/spec/features/dashboard/subscription_spec.rb +2 -2
  199. data/spec/features/pages_spec.rb +3 -3
  200. data/spec/features/posts_spec.rb +2 -2
  201. data/spec/features/subscription_spec.rb +3 -3
  202. data/spec/importers/wordpress_spec.rb +1 -1
  203. data/spec/lib/mysql_fulltext_search_adapter_spec.rb +3 -3
  204. data/spec/lib/mysql_search_adapter_spec.rb +3 -3
  205. data/spec/lib/postgres_search_adapter_spec.rb +3 -3
  206. data/spec/lib/sqlite3_search_adapter_spec.rb +3 -3
  207. data/spec/lib/storytime/constraints/page_constraint_spec.rb +40 -0
  208. data/spec/lib/storytime_helpers_spec.rb +2 -2
  209. data/spec/models/navigation_spec.rb +3 -3
  210. data/spec/models/post_spec.rb +29 -29
  211. data/spec/models/snippet_spec.rb +31 -0
  212. data/spec/models/subscription_spec.rb +4 -4
  213. data/spec/models/tagging_spec.rb +14 -14
  214. data/spec/models/version_spec.rb +29 -29
  215. data/spec/policies/comment_policy_spec.rb +11 -11
  216. data/spec/policies/post_policy_spec.rb +13 -13
  217. data/spec/requests/pages_spec.rb +37 -0
  218. data/spec/requests/routings_spec.rb +14 -15
  219. data/spec/spec_helper.rb +8 -15
  220. data/spec/support/domains.rb +2 -2
  221. data/spec/support/feature_macros.rb +5 -5
  222. data/spec/support/pundit_matcher.rb +3 -3
  223. data/storytime.gemspec +15 -20
  224. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +195 -0
  225. data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +169 -0
  226. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +182 -0
  227. data/vendor/assets/javascripts/codemirror.js +8922 -0
  228. data/vendor/assets/javascripts/medium-editor.min.js +3 -3
  229. data/vendor/assets/stylesheets/codemirror/themes/solarized.css +169 -0
  230. data/vendor/assets/stylesheets/codemirror.css +347 -0
  231. metadata +94 -134
  232. data/config/initializers/storytime_admin.rb +0 -5
  233. data/config/spring.rb +0 -1
  234. data/spec/dummy/app/controllers/storytime_admin/widgets_controller.rb +0 -5
  235. data/spec/dummy/db/development.sqlite3 +0 -0
  236. data/spec/dummy/db/test.sqlite3 +0 -0
@@ -2,8 +2,8 @@ require "spec_helper"
2
2
 
3
3
  describe "Root path", type: :request do
4
4
  it "routes to blog_homepage#show when site homepage is a blog" do
5
- site = FactoryGirl.create(:site)
6
- user = FactoryGirl.create(:admin)
5
+ site = FactoryBot.create(:site)
6
+ user = FactoryBot.create(:admin)
7
7
  site.save_with_seeds(user)
8
8
  site.homepage = site.blogs.first
9
9
 
@@ -14,12 +14,11 @@ describe "Root path", type: :request do
14
14
  end
15
15
 
16
16
  it "routes to pages#show when site homepage is page" do
17
- site = FactoryGirl.create(:site)
18
- user = FactoryGirl.create(:admin)
19
- home_page = FactoryGirl.create(:page, site: site)
17
+ site = FactoryBot.create(:site)
18
+ user = FactoryBot.create(:admin)
19
+ home_page = FactoryBot.create(:page, site: site)
20
20
  site.save_with_seeds(user)
21
- site.homepage = home_page
22
- site.save
21
+ site.update_attribute :root_post_id, home_page.id
23
22
 
24
23
  get "/"
25
24
 
@@ -31,8 +30,8 @@ end
31
30
 
32
31
  describe "Post path", type: :request do
33
32
  it "uses /posts/post-slug when site#post_slug_style is default" do
34
- site = FactoryGirl.create(:site, post_slug_style: :default, custom_domain: "www.example.com")
35
- post = FactoryGirl.create(:post, site: site)
33
+ site = FactoryBot.create(:site, post_slug_style: :default, custom_domain: "www.example.com")
34
+ post = FactoryBot.create(:post, site: site)
36
35
  expect(storytime.post_path(post)).to eq("/posts/#{post.slug}")
37
36
 
38
37
  get url_for([post, only_path: true])
@@ -43,8 +42,8 @@ describe "Post path", type: :request do
43
42
  end
44
43
 
45
44
  it "uses /year/month/day/post-slug when site#post_slug_style is day_and_name" do
46
- site = FactoryGirl.create(:site, post_slug_style: :day_and_name, custom_domain: "www.example.com")
47
- post = FactoryGirl.create(:post, site: site)
45
+ site = FactoryBot.create(:site, post_slug_style: :day_and_name, custom_domain: "www.example.com")
46
+ post = FactoryBot.create(:post, site: site)
48
47
  date = post.created_at.to_date
49
48
 
50
49
  expect(url_for([post, only_path: true])).to eq("/#{date.year}/#{date.strftime('%m')}/#{date.strftime('%d')}/#{post.slug}")
@@ -57,8 +56,8 @@ describe "Post path", type: :request do
57
56
  end
58
57
 
59
58
  it "uses /year/month/post-slug when site#post_slug_style is month_and_name" do
60
- site = FactoryGirl.create(:site, post_slug_style: :month_and_name, custom_domain: "www.example.com")
61
- post = FactoryGirl.create(:post, site: site)
59
+ site = FactoryBot.create(:site, post_slug_style: :month_and_name, custom_domain: "www.example.com")
60
+ post = FactoryBot.create(:post, site: site)
62
61
  date = post.created_at.to_date
63
62
  expect(url_for([post, only_path: true])).to eq("/#{date.year}/#{date.strftime('%m')}/#{post.slug}")
64
63
 
@@ -70,8 +69,8 @@ describe "Post path", type: :request do
70
69
  end
71
70
 
72
71
  it "uses /post-id when site#post_slug_style is post_id" do
73
- site = FactoryGirl.create(:site, post_slug_style: :post_id, custom_domain: "www.example.com")
74
- post = FactoryGirl.create(:post, site: site)
72
+ site = FactoryBot.create(:site, post_slug_style: :post_id, custom_domain: "www.example.com")
73
+ post = FactoryBot.create(:post, site: site)
75
74
  expect(url_for([post, only_path: true])).to eq("/posts/#{post.id}")
76
75
 
77
76
  get url_for([post, only_path: true])
data/spec/spec_helper.rb CHANGED
@@ -2,32 +2,25 @@
2
2
  ENV["RAILS_ENV"] ||= 'test'
3
3
  require File.expand_path("../dummy/config/environment", __FILE__)
4
4
  require 'rspec/rails'
5
- require 'rspec/autorun'
6
- require 'factory_girl_rails'
5
+ require 'factory_bot_rails'
7
6
  require 'capybara/rails'
8
7
  require 'capybara/rspec'
9
- require 'capybara/poltergeist'
8
+ require 'capybara/cuprite'
10
9
  require "pundit/rspec"
11
10
 
12
11
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
13
12
 
14
13
  # Checks for pending migrations before tests are run.
15
14
  # If you are not using ActiveRecord, you can remove this line.
15
+ # require "pry-byebug"
16
+ # binding.pry
16
17
  ActiveRecord::Migration.maintain_test_schema!
17
18
 
18
- poltergeist_options = {
19
- phantomjs_logger: Logger.new('/dev/null'),
20
- # inspector: true,
21
- # debug: true,
22
- phantomjs_options: ['--load-images=no', '--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1'],
23
- js_errors: false
24
- }
25
-
26
- Capybara.register_driver :poltergeist_st do |app|
27
- Capybara::Poltergeist::Driver.new(app, poltergeist_options)
19
+ Capybara.register_driver :cuprite do |app|
20
+ Capybara::Cuprite::Driver.new(app, js_errors: false, headless: true)
28
21
  end
29
22
 
30
- Capybara.javascript_driver = :poltergeist_st
23
+ Capybara.javascript_driver = :cuprite
31
24
 
32
25
  RSpec.configure do |config|
33
26
 
@@ -79,7 +72,7 @@ RSpec.configure do |config|
79
72
 
80
73
  config.include FeatureMacros, type: :feature
81
74
  config.include Storytime::Engine.routes.url_helpers
82
- config.include Devise::TestHelpers, type: :controller
75
+ config.include Devise::Test::ControllerHelpers, type: :controller
83
76
 
84
77
  config.filter_run focus: true
85
78
  config.run_all_when_everything_filtered = true
@@ -2,13 +2,13 @@ RSpec.configure do |config|
2
2
  Capybara.always_include_port = true
3
3
 
4
4
  config.before(type: :feature) do
5
- @current_site ||= FactoryGirl.build(:site)
5
+ @current_site ||= FactoryBot.build(:site)
6
6
  set_domain @current_site.custom_domain
7
7
  end
8
8
 
9
9
  config.before(type: :controller) do
10
10
  @request.env["devise.mapping"] = Devise.mappings[:user]
11
- @current_site ||= FactoryGirl.create(:site)
11
+ @current_site ||= FactoryBot.create(:site)
12
12
  @request.host = @current_site.custom_domain
13
13
  end
14
14
  end
@@ -1,6 +1,6 @@
1
1
  module FeatureMacros
2
2
  def login(user = nil, skip_site = false)
3
- user ||= FactoryGirl.create(:user)
3
+ user ||= FactoryBot.create(:user)
4
4
  unless skip_site
5
5
  setup_site(user)
6
6
  set_domain(@current_site.custom_domain)
@@ -18,15 +18,15 @@ module FeatureMacros
18
18
  end
19
19
 
20
20
  def login_admin(admin = nil)
21
- login FactoryGirl.create(:admin)
21
+ login FactoryBot.create(:admin)
22
22
  end
23
23
 
24
24
  def login_editor(editor = nil)
25
- login FactoryGirl.create(:editor)
25
+ login FactoryBot.create(:editor)
26
26
  end
27
27
 
28
28
  def login_writer(writer = nil)
29
- login FactoryGirl.create(:writer)
29
+ login FactoryBot.create(:writer)
30
30
  end
31
31
 
32
32
  def current_user
@@ -38,7 +38,7 @@ module FeatureMacros
38
38
  end
39
39
 
40
40
  def setup_site(user)
41
- @current_site ||= FactoryGirl.create(:site)
41
+ @current_site ||= FactoryBot.create(:site)
42
42
  @current_site.save_with_seeds(user)
43
43
  @current_site.homepage = @current_site.blogs.first
44
44
  @current_site.save
@@ -3,11 +3,11 @@ RSpec::Matchers.define :permit! do |action|
3
3
  policy.public_send("#{action}?")
4
4
  end
5
5
 
6
- failure_message_for_should do |policy|
6
+ failure_message do |policy|
7
7
  "#{policy.class} does not permit #{action} on #{policy.record} for #{policy.user.inspect}."
8
8
  end
9
9
 
10
- failure_message_for_should_not do |policy|
10
+ failure_message_when_negated do |policy|
11
11
  "#{policy.class} does not forbid #{action} on #{policy.record} for #{policy.user.inspect}."
12
12
  end
13
- end
13
+ end
data/storytime.gemspec CHANGED
@@ -18,44 +18,39 @@ Gem::Specification.new do |s|
18
18
  s.test_files = Dir["spec/**/*"] - Dir["spec/dummy/tmp/**/*"] - Dir["spec/dummy/log/*"] - Dir["spec/dummy/public/uploads/**/*"]
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_dependency "rails", ">= 4.0", '< 5.1'
22
- s.add_dependency "pundit", ">= 0.2"
23
- s.add_dependency "kaminari", ">= 0.15"
24
- s.add_dependency "jbuilder", ">= 1.5"
21
+ s.add_dependency "rails", ">= 7.0"
22
+ s.add_dependency "pundit", ">= 2.0.0"
23
+ s.add_dependency "kaminari", ">= 1.0.0"
24
+ s.add_dependency "jbuilder", ">= 2.0.0"
25
25
  s.add_dependency "sass-rails", ">= 4.0"
26
26
  s.add_dependency "bootstrap-sass", ">= 3.1"
27
27
  s.add_dependency "coffee-rails", ">= 4.0"
28
28
  s.add_dependency "jquery-rails", ">= 3.0"
29
29
  s.add_dependency "simple_form", ">= 3.0"
30
30
  s.add_dependency "friendly_id", ">= 5.0"
31
- s.add_dependency "fog", ">= 1.18"
32
- s.add_dependency "carrierwave", ">= 1.0"
31
+ s.add_dependency "fog-aws", ">= 3.0"
32
+ s.add_dependency "carrierwave", ">= 3.0"
33
33
  s.add_dependency "mini_magick", ">= 3.7"
34
34
  s.add_dependency "nokogiri", ">= 1.6"
35
- s.add_dependency "font-awesome-sass", ">= 4.0.3"
36
- s.add_dependency "jquery-ui-rails", "~> 5.0"
37
- s.add_dependency "thor", "~> 0.19.1"
38
- s.add_dependency "leather", ">= 3.5"
39
- s.add_dependency "codemirror-rails", ">=5.0"
40
- s.add_dependency "storytime-admin", "~> 0.2"
35
+ s.add_dependency "font-awesome-sass", "<= 4.7.0"
36
+ s.add_dependency "jquery-ui-rails", ">= 6.0"
37
+ s.add_dependency "thor", ">= 0.19.1"
41
38
  s.add_dependency "devise", ">= 3.2"
42
39
  s.add_dependency "cocoon"
43
40
  s.add_dependency "acts_as_list"
41
+ s.add_dependency "sprockets", ">= 3.7", "< 4.0"
44
42
 
45
43
  s.add_development_dependency "pg"
46
44
  s.add_development_dependency "rspec-rails"
47
45
  s.add_development_dependency "capybara"
48
- s.add_development_dependency "poltergeist", "~>1.5"
49
- s.add_development_dependency "factory_girl_rails"
50
- s.add_development_dependency "guard-rspec", "~> 4.2.8"
51
- s.add_development_dependency "spring-commands-rspec"
52
- s.add_development_dependency "spring", "1.1.3"
46
+ s.add_development_dependency "cuprite"
47
+ s.add_development_dependency "factory_bot_rails"
48
+ s.add_development_dependency "guard-rspec"
53
49
  s.add_development_dependency "rb-fsevent"
54
- s.add_development_dependency "pry-nav"
55
- s.add_development_dependency "pry-stack_explorer"
50
+ s.add_development_dependency "debug"
56
51
  s.add_development_dependency "database_cleaner"
57
52
  s.add_development_dependency "better_errors"
58
53
  s.add_development_dependency "binding_of_caller"
59
54
  s.add_development_dependency "launchy"
60
- s.add_development_dependency "thin"
55
+ s.add_development_dependency "puma"
61
56
  end
@@ -0,0 +1,195 @@
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ var defaults = {
13
+ pairs: "()[]{}''\"\"",
14
+ triples: "",
15
+ explode: "[]{}"
16
+ };
17
+
18
+ var Pos = CodeMirror.Pos;
19
+
20
+ CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
21
+ if (old && old != CodeMirror.Init) {
22
+ cm.removeKeyMap(keyMap);
23
+ cm.state.closeBrackets = null;
24
+ }
25
+ if (val) {
26
+ cm.state.closeBrackets = val;
27
+ cm.addKeyMap(keyMap);
28
+ }
29
+ });
30
+
31
+ function getOption(conf, name) {
32
+ if (name == "pairs" && typeof conf == "string") return conf;
33
+ if (typeof conf == "object" && conf[name] != null) return conf[name];
34
+ return defaults[name];
35
+ }
36
+
37
+ var bind = defaults.pairs + "`";
38
+ var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
39
+ for (var i = 0; i < bind.length; i++)
40
+ keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
41
+
42
+ function handler(ch) {
43
+ return function(cm) { return handleChar(cm, ch); };
44
+ }
45
+
46
+ function getConfig(cm) {
47
+ var deflt = cm.state.closeBrackets;
48
+ if (!deflt) return null;
49
+ var mode = cm.getModeAt(cm.getCursor());
50
+ return mode.closeBrackets || deflt;
51
+ }
52
+
53
+ function handleBackspace(cm) {
54
+ var conf = getConfig(cm);
55
+ if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
56
+
57
+ var pairs = getOption(conf, "pairs");
58
+ var ranges = cm.listSelections();
59
+ for (var i = 0; i < ranges.length; i++) {
60
+ if (!ranges[i].empty()) return CodeMirror.Pass;
61
+ var around = charsAround(cm, ranges[i].head);
62
+ if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
63
+ }
64
+ for (var i = ranges.length - 1; i >= 0; i--) {
65
+ var cur = ranges[i].head;
66
+ cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
67
+ }
68
+ }
69
+
70
+ function handleEnter(cm) {
71
+ var conf = getConfig(cm);
72
+ var explode = conf && getOption(conf, "explode");
73
+ if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
74
+
75
+ var ranges = cm.listSelections();
76
+ for (var i = 0; i < ranges.length; i++) {
77
+ if (!ranges[i].empty()) return CodeMirror.Pass;
78
+ var around = charsAround(cm, ranges[i].head);
79
+ if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
80
+ }
81
+ cm.operation(function() {
82
+ cm.replaceSelection("\n\n", null);
83
+ cm.execCommand("goCharLeft");
84
+ ranges = cm.listSelections();
85
+ for (var i = 0; i < ranges.length; i++) {
86
+ var line = ranges[i].head.line;
87
+ cm.indentLine(line, null, true);
88
+ cm.indentLine(line + 1, null, true);
89
+ }
90
+ });
91
+ }
92
+
93
+ function contractSelection(sel) {
94
+ var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
95
+ return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
96
+ head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
97
+ }
98
+
99
+ function handleChar(cm, ch) {
100
+ var conf = getConfig(cm);
101
+ if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
102
+
103
+ var pairs = getOption(conf, "pairs");
104
+ var pos = pairs.indexOf(ch);
105
+ if (pos == -1) return CodeMirror.Pass;
106
+ var triples = getOption(conf, "triples");
107
+
108
+ var identical = pairs.charAt(pos + 1) == ch;
109
+ var ranges = cm.listSelections();
110
+ var opening = pos % 2 == 0;
111
+
112
+ var type;
113
+ for (var i = 0; i < ranges.length; i++) {
114
+ var range = ranges[i], cur = range.head, curType;
115
+ var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
116
+ if (opening && !range.empty()) {
117
+ curType = "surround";
118
+ } else if ((identical || !opening) && next == ch) {
119
+ if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
120
+ curType = "skipThree";
121
+ else
122
+ curType = "skip";
123
+ } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
124
+ cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
125
+ (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
126
+ curType = "addFour";
127
+ } else if (identical) {
128
+ if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
129
+ else return CodeMirror.Pass;
130
+ } else if (opening && (cm.getLine(cur.line).length == cur.ch ||
131
+ isClosingBracket(next, pairs) ||
132
+ /\s/.test(next))) {
133
+ curType = "both";
134
+ } else {
135
+ return CodeMirror.Pass;
136
+ }
137
+ if (!type) type = curType;
138
+ else if (type != curType) return CodeMirror.Pass;
139
+ }
140
+
141
+ var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
142
+ var right = pos % 2 ? ch : pairs.charAt(pos + 1);
143
+ cm.operation(function() {
144
+ if (type == "skip") {
145
+ cm.execCommand("goCharRight");
146
+ } else if (type == "skipThree") {
147
+ for (var i = 0; i < 3; i++)
148
+ cm.execCommand("goCharRight");
149
+ } else if (type == "surround") {
150
+ var sels = cm.getSelections();
151
+ for (var i = 0; i < sels.length; i++)
152
+ sels[i] = left + sels[i] + right;
153
+ cm.replaceSelections(sels, "around");
154
+ sels = cm.listSelections().slice();
155
+ for (var i = 0; i < sels.length; i++)
156
+ sels[i] = contractSelection(sels[i]);
157
+ cm.setSelections(sels);
158
+ } else if (type == "both") {
159
+ cm.replaceSelection(left + right, null);
160
+ cm.triggerElectric(left + right);
161
+ cm.execCommand("goCharLeft");
162
+ } else if (type == "addFour") {
163
+ cm.replaceSelection(left + left + left + left, "before");
164
+ cm.execCommand("goCharRight");
165
+ }
166
+ });
167
+ }
168
+
169
+ function isClosingBracket(ch, pairs) {
170
+ var pos = pairs.lastIndexOf(ch);
171
+ return pos > -1 && pos % 2 == 1;
172
+ }
173
+
174
+ function charsAround(cm, pos) {
175
+ var str = cm.getRange(Pos(pos.line, pos.ch - 1),
176
+ Pos(pos.line, pos.ch + 1));
177
+ return str.length == 2 ? str : null;
178
+ }
179
+
180
+ // Project the token type that will exists after the given char is
181
+ // typed, and use it to determine whether it would cause the start
182
+ // of a string token.
183
+ function enteringString(cm, pos, ch) {
184
+ var line = cm.getLine(pos.line);
185
+ var token = cm.getTokenAt(pos);
186
+ if (/\bstring2?\b/.test(token.type)) return false;
187
+ var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
188
+ stream.pos = stream.start = token.start;
189
+ for (;;) {
190
+ var type1 = cm.getMode().token(stream, token.state);
191
+ if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
192
+ stream.start = stream.pos;
193
+ }
194
+ }
195
+ });
@@ -0,0 +1,169 @@
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ /**
5
+ * Tag-closer extension for CodeMirror.
6
+ *
7
+ * This extension adds an "autoCloseTags" option that can be set to
8
+ * either true to get the default behavior, or an object to further
9
+ * configure its behavior.
10
+ *
11
+ * These are supported options:
12
+ *
13
+ * `whenClosing` (default true)
14
+ * Whether to autoclose when the '/' of a closing tag is typed.
15
+ * `whenOpening` (default true)
16
+ * Whether to autoclose the tag when the final '>' of an opening
17
+ * tag is typed.
18
+ * `dontCloseTags` (default is empty tags for HTML, none for XML)
19
+ * An array of tag names that should not be autoclosed.
20
+ * `indentTags` (default is block tags for HTML, none for XML)
21
+ * An array of tag names that should, when opened, cause a
22
+ * blank line to be added inside the tag, and the blank line and
23
+ * closing line to be indented.
24
+ *
25
+ * See demos/closetag.html for a usage example.
26
+ */
27
+
28
+ (function(mod) {
29
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
30
+ mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
31
+ else if (typeof define == "function" && define.amd) // AMD
32
+ define(["../../lib/codemirror", "../fold/xml-fold"], mod);
33
+ else // Plain browser env
34
+ mod(CodeMirror);
35
+ })(function(CodeMirror) {
36
+ CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
37
+ if (old != CodeMirror.Init && old)
38
+ cm.removeKeyMap("autoCloseTags");
39
+ if (!val) return;
40
+ var map = {name: "autoCloseTags"};
41
+ if (typeof val != "object" || val.whenClosing)
42
+ map["'/'"] = function(cm) { return autoCloseSlash(cm); };
43
+ if (typeof val != "object" || val.whenOpening)
44
+ map["'>'"] = function(cm) { return autoCloseGT(cm); };
45
+ cm.addKeyMap(map);
46
+ });
47
+
48
+ var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
49
+ "source", "track", "wbr"];
50
+ var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
51
+ "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
52
+
53
+ function autoCloseGT(cm) {
54
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
55
+ var ranges = cm.listSelections(), replacements = [];
56
+ for (var i = 0; i < ranges.length; i++) {
57
+ if (!ranges[i].empty()) return CodeMirror.Pass;
58
+ var pos = ranges[i].head, tok = cm.getTokenAt(pos);
59
+ var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
60
+ if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
61
+
62
+ var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
63
+ var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
64
+ var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
65
+
66
+ var tagName = state.tagName;
67
+ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
68
+ var lowerTagName = tagName.toLowerCase();
69
+ // Don't process the '>' at the end of an end-tag or self-closing tag
70
+ if (!tagName ||
71
+ tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
72
+ tok.type == "tag" && state.type == "closeTag" ||
73
+ tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
74
+ dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
75
+ closingTagExists(cm, tagName, pos, state, true))
76
+ return CodeMirror.Pass;
77
+
78
+ var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
79
+ replacements[i] = {indent: indent,
80
+ text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
81
+ newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
82
+ }
83
+
84
+ for (var i = ranges.length - 1; i >= 0; i--) {
85
+ var info = replacements[i];
86
+ cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
87
+ var sel = cm.listSelections().slice(0);
88
+ sel[i] = {head: info.newPos, anchor: info.newPos};
89
+ cm.setSelections(sel);
90
+ if (info.indent) {
91
+ cm.indentLine(info.newPos.line, null, true);
92
+ cm.indentLine(info.newPos.line + 1, null, true);
93
+ }
94
+ }
95
+ }
96
+
97
+ function autoCloseCurrent(cm, typingSlash) {
98
+ var ranges = cm.listSelections(), replacements = [];
99
+ var head = typingSlash ? "/" : "</";
100
+ for (var i = 0; i < ranges.length; i++) {
101
+ if (!ranges[i].empty()) return CodeMirror.Pass;
102
+ var pos = ranges[i].head, tok = cm.getTokenAt(pos);
103
+ var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
104
+ if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
105
+ tok.start != pos.ch - 1))
106
+ return CodeMirror.Pass;
107
+ // Kludge to get around the fact that we are not in XML mode
108
+ // when completing in JS/CSS snippet in htmlmixed mode. Does not
109
+ // work for other XML embedded languages (there is no general
110
+ // way to go from a mixed mode to its current XML state).
111
+ var replacement;
112
+ if (inner.mode.name != "xml") {
113
+ if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
114
+ replacement = head + "script";
115
+ else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
116
+ replacement = head + "style";
117
+ else
118
+ return CodeMirror.Pass;
119
+ } else {
120
+ if (!state.context || !state.context.tagName ||
121
+ closingTagExists(cm, state.context.tagName, pos, state))
122
+ return CodeMirror.Pass;
123
+ replacement = head + state.context.tagName;
124
+ }
125
+ if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
126
+ replacements[i] = replacement;
127
+ }
128
+ cm.replaceSelections(replacements);
129
+ ranges = cm.listSelections();
130
+ for (var i = 0; i < ranges.length; i++)
131
+ if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
132
+ cm.indentLine(ranges[i].head.line);
133
+ }
134
+
135
+ function autoCloseSlash(cm) {
136
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
137
+ return autoCloseCurrent(cm, true);
138
+ }
139
+
140
+ CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
141
+
142
+ function indexOf(collection, elt) {
143
+ if (collection.indexOf) return collection.indexOf(elt);
144
+ for (var i = 0, e = collection.length; i < e; ++i)
145
+ if (collection[i] == elt) return i;
146
+ return -1;
147
+ }
148
+
149
+ // If xml-fold is loaded, we use its functionality to try and verify
150
+ // whether a given tag is actually unclosed.
151
+ function closingTagExists(cm, tagName, pos, state, newTag) {
152
+ if (!CodeMirror.scanForClosingTag) return false;
153
+ var end = Math.min(cm.lastLine() + 1, pos.line + 500);
154
+ var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
155
+ if (!nextClose || nextClose.tag != tagName) return false;
156
+ var cx = state.context;
157
+ // If the immediate wrapping context contains onCx instances of
158
+ // the same tag, a closing tag only exists if there are at least
159
+ // that many closing tags of that type following.
160
+ for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
161
+ pos = nextClose.to;
162
+ for (var i = 1; i < onCx; i++) {
163
+ var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
164
+ if (!next || next.tag != tagName) return false;
165
+ pos = next.to;
166
+ }
167
+ return true;
168
+ }
169
+ });