thredded 0.16.15 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -23
  3. data/app/assets/javascripts/thredded/components/preview_area.es6 +3 -1
  4. data/app/commands/thredded/create_messageboard.rb +2 -2
  5. data/app/controllers/concerns/thredded/render_preview.rb +6 -0
  6. data/app/controllers/thredded/application_controller.rb +5 -10
  7. data/app/controllers/thredded/topics_controller.rb +0 -6
  8. data/app/forms/thredded/private_topic_form.rb +1 -1
  9. data/app/helpers/thredded/application_helper.rb +3 -3
  10. data/app/helpers/thredded/urls_helper.rb +1 -1
  11. data/app/mailer_previews/thredded/base_mailer_preview.rb +5 -5
  12. data/app/models/concerns/thredded/friendly_id_reserved_words_and_pagination.rb +1 -1
  13. data/app/models/concerns/thredded/notifier_preference.rb +1 -1
  14. data/app/models/concerns/thredded/post_common.rb +8 -7
  15. data/app/models/concerns/thredded/topic_common.rb +1 -1
  16. data/app/models/concerns/thredded/user_topic_read_state_common.rb +5 -5
  17. data/app/models/thredded/messageboard.rb +3 -4
  18. data/app/models/thredded/notifications_for_followed_topics.rb +1 -1
  19. data/app/models/thredded/post.rb +3 -2
  20. data/app/models/thredded/post_moderation_record.rb +12 -13
  21. data/app/models/thredded/private_post.rb +2 -2
  22. data/app/models/thredded/private_topic.rb +4 -2
  23. data/app/models/thredded/topic.rb +2 -2
  24. data/app/models/thredded/user_detail.rb +1 -1
  25. data/app/models/thredded/user_extender.rb +1 -1
  26. data/app/view_models/thredded/post_view.rb +1 -0
  27. data/app/view_models/thredded/posts_page_view.rb +10 -9
  28. data/app/view_models/thredded/private_topics_page_view.rb +10 -6
  29. data/app/view_models/thredded/topic_posts_page_view.rb +16 -3
  30. data/app/view_models/thredded/topics_page_view.rb +9 -6
  31. data/app/views/layouts/thredded/application.html.erb +2 -2
  32. data/app/views/thredded/messageboards/_form.html.erb +3 -3
  33. data/app/views/thredded/moderation/_post_moderation_record.html.erb +3 -3
  34. data/app/views/thredded/posts_common/_content.html.erb +1 -1
  35. data/app/views/thredded/posts_common/actions/_quote.html.erb +1 -1
  36. data/app/views/thredded/shared/_page.html.erb +1 -1
  37. data/app/views/thredded/shared/nav/_standalone.html.erb +2 -2
  38. data/bin/create_migration_fixture +23 -0
  39. data/bin/rubocop +11 -0
  40. data/config/i18n-tasks.yml +6 -1
  41. data/config/locales/de.yml +2 -0
  42. data/config/locales/en.yml +3 -1
  43. data/config/locales/es.yml +2 -0
  44. data/config/locales/fr.yml +2 -0
  45. data/config/locales/it.yml +4 -2
  46. data/config/locales/pl.yml +2 -0
  47. data/config/locales/pt-BR.yml +2 -0
  48. data/config/locales/ru.yml +2 -0
  49. data/config/locales/zh-CN.yml +2 -0
  50. data/db/upgrade_migrations/20161019150201_upgrade_v0_7_to_v0_8.rb +5 -5
  51. data/db/upgrade_migrations/20180110200009_upgrade_thredded_v0_14_to_v0_15.rb +1 -1
  52. data/lib/generators/thredded/install/templates/initializer.rb +3 -3
  53. data/lib/thredded/arel_compat.rb +1 -42
  54. data/lib/thredded/base_migration.rb +2 -2
  55. data/lib/thredded/collection_to_strings_with_cache_renderer.rb +91 -28
  56. data/lib/thredded/compat.rb +35 -0
  57. data/lib/thredded/content_formatter.rb +30 -8
  58. data/lib/thredded/database_seeder.rb +11 -4
  59. data/lib/thredded/db_tools.rb +3 -5
  60. data/lib/thredded/email_transformer.rb +2 -2
  61. data/lib/thredded/engine.rb +1 -1
  62. data/lib/thredded/formatting_demo_content.rb +21 -21
  63. data/lib/thredded/html_pipeline/at_mention_filter.rb +1 -1
  64. data/lib/thredded/html_pipeline/onebox_filter.rb +3 -3
  65. data/lib/thredded/html_pipeline/utils.rb +1 -1
  66. data/lib/thredded/version.rb +1 -1
  67. data/lib/thredded.rb +3 -23
  68. metadata +56 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac00c63103252bbf9bff35aa057a6630605ad897368010665476b8b4d2abfc3a
