thredded 0.16.15 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![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=
|
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
|
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'
|