thredded 0.16.15 → 1.0.1
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.
- checksums.yaml +4 -4
- data/README.md +35 -23
- data/app/assets/javascripts/thredded/components/preview_area.es6 +3 -1
- data/app/commands/thredded/create_messageboard.rb +2 -2
- data/app/controllers/concerns/thredded/render_preview.rb +6 -0
- data/app/controllers/thredded/application_controller.rb +5 -10
- data/app/controllers/thredded/topics_controller.rb +0 -6
- data/app/forms/thredded/private_topic_form.rb +1 -1
- data/app/helpers/thredded/application_helper.rb +3 -3
- data/app/helpers/thredded/urls_helper.rb +1 -1
- data/app/mailer_previews/thredded/base_mailer_preview.rb +5 -5
- data/app/models/concerns/thredded/friendly_id_reserved_words_and_pagination.rb +1 -1
- data/app/models/concerns/thredded/notifier_preference.rb +1 -1
- data/app/models/concerns/thredded/post_common.rb +8 -7
- data/app/models/concerns/thredded/topic_common.rb +1 -1
- data/app/models/concerns/thredded/user_topic_read_state_common.rb +5 -5
- data/app/models/thredded/messageboard.rb +3 -4
- data/app/models/thredded/notifications_for_followed_topics.rb +1 -1
- data/app/models/thredded/post.rb +3 -2
- data/app/models/thredded/post_moderation_record.rb +12 -13
- data/app/models/thredded/private_post.rb +2 -2
- data/app/models/thredded/private_topic.rb +4 -2
- data/app/models/thredded/topic.rb +2 -2
- data/app/models/thredded/user_detail.rb +1 -1
- data/app/models/thredded/user_extender.rb +1 -1
- data/app/view_models/thredded/post_view.rb +1 -0
- data/app/view_models/thredded/posts_page_view.rb +10 -9
- data/app/view_models/thredded/private_topics_page_view.rb +10 -6
- data/app/view_models/thredded/topic_posts_page_view.rb +16 -3
- data/app/view_models/thredded/topics_page_view.rb +9 -6
- data/app/views/layouts/thredded/application.html.erb +2 -2
- data/app/views/thredded/messageboards/_form.html.erb +3 -3
- data/app/views/thredded/moderation/_post_moderation_record.html.erb +3 -3
- data/app/views/thredded/posts_common/_content.html.erb +1 -1
- data/app/views/thredded/posts_common/actions/_quote.html.erb +1 -1
- data/app/views/thredded/shared/_page.html.erb +1 -1
- data/app/views/thredded/shared/nav/_standalone.html.erb +2 -2
- data/bin/create_migration_fixture +23 -0
- data/bin/rubocop +11 -0
- data/config/i18n-tasks.yml +6 -1
- data/config/locales/de.yml +2 -0
- data/config/locales/en.yml +3 -1
- data/config/locales/es.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/it.yml +4 -2
- data/config/locales/pl.yml +2 -0
- data/config/locales/pt-BR.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/locales/zh-CN.yml +2 -0
- data/db/upgrade_migrations/20161019150201_upgrade_v0_7_to_v0_8.rb +5 -5
- data/db/upgrade_migrations/20180110200009_upgrade_thredded_v0_14_to_v0_15.rb +1 -1
- data/lib/generators/thredded/install/templates/initializer.rb +3 -3
- data/lib/thredded/arel_compat.rb +1 -42
- data/lib/thredded/base_migration.rb +2 -2
- data/lib/thredded/collection_to_strings_with_cache_renderer.rb +91 -28
- data/lib/thredded/compat.rb +35 -0
- data/lib/thredded/content_formatter.rb +30 -8
- data/lib/thredded/database_seeder.rb +11 -4
- data/lib/thredded/db_tools.rb +3 -5
- data/lib/thredded/email_transformer.rb +2 -2
- data/lib/thredded/engine.rb +1 -1
- data/lib/thredded/formatting_demo_content.rb +21 -21
- data/lib/thredded/html_pipeline/at_mention_filter.rb +1 -1
- data/lib/thredded/html_pipeline/onebox_filter.rb +3 -3
- data/lib/thredded/html_pipeline/utils.rb +1 -1
- data/lib/thredded/version.rb +1 -1
- data/lib/thredded.rb +3 -23
- metadata +56 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c38b0b431b19a2a3bcb74955be64a67835d60870754e65436e8498ca67729bc8
|
4
|
+
data.tar.gz: 1b9827d5ed79af58f52c86e5badb430e1b44dfaff0381fde2390ad08ce436b26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43a2362878a9949d88097d77efe90c7997483e1c70f0fb505ffff1fa06e2097036d6ae6aff829120a406bac06b9e1cbb0879c1b614cf0c8205f837044a6fb105
|
7
|
+
data.tar.gz: 6f59d7de62c088da6ef53bb474ab02bdc666313ff5e050f86c3a1414a7371d93d60874008dc2ce68b8df8a7601754fe9771fef1804e11e1a4060620968465917
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Thredded [](https://codeclimate.com/github/thredded/thredded) [](https://codeclimate.com/github/thredded/thredded) [](https://travis-ci.org/thredded/thredded/) [](https://codeclimate.com/github/thredded/thredded/coverage) [](http://inch-ci.org/github/thredded/thredded) [](https://gitter.im/thredded/thredded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
2
2
|
|
3
|
-
_Thredded_ is a Rails
|
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
|
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
|
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/
|
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/
|
370
|
-
[thredded-scss-base]: https://github.com/thredded/thredded/blob/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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/
|
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
|
-
|
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
|
-
|
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
|
681
|
-
brew cask
|
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
|
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/
|
812
|
+
[initializer]: https://github.com/thredded/thredded/blob/main/lib/generators/thredded/install/templates/initializer.rb
|
@@ -34,8 +34,8 @@ module Thredded
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def first_topic_content
|
37
|
-
|
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
|
@@ -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
|
-
|
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/
|
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
|
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
|
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
|
-
|
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
|
|
@@ -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
|
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 =
|
27
|
-
owners_by_id.values, :first_post,
|
28
|
-
unscoped.where(<<~SQL.delete("\n"))
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
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
|
-
|
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
|
-
|
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(
|
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(
|
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(
|
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
|
-
|
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',
|
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
|
-
|
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
|
-
|
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
|
-
|
10
|
+
optional: true
|
11
11
|
belongs_to :user_preference,
|
12
12
|
primary_key: :user_id,
|
13
13
|
foreign_key: :user_id,
|
data/app/models/thredded/post.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
12
|
+
|
14
13
|
belongs_to :post,
|
15
14
|
inverse_of: :moderation_records,
|
16
|
-
|
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
|
-
|
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
|
-
|
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({})
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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'
|