4
- data.tar.gz: cf7c0937115c8967c8fed0ba5789e4445db0a9e8b098a3109563b63be3883059
3
+ metadata.gz: c38b0b431b19a2a3bcb74955be64a67835d60870754e65436e8498ca67729bc8
4
+ data.tar.gz: 1b9827d5ed79af58f52c86e5badb430e1b44dfaff0381fde2390ad08ce436b26
5
5
  SHA512:
6
- metadata.gz: cd1d9295ea54d35b3f6f1ac48f741b2766645c118b4519b717d5c4f87d926be12492ff2f4b76449088dfe2357b10e518b28442c76ac2998c19614ea2d3631603
7
- data.tar.gz: 6d8892713aba82af3017146f0c4f5f8238af39842f4536640689915fa3833b68dc63023502c23e1311a63b6dd45aec0c02c14e4be3367fa6b67e3a471df70caf
6
+ metadata.gz: 43a2362878a9949d88097d77efe90c7997483e1c70f0fb505ffff1fa06e2097036d6ae6aff829120a406bac06b9e1cbb0879c1b614cf0c8205f837044a6fb105
7
+ data.tar.gz: 6f59d7de62c088da6ef53bb474ab02bdc666313ff5e050f86c3a1414a7371d93d60874008dc2ce68b8df8a7601754fe9771fef1804e11e1a4060620968465917
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Thredded [![Code Climate](https://codeclimate.com/github/thredded/thredded/badges/gpa.svg)](https://codeclimate.com/github/thredded/thredded) [![Travis-CI](https://api.travis-ci.org/thredded/thredded.svg?branch=master)](https://travis-ci.org/thredded/thredded/) [![Test Coverage](https://codeclimate.com/github/thredded/thredded/badges/coverage.svg)](https://codeclimate.com/github/thredded/thredded/coverage) [![Inline docs](http://inch-ci.org/github/thredded/thredded.svg?branch=master)](http://inch-ci.org/github/thredded/thredded) [![Gitter](https://badges.gitter.im/thredded/thredded.svg)](https://gitter.im/thredded/thredded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
1
+ # Thredded [![Code Climate](https://codeclimate.com/github/thredded/thredded/badges/gpa.svg)](https://codeclimate.com/github/thredded/thredded) [![Travis-CI](https://api.travis-ci.org/thredded/thredded.svg?branch=main)](https://travis-ci.org/thredded/thredded/) [![Test Coverage](https://codeclimate.com/github/thredded/thredded/badges/coverage.svg)](https://codeclimate.com/github/thredded/thredded/coverage) [![Inline docs](http://inch-ci.org/github/thredded/thredded.svg?branch=main)](http://inch-ci.org/github/thredded/thredded) [![Gitter](https://badges.gitter.im/thredded/thredded.svg)](https://gitter.im/thredded/thredded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
2
2
 
3
- _Thredded_ is a Rails 4.2+ forum/messageboard engine. Its goal is to be as simple and feature rich as possible.
3
+ _Thredded_ is a Rails 5.2+ forum/messageboard engine. Its goal is to be as simple and feature rich as possible.
4
4
 
5
5
  Some of the features currently in Thredded:
6
6
 
@@ -96,7 +96,7 @@ Then, see the rest of this Readme for more information about using and customizi
96
96
  Add the gem to your Gemfile:
97
97
 
98
98
  ```ruby
99
- gem 'thredded', '~> 0.16.15'
99
+ gem 'thredded', '~> 1.0'
100
100
  ```
101
101
 
102
102
  Add the Thredded [initializer] to your parent app by running the install generator.
@@ -174,7 +174,7 @@ mkdir -p app/views/thredded/shared/nav && cp "$(bundle show thredded)/$_/_standa
174
174
 
175
175
  ### Application layout
176
176
 
177
- You can also use Thredded with your application (or other) layout by by setting `Thredded.layout` in the initializer.
177
+ You can also use Thredded with your application (or other) layout by setting `Thredded.layout` in the initializer.
178
178
 
179
179
  In this case, you will need to reference your paths/routes carefully and pull in thredded assets (styles and javascript):
180
180
 
@@ -352,7 +352,7 @@ with a "themed" version of thredded.
352
352
  #### Styles
353
353
 
354
354
  Thredded comes with a light Sass theme controlled by a handful of variables that can be found here:
355
- https://github.com/thredded/thredded/blob/master/app/assets/stylesheets/thredded/base/_variables.scss.
355
+ https://github.com/thredded/thredded/blob/main/app/assets/stylesheets/thredded/base/_variables.scss.
356
356
 
357
357
  To override the styles, override the variables *before* importing Thredded styles, e.g.:
358
358
 
@@ -366,8 +366,8 @@ If you are writing a Thredded plugin, import the [`thredded/base`][thredded-scss
366
366
  The `base` package only defines variables, mixins, and %-placeholders, so it can be imported safely without producing
367
367
  any duplicate CSS.
368
368
 
369
- [thredded-scss-dependencies]: https://github.com/thredded/thredded/blob/master/app/assets/stylesheets/thredded/_dependencies.scss
370
- [thredded-scss-base]: https://github.com/thredded/thredded/blob/master/app/assets/stylesheets/thredded/_base.scss
369
+ [thredded-scss-dependencies]: https://github.com/thredded/thredded/blob/main/app/assets/stylesheets/thredded/_dependencies.scss
370
+ [thredded-scss-base]: https://github.com/thredded/thredded/blob/main/app/assets/stylesheets/thredded/_base.scss
371
371
 
372
372
  ### Email and other notifications
373
373
 
@@ -513,35 +513,35 @@ Below is an overview of the default permissions, with links to the implementatio
513
513
  <tbody>
514
514
  <tr>
515
515
  <th align="center">Logged in</th>
516
- <td align="center" rowspan="2"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/read/all.rb">
516
+ <td align="center" rowspan="2"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/read/all.rb">
517
517
  ✅ All
518
518
  </a></td>
519
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/write/all.rb">
519
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/write/all.rb">
520
520
  ✅ All
521
521
  </a></td>
522
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb">
522
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb">
523
523
  Readers of the messageboards<br>the user can post in
524
524
  </a></td>
525
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/moderate/if_moderator_column_true.rb">
525
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/moderate/if_moderator_column_true.rb">
526
526
  <code>moderator_column</code>
527
527
  </a></td>
528
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/admin/if_admin_column_true.rb">
528
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/admin/if_admin_column_true.rb">
529
529
  <code>admin_column</code>
530
530
  </a></td>
531
531
  </tr>
532
532
  <tr>
533
533
  <th align="center">Not logged in</th>
534
534
  <!-- rowspan -->
535
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/write/none.rb">
535
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/write/none.rb">
536
536
  ❌ No
537
537
  </a></td>
538
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb">
538
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb">
539
539
  ❌ No
540
540
  </a></td>
541
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/moderate/none.rb">
541
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/moderate/none.rb">
542
542
  ❌ No
543
543
  </a></td>
544
- <td align="center"><a href="https://github.com/thredded/thredded/blob/master/app/models/thredded/user_permissions/admin/none.rb">
544
+ <td align="center"><a href="https://github.com/thredded/thredded/blob/main/app/models/thredded/user_permissions/admin/none.rb">
545
545
  ❌ No
546
546
  </a></td>
547
547
  </tr>
@@ -551,7 +551,7 @@ Below is an overview of the default permissions, with links to the implementatio
551
551
  ### Handling "Permission denied" and "Not found" errors
552
552
 
553
553
  Thredded defines a number of Exception classes for not found / permission denied errors.
554
- The complete list can be found [here](https://github.com/thredded/thredded/blob/master/app/controllers/thredded/application_controller.rb#L18-L40).
554
+ The complete list can be found [here](https://github.com/thredded/thredded/blob/main/app/controllers/thredded/application_controller.rb#L18-L40).
555
555
 
556
556
  Currently, the default behaviour is to render an error message with an appropriate response code within the Thredded
557
557
  layout. You may want to override the handling for `Thredded::Errors::LoginRequired` to render a login form instead.
@@ -655,12 +655,24 @@ By default, the dummy app server uses Webpack for JavaScript.
655
655
  To use Sprockets instead, run:
656
656
 
657
657
  ```bash
658
- THREDDED_TESTAPP_WEBPACK=1 bin/rails s
658
+ THREDDED_TESTAPP_SPROCKETS=1 bin/rails s
659
659
  ```
660
660
 
661
+ alternatively you can use guard (which comes with activereload to make development more pleasant) with:
662
+
663
+ export THREDDED_USE_GUARD=1
664
+ bundle
665
+ bundle exec guard
666
+
667
+
661
668
  ### Testing
662
669
 
663
- To run the tests, just run `rspec`. The test suite will re-create the test database on every run, so there is no need to
670
+ In order to run the tests locally, you will need to be running webpack-dev-server (or do a manual compilation):
671
+
672
+ cd spec/dummy && yarn && cd -
673
+ BUNDLE_GEMFILE="${PWD}/Gemfile" spec/dummy/bin/webpack-dev-server
674
+
675
+ Then to run the tests, just run `rspec`. The test suite will re-create the test database on every run, so there is no need to
664
676
  run tasks that maintain the test database.
665
677
 
666
678
  By default, SQLite is used in development and test. On Travis, the tests will run using SQLite, PostgreSQL, MySQL,
@@ -677,8 +689,8 @@ sudo apt-get install chromium-chromedriver
677
689
  On Mac, run:
678
690
 
679
691
  ```bash
680
- brew cask install chromium
681
- brew cask install chromedriver
692
+ brew install --cask chromium
693
+ brew install --cask chromedriver
682
694
  ```
683
695
 
684
696
  To get better page saves (`page.save_and_open_page`) from local capybara specs ensure you are running the server locally
@@ -777,7 +789,7 @@ start the included docker-compose.yml file with:
777
789
 
778
790
  ```console
779
791
  docker-compose build
780
- docker-compose up -d
792
+ docker-compose up
781
793
  ```
782
794
 
783
795
  The above will build and run everything, daemonized, resulting in a running
@@ -797,4 +809,4 @@ docker-compose run web bundle exec rake
797
809
 
798
810
  The docker container uses PostgreSQL.
799
811
 
800
- [initializer]: https://github.com/thredded/thredded/blob/master/lib/generators/thredded/install/templates/initializer.rb
812
+ [initializer]: https://github.com/thredded/thredded/blob/main/lib/generators/thredded/install/templates/initializer.rb
@@ -27,7 +27,9 @@
27
27
  }, 200, false);
28
28
 
29
29
  textarea.addEventListener('input', onChange, false);
30
-
30
+ if(textarea.value.trim() !== '') {
31
+ onChange();
32
+ }
31
33
  this.requestId = 0;
32
34
  }
33
35
 
@@ -34,8 +34,8 @@ module Thredded
34
34
  end
35
35
 
36
36
  def first_topic_content
37
- <<-MARKDOWN
38
- #{I18n.t('thredded.messageboard_first_topic.content', thredded_version: Thredded::VERSION)}
37
+ <<~MARKDOWN
38
+ #{I18n.t('thredded.messageboard_first_topic.content', thredded_version: Thredded::VERSION)}
39
39
  MARKDOWN
40
40
  end
41
41
  end
@@ -2,6 +2,12 @@
2
2
 
3
3
  module Thredded
4
4
  module RenderPreview
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ skip_forgery_protection
9
+ end
10
+
5
11
  protected
6
12
 
7
13
  def render_preview
@@ -4,7 +4,11 @@ module Thredded
4
4
  class ApplicationController < ::ApplicationController # rubocop:disable Metrics/ClassLength
5
5
  layout :thredded_layout
6
6
  include ::Thredded::UrlsHelper
7
- include Pundit
7
+ if defined?(Pundit::Authorization)
8
+ include Pundit::Authorization
9
+ else
10
+ include Pundit
11
+ end
8
12
 
9
13
  helper Thredded::Engine.helpers
10
14
  helper_method \
@@ -63,15 +67,6 @@ module Thredded
63
67
  @is_thredded_moderator = !thredded_current_user.thredded_can_moderate_messageboards.empty?
64
68
  end
65
69
 
66
- if Rails::VERSION::MAJOR < 5
67
- # redirect_back polyfill
68
- def redirect_back(fallback_location:, **args)
69
- redirect_to :back, args
70
- rescue ActionController::RedirectBackError
71
- redirect_to fallback_location, args
72
- end
73
- end
74
-
75
70
  # @param given [Hash]
76
71
  # @return [Boolean] whether the given params are a subset of the controller's {#params}.
77
72
  def params_match?(given = {})
@@ -203,12 +203,6 @@ module Thredded
203
203
  @messageboard = topic.messageboard
204
204
  end
205
205
 
206
- def topic_params
207
- params
208
- .require(:topic)
209
- .permit(:title, :locked, :sticky, category_ids: [])
210
- end
211
-
212
206
  def topic_params_for_update
213
207
  params
214
208
  .require(:topic)
@@ -130,7 +130,7 @@ module Thredded
130
130
  end
131
131
  end
132
132
 
133
- def parse_names(text) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
133
+ def parse_names(text) # rubocop:disable Metrics/MethodLength
134
134
  result = []
135
135
  current = +''
136
136
  in_name = in_quoted = false
@@ -92,7 +92,7 @@ module Thredded
92
92
  end
93
93
 
94
94
  def paginate(collection, args = {})
95
- super(collection, args.reverse_merge(views_prefix: 'thredded'))
95
+ super(collection, **args.reverse_merge(views_prefix: 'thredded'))
96
96
  end
97
97
 
98
98
  # @param topic [BaseTopicView]
@@ -108,9 +108,9 @@ module Thredded
108
108
  # @param follow_reason ['manual', 'posted', 'mentioned', 'auto', nil]
109
109
  def topic_follow_reason_text(follow_reason)
110
110
  if follow_reason
111
- # rubocop:disable Metrics/LineLength
111
+ # rubocop:disable Layout/LineLength
112
112
  # i18n-tasks-use t('thredded.topics.following.manual') t('thredded.topics.following.posted') t('thredded.topics.following.mentioned') t('thredded.topics.following.auto')
113
- # rubocop:enable Metrics/LineLength
113
+ # rubocop:enable Layout/LineLength
114
114
  t("thredded.topics.following.#{follow_reason}")
115
115
  else
116
116
  t('thredded.topics.not_following')
@@ -54,7 +54,7 @@ module Thredded
54
54
  # @param user [Thredded.user_class] the current user
55
55
  # @return [String] path to the topic page with the post anchor.
56
56
  def post_path(post, user:, **params)
57
- post_url(post, params.merge(user: user, only_path: true))
57
+ post_url(post, **params.merge(user: user, only_path: true))
58
58
  end
59
59
 
60
60
  # @param post [Post, PrivatePost]
@@ -11,13 +11,13 @@ module Thredded
11
11
  protected
12
12
 
13
13
  def mock_content(mention_users: [])
14
- <<-MARKDOWN
15
- Hey #{mention_users.map { |u| "@#{u}" } * ', '}!
16
- All of the basic [Markdown](https://kramdown.gettalong.org/quickref.html) formatting is supported (powered by [Kramdown](https://kramdown.gettalong.org)).
14
+ <<~MARKDOWN
15
+ Hey #{mention_users.map { |u| "@#{u}" } * ', '}!
16
+ All of the basic [Markdown](https://kramdown.gettalong.org/quickref.html) formatting is supported (powered by [Kramdown](https://kramdown.gettalong.org)).
17
17
 
18
- Additionally, Markdown is extended to support the following:
18
+ Additionally, Markdown is extended to support the following:
19
19
 
20
- #{Thredded::FormattingDemoContent.parts.join("\n")}
20
+ #{Thredded::FormattingDemoContent.parts.join("\n")}
21
21
  MARKDOWN
22
22
  end
23
23
 
@@ -11,7 +11,7 @@ module Thredded
11
11
  end
12
12
 
13
13
  def include?(slug)
14
- @words.include?(slug) || slug =~ PAGINATION_PATTERN
14
+ @words.include?(slug) || PAGINATION_PATTERN.match?(slug)
15
15
  end
16
16
  end
17
17
  end
@@ -8,7 +8,7 @@ module Thredded
8
8
  delegate :human_name, to: :notifier, prefix: true
9
9
 
10
10
  def self.detect_or_default(prefs, notifier)
11
- (prefs && prefs.find { |pref| pref.notifier_key == notifier.key }) || default(notifier)
11
+ (prefs&.find { |pref| pref.notifier_key == notifier.key }) || default(notifier)
12
12
  end
13
13
  end
14
14
 
@@ -23,12 +23,12 @@ module Thredded
23
23
  result = all
24
24
  owners_by_id = result.each_with_object({}) { |r, h| h[r.postable_id] = r.postable }
25
25
  next result if owners_by_id.empty?
26
- preloader = ActiveRecord::Associations::Preloader.new.preload(
27
- owners_by_id.values, :first_post,
28
- unscoped.where(<<~SQL.delete("\n"))
29
- #{posts_table_name}.created_at = (
30
- SELECT MAX(p2.created_at) from #{posts_table_name} p2 WHERE p2.postable_id = #{posts_table_name}.postable_id)
31
- SQL
26
+ preloader = Thredded::Compat.association_preloader(
27
+ records: owners_by_id.values, associations: [:first_post],
28
+ scope: unscoped.where(<<~SQL.delete("\n"))
29
+ #{posts_table_name}.created_at = (
30
+ SELECT MAX(p2.created_at) from #{posts_table_name} p2 WHERE p2.postable_id = #{posts_table_name}.postable_id)
31
+ SQL
32
32
  )
33
33
  preloader[0].preloaded_records.each do |post|
34
34
  topic = owners_by_id.delete(post.postable_id)
@@ -68,7 +68,7 @@ module Thredded
68
68
  def mark_as_unread(user)
69
69
  if previous_post.nil?
70
70
  read_state = postable.user_read_states.find_by(user_id: user.id)
71
- read_state.destroy if read_state
71
+ read_state&.destroy
72
72
  else
73
73
  postable.user_read_states.touch!(user.id, previous_post, overwrite_newer: true)
74
74
  end
@@ -81,6 +81,7 @@ module Thredded
81
81
  protected
82
82
 
83
83
  def update_unread_posts_count
84
+ return if destroyed_by_association
84
85
  postable.user_read_states.update_post_counts!
85
86
  end
86
87
 
@@ -9,7 +9,7 @@ module Thredded
9
9
  belongs_to :last_user, # rubocop:disable Rails/InverseOf
10
10
  class_name: Thredded.user_class_name,
11
11
  foreign_key: 'last_user_id',
12
- **(Thredded.rails_gte_51? ? { optional: true } : {})
12
+ optional: true
13
13
 
14
14
  scope :order_recently_posted_first, -> { order(last_post_at: :desc, id: :desc) }
15
15
  scope :on_page, ->(page_num) { page(page_num) }
@@ -29,7 +29,7 @@ module Thredded
29
29
  def calculate_post_counts
30
30
  relation = self.class.visible_posts_scope(user).where(postable_id: postable_id)
31
31
  unread_posts_count, read_posts_count =
32
- Thredded::ArelCompat.pluck(relation, *self.class.post_counts_arel(read_at))[0]
32
+ relation.pluck(*self.class.post_counts_arel(read_at))[0]
33
33
  { unread_posts_count: unread_posts_count || 0, read_posts_count: read_posts_count || 0 }
34
34
  end
35
35
 
@@ -44,7 +44,7 @@ module Thredded
44
44
  selects << states[Arel.star] if !is_a?(ActiveRecord::Relation) || select_values.empty?
45
45
  selects += [
46
46
  Arel::Nodes::Case.new(states[:unread_posts_count].not_eq(0))
47
- .when(Thredded::ArelCompat.true_value(self)).then(
47
+ .when(true).then(
48
48
  Arel::Nodes::Addition.new(
49
49
  Thredded::ArelCompat.integer_division(self, states[:read_posts_count], posts_per_page), 1
50
50
  )
@@ -75,11 +75,11 @@ module Thredded
75
75
  [
76
76
  Arel::Nodes::Sum.new(
77
77
  [Arel::Nodes::Case.new(posts[:created_at].gt(read_at))
78
- .when(Thredded::ArelCompat.true_value(self)).then(1).else(0)]
78
+ .when(true).then(1).else(0)]
79
79
  ).as('unread_posts_count'),
80
80
  Arel::Nodes::Sum.new(
81
81
  [Arel::Nodes::Case.new(posts[:created_at].gt(read_at))
82
- .when(Thredded::ArelCompat.true_value(self)).then(0).else(1)]
82
+ .when(true).then(0).else(1)]
83
83
  ).as('read_posts_count')
84
84
  ]
85
85
  end
@@ -90,7 +90,7 @@ module Thredded
90
90
  posts = post_class.arel_table
91
91
  relation = joins(states.join(posts).on(states[:postable_id].eq(posts[:postable_id])).join_sources)
92
92
  .group(states[:id])
93
- Thredded::ArelCompat.pluck(relation, states[:id], *post_counts_arel(states[:read_at], posts: posts))
93
+ relation.pluck(states[:id], *post_counts_arel(states[:read_at], posts: posts))
94
94
  end
95
95
  end
96
96
  end
@@ -39,7 +39,7 @@ module Thredded
39
39
  has_many :posts, dependent: :destroy, inverse_of: :messageboard
40
40
  has_many :topics, dependent: :destroy, inverse_of: :messageboard
41
41
 
42
- belongs_to :last_topic, class_name: 'Thredded::Topic', **(Thredded.rails_gte_51? ? { optional: true } : {})
42
+ belongs_to :last_topic, class_name: 'Thredded::Topic', optional: true
43
43
 
44
44
  has_many :user_details, through: :posts
45
45
  has_many :messageboard_users,
@@ -65,7 +65,7 @@ module Thredded
65
65
  inverse_of: :messageboards,
66
66
  foreign_key: :messageboard_group_id,
67
67
  class_name: 'Thredded::MessageboardGroup',
68
- **(Thredded.rails_gte_51? ? { optional: true } : {})
68
+ optional: true
69
69
 
70
70
  has_many :post_moderation_records, inverse_of: :messageboard, dependent: :delete_all
71
71
  scope :top_level_messageboards, -> { where(group: nil) }
@@ -142,8 +142,7 @@ module Thredded
142
142
  relation = joins(:topics).merge(topics_scope).joins(
143
143
  messageboards.outer_join(read_states).on(read_states_join_cond).join_sources
144
144
  ).group(messageboards[:id])
145
- Thredded::ArelCompat.pluck(
146
- relation,
145
+ relation.pluck(
147
146
  :id,
148
147
  Arel::Nodes::Subtraction.new(topics[:id].count, read_states[:id].count)
149
148
  ).to_h
@@ -7,7 +7,7 @@ module Thredded
7
7
  inverse_of: :thredded_notifications_for_followed_topics
8
8
  belongs_to :messageboard,
9
9
  # If messageboard is `nil`, these are the global preferences.
10
- **(Thredded.rails_gte_51? ? { optional: true } : {})
10
+ optional: true
11
11
  belongs_to :user_preference,
12
12
  primary_key: :user_id,
13
13
  foreign_key: :user_id,
@@ -8,7 +8,7 @@ module Thredded
8
8
  belongs_to :user,
9
9
  class_name: Thredded.user_class_name,
10
10
  inverse_of: :thredded_posts,
11
- **(Thredded.rails_gte_51? ? { optional: true } : {})
11
+ optional: true
12
12
  belongs_to :messageboard,
13
13
  counter_cache: true,
14
14
  inverse_of: :posts
@@ -21,7 +21,7 @@ module Thredded
21
21
  primary_key: :user_id,
22
22
  foreign_key: :user_id,
23
23
  counter_cache: true,
24
- **(Thredded.rails_gte_51? ? { optional: true } : {})
24
+ optional: true
25
25
  has_many :moderation_records,
26
26
  class_name: 'Thredded::PostModerationRecord',
27
27
  dependent: :nullify
@@ -78,6 +78,7 @@ module Thredded
78
78
  end
79
79
 
80
80
  def update_parent_last_user_and_time_from_last_post
81
+ return if destroyed_by_association
81
82
  postable.update_last_user_and_time_from_last_post!
82
83
  messageboard.update_last_topic!
83
84
  end
@@ -3,25 +3,24 @@
3
3
  module Thredded
4
4
  class PostModerationRecord < ActiveRecord::Base
5
5
  include Thredded::ModerationState
6
- # Rails 4 doesn't support enum _prefix
7
- enum previous_moderation_state: moderation_states, _prefix: :previous if Rails::VERSION::MAJOR >= 5
6
+ enum previous_moderation_state: moderation_states, _prefix: :previous
8
7
  validates :previous_moderation_state, presence: true
9
8
 
10
9
  scope :order_newest_first, -> { order(created_at: :desc, id: :desc) }
11
10
 
12
11
  belongs_to :messageboard, inverse_of: :post_moderation_records
13
- validates :messageboard_id, presence: true unless Thredded.rails_gte_51?
12
+
14
13
  belongs_to :post,
15
14
  inverse_of: :moderation_records,
16
- **(Thredded.rails_gte_51? ? { optional: true } : {})
15
+ optional: true
17
16
  belongs_to :post_user,
18
17
  class_name: Thredded.user_class_name,
19
18
  inverse_of: :thredded_post_moderation_records,
20
- **(Thredded.rails_gte_51? ? { optional: true } : {})
19
+ optional: true
21
20
  belongs_to :moderator,
22
21
  class_name: Thredded.user_class_name,
23
22
  inverse_of: :thredded_post_moderation_records,
24
- **(Thredded.rails_gte_51? ? { optional: true } : {})
23
+ optional: true
25
24
 
26
25
  validates_each :moderation_state do |record, attr, value|
27
26
  record.errors.add attr, "Post moderation_state is already #{value}" if record.previous_moderation_state == value
@@ -30,14 +29,16 @@ module Thredded
30
29
  scope :preload_first_topic_post, -> {
31
30
  posts_table_name = Thredded::Post.quoted_table_name
32
31
  result = all
33
- owners_by_id = result.each_with_object({}) { |r, h| h[r.post.postable_id] = r.post.postable }
32
+ owners_by_id = result.each_with_object({}) do |r, h|
33
+ h[r.post.postable_id] = r.post.postable if r.post
34
+ end
34
35
  next result if owners_by_id.empty?
35
- preloader = ActiveRecord::Associations::Preloader.new.preload(
36
- owners_by_id.values, :first_post,
37
- Thredded::Post.unscoped.where(<<~SQL.delete("\n"))
36
+ preloader = Thredded::Compat.association_preloader(
37
+ records: owners_by_id.values, associations: [:first_post],
38
+ scope: Thredded::Post.unscoped.where(<<~SQL.delete("\n"))
38
39
  #{posts_table_name}.created_at = (
39
40
  SELECT MAX(p2.created_at) from #{posts_table_name} p2 WHERE p2.postable_id = #{posts_table_name}.postable_id)
40
- SQL
41
+ SQL
41
42
  )
42
43
  preloader[0].preloaded_records.each do |post|
43
44
  topic = owners_by_id.delete(post.postable_id)
@@ -60,8 +61,6 @@ module Thredded
60
61
  # @param [Symbol, String] moderation_state
61
62
  # @return [Thredded::PostModerationRecord] the newly created persisted record
62
63
  def self.record!(moderator:, post:, previous_moderation_state:, moderation_state:)
63
- # Rails 4 doesn't support enum _prefix
64
- previous_moderation_state = moderation_states[previous_moderation_state.to_s] if Rails::VERSION::MAJOR < 5
65
64
  create!(
66
65
  previous_moderation_state: previous_moderation_state,
67
66
  moderation_state: moderation_state,
@@ -7,7 +7,7 @@ module Thredded
7
7
  belongs_to :user,
8
8
  class_name: Thredded.user_class_name,
9
9
  inverse_of: :thredded_private_posts,
10
- **(Thredded.rails_gte_51? ? { optional: true } : {})
10
+ optional: true
11
11
  belongs_to :postable,
12
12
  class_name: 'Thredded::PrivateTopic',
13
13
  inverse_of: :posts,
@@ -16,7 +16,7 @@ module Thredded
16
16
  inverse_of: :private_posts,
17
17
  primary_key: :user_id,
18
18
  foreign_key: :user_id,
19
- **(Thredded.rails_gte_51? ? { optional: true } : {})
19
+ optional: true
20
20
 
21
21
  after_commit :update_parent_last_user_and_timestamp, on: %i[create destroy]
22
22
  after_commit :notify_users, on: [:create]
@@ -15,12 +15,12 @@ module Thredded
15
15
  belongs_to :user,
16
16
  class_name: Thredded.user_class_name,
17
17
  inverse_of: :thredded_private_topics,
18
- **(Thredded.rails_gte_51? ? { optional: true } : {})
18
+ optional: true
19
19
  belongs_to :user_detail,
20
20
  primary_key: :user_id,
21
21
  foreign_key: :user_id,
22
22
  inverse_of: :private_topics,
23
- **(Thredded.rails_gte_51? ? { optional: true } : {})
23
+ optional: true
24
24
 
25
25
  has_many :posts,
26
26
  class_name: 'Thredded::PrivatePost',
@@ -102,6 +102,8 @@ module Thredded
102
102
  end
103
103
 
104
104
  def ensure_user_in_private_users
105
+ # TODO: investigate performance of this. Seems to take a long time and be repeatedly called in tests
106
+ # can we avoid callling this so often
105
107
  users << user if user.present? && !users.include?(user)
106
108
  end
107
109
 
@@ -37,7 +37,7 @@ module Thredded
37
37
  belongs_to :user,
38
38
  class_name: Thredded.user_class_name,
39
39
  inverse_of: :thredded_topics,
40
- **(Thredded.rails_gte_51? ? { optional: true } : {})
40
+ optional: true
41
41
 
42
42
  belongs_to :messageboard,
43
43
  counter_cache: true,
@@ -50,7 +50,7 @@ module Thredded
50
50
  foreign_key: :user_id,
51
51
  inverse_of: :topics,
52
52
  counter_cache: :topics_count,
53
- **(Thredded.rails_gte_51? ? { optional: true } : {})
53
+ optional: true
54
54
 
55
55
  has_many :posts,
56
56
  autosave: true,
@@ -7,7 +7,7 @@ module Thredded
7
7
  belongs_to :user, class_name: Thredded.user_class_name, inverse_of: :thredded_user_detail
8
8
  validates :user_id,
9
9
  uniqueness: { case_sensitive: true },
10
- **(Thredded.rails_gte_51? ? {} : { presence: true })
10
+ presence: true
11
11
 
12
12
  with_options foreign_key: :user_id, primary_key: :user_id, inverse_of: :user_detail, dependent: :nullify do
13
13
  has_many :topics, class_name: 'Thredded::Topic'
@@ -30,7 +30,7 @@ module Thredded
30
30
  class_name: 'Thredded::MessageboardNotificationsForFollowedTopics'
31
31
  has_many :thredded_notifications_for_private_topics, class_name: 'Thredded::NotificationsForPrivateTopics'
32
32
  has_many :thredded_post_notifications, class_name: 'Thredded::UserPostNotification'
33
- has_many :thredded_private_users, class_name: 'Thredded::PrivateUser'
33
+ has_many :thredded_private_users, class_name: 'Thredded::PrivateUser', inverse_of: :user
34
34
  has_many :thredded_topic_read_states, class_name: 'Thredded::UserTopicReadState'
35
35
  has_many :thredded_private_topic_read_states, class_name: 'Thredded::UserPrivateTopicReadState'
36
36
  has_many :thredded_topic_follows, class_name: 'Thredded::UserTopicFollow'
@@ -13,6 +13,7 @@ module Thredded
13
13
  :blocked?,
14
14
  :last_moderation_record,
15
15
  :cache_key,
16
+ :cache_version,
16
17
  :cache_key_with_version,
17
18
  to: :@post
18
19