thredded 0.16.14 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +19 -7
- data/app/assets/javascripts/thredded/components/preview_area.es6 +3 -1
- 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/helpers/thredded/application_helper.rb +1 -1
- data/app/helpers/thredded/icon_helper.rb +1 -1
- data/app/helpers/thredded/urls_helper.rb +1 -1
- data/app/models/concerns/thredded/post_common.rb +5 -4
- data/app/models/concerns/thredded/topic_common.rb +1 -1
- data/app/models/concerns/thredded/user_topic_read_state_common.rb +7 -8
- data/app/models/thredded/messageboard.rb +5 -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 +8 -9
- 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/models/thredded/user_private_topic_read_state.rb +3 -0
- data/app/models/thredded/user_topic_read_state.rb +3 -0
- 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/posts_common/_actions.html.erb +1 -1
- 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/_moderation.html.erb +3 -3
- data/app/views/thredded/shared/nav/_notification_preferences.html.erb +1 -1
- data/app/views/thredded/shared/nav/_private_topics.html.erb +3 -3
- data/app/views/thredded/shared/nav/_standalone.html.erb +2 -2
- data/app/views/thredded/topics/_header.html.erb +1 -1
- data/bin/create_migration_fixture +23 -0
- data/config/i18n-tasks.yml +5 -0
- 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/20180110200009_upgrade_thredded_v0_14_to_v0_15.rb +1 -1
- data/lib/generators/thredded/install/templates/initializer.rb +2 -2
- data/lib/thredded/arel_compat.rb +0 -32
- data/lib/thredded/base_migration.rb +1 -1
- data/lib/thredded/collection_to_strings_with_cache_renderer.rb +91 -28
- data/lib/thredded/compat.rb +35 -0
- data/lib/thredded/database_seeder.rb +11 -4
- data/lib/thredded/db_tools.rb +2 -4
- data/lib/thredded/email_transformer.rb +2 -2
- data/lib/thredded/html_pipeline/onebox_filter.rb +1 -4
- data/lib/thredded/version.rb +1 -1
- data/lib/thredded.rb +3 -23
- metadata +43 -31
- data/bin/rubocop +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a7da465ff23d46ffb17f30aef22bc8195dc7551f485d28d698f3a8e20aaf958
|
4
|
+
data.tar.gz: 24d752703abdc40ba28ffa48d931d70d5c9baeff461467059e7f2c2fbdfea27c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dec36328aba9edd1143d2aecaa70970ba48897ed470e97785c534067c6d5f38e0e175d4637a5824f1d09827059ab508147c2c721400a8027e966884f235a74d
|
7
|
+
data.tar.gz: c35c5f19f198b78b0d6426b96e1f15863cb29ff74c5a130d665a1fde1dd89d9f5af8bb194b0991d2a7bf965aa9fe6309af0de03246a6bf7d2711e1356b34d636
|
data/README.md
CHANGED
@@ -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
|
|
@@ -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
|
@@ -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)
|
@@ -25,7 +25,7 @@ module Thredded
|
|
25
25
|
def inline_svg_once(filename, id:, **transform_params)
|
26
26
|
return if @already_inlined_svg_ids&.include?(id)
|
27
27
|
record_already_inlined_svg(filename, id)
|
28
|
-
|
28
|
+
inline_svg_tag(filename, id: id, **transform_params)
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
@@ -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]
|
@@ -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"))
|
26
|
+
preloader = Thredded::Compat.association_preloader(
|
27
|
+
records: owners_by_id.values, associations: [:first_post],
|
28
|
+
scope: unscoped.where(<<~SQL.delete("\n"))
|
29
29
|
#{posts_table_name}.created_at = (
|
30
30
|
SELECT MAX(p2.created_at) from #{posts_table_name} p2 WHERE p2.postable_id = #{posts_table_name}.postable_id)
|
31
|
-
|
31
|
+
SQL
|
32
32
|
)
|
33
33
|
preloader[0].preloaded_records.each do |post|
|
34
34
|
topic = owners_by_id.delete(post.postable_id)
|
@@ -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) }
|
@@ -27,10 +27,9 @@ module Thredded
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def calculate_post_counts
|
30
|
+
relation = self.class.visible_posts_scope(user).where(postable_id: postable_id)
|
30
31
|
unread_posts_count, read_posts_count =
|
31
|
-
self.class.
|
32
|
-
.where(postable_id: postable_id)
|
33
|
-
.pluck(*self.class.post_counts_arel(read_at))[0]
|
32
|
+
relation.pluck(*self.class.post_counts_arel(read_at))[0]
|
34
33
|
{ unread_posts_count: unread_posts_count || 0, read_posts_count: read_posts_count || 0 }
|
35
34
|
end
|
36
35
|
|
@@ -45,7 +44,7 @@ module Thredded
|
|
45
44
|
selects << states[Arel.star] if !is_a?(ActiveRecord::Relation) || select_values.empty?
|
46
45
|
selects += [
|
47
46
|
Arel::Nodes::Case.new(states[:unread_posts_count].not_eq(0))
|
48
|
-
.when(
|
47
|
+
.when(true).then(
|
49
48
|
Arel::Nodes::Addition.new(
|
50
49
|
Thredded::ArelCompat.integer_division(self, states[:read_posts_count], posts_per_page), 1
|
51
50
|
)
|
@@ -76,11 +75,11 @@ module Thredded
|
|
76
75
|
[
|
77
76
|
Arel::Nodes::Sum.new(
|
78
77
|
[Arel::Nodes::Case.new(posts[:created_at].gt(read_at))
|
79
|
-
.when(
|
78
|
+
.when(true).then(1).else(0)]
|
80
79
|
).as('unread_posts_count'),
|
81
80
|
Arel::Nodes::Sum.new(
|
82
81
|
[Arel::Nodes::Case.new(posts[:created_at].gt(read_at))
|
83
|
-
.when(
|
82
|
+
.when(true).then(0).else(1)]
|
84
83
|
).as('read_posts_count')
|
85
84
|
]
|
86
85
|
end
|
@@ -89,9 +88,9 @@ module Thredded
|
|
89
88
|
def calculate_post_counts
|
90
89
|
states = arel_table
|
91
90
|
posts = post_class.arel_table
|
92
|
-
joins(states.join(posts).on(states[:postable_id].eq(posts[:postable_id])).join_sources)
|
91
|
+
relation = joins(states.join(posts).on(states[:postable_id].eq(posts[:postable_id])).join_sources)
|
93
92
|
.group(states[:id])
|
94
|
-
|
93
|
+
relation.pluck(states[:id], *post_counts_arel(states[:read_at], posts: posts))
|
95
94
|
end
|
96
95
|
end
|
97
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) }
|
@@ -139,9 +139,10 @@ module Thredded
|
|
139
139
|
.and(read_states[:user_id].eq(user.id))
|
140
140
|
.and(read_states[:unread_posts_count].eq(0))
|
141
141
|
|
142
|
-
joins(:topics).merge(topics_scope).joins(
|
142
|
+
relation = joins(:topics).merge(topics_scope).joins(
|
143
143
|
messageboards.outer_join(read_states).on(read_states_join_cond).join_sources
|
144
|
-
).group(messageboards[:id])
|
144
|
+
).group(messageboards[:id])
|
145
|
+
relation.pluck(
|
145
146
|
:id,
|
146
147
|
Arel::Nodes::Subtraction.new(topics[:id].count, read_states[:id].count)
|
147
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,7 +29,9 @@ 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
36
|
preloader = ActiveRecord::Associations::Preloader.new.preload(
|
36
37
|
owners_by_id.values, :first_post,
|
@@ -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'
|
@@ -27,6 +27,9 @@ module Thredded
|
|
27
27
|
return if !overwrite_newer && state.read_at? && state.read_at >= post.created_at
|
28
28
|
state.read_at = post.created_at
|
29
29
|
state.update!(state.calculate_post_counts)
|
30
|
+
rescue ActiveRecord::RecordNotUnique
|
31
|
+
# The record has been created from another connection, retry to find it.
|
32
|
+
retry
|
30
33
|
end
|
31
34
|
|
32
35
|
# @param [Thredded.user_class] user
|
@@ -31,6 +31,9 @@ module Thredded
|
|
31
31
|
state.messageboard_id = post.messageboard_id
|
32
32
|
state.read_at = post.created_at
|
33
33
|
state.update!(state.calculate_post_counts)
|
34
|
+
rescue ActiveRecord::RecordNotUnique
|
35
|
+
# The record has been created from another connection, retry to find it.
|
36
|
+
retry
|
34
37
|
end
|
35
38
|
|
36
39
|
# @param [Thredded.user_class] user
|
@@ -3,24 +3,25 @@
|
|
3
3
|
module Thredded
|
4
4
|
# A view model for a page of PostViews.
|
5
5
|
class PostsPageView
|
6
|
-
delegate :
|
6
|
+
delegate :each,
|
7
|
+
:each_with_index,
|
8
|
+
:map,
|
9
|
+
:size,
|
10
|
+
:to_a,
|
7
11
|
:to_ary,
|
8
12
|
:present?,
|
9
13
|
to: :@post_views
|
10
14
|
delegate :total_pages,
|
11
15
|
:current_page,
|
12
16
|
:limit_value,
|
13
|
-
to: :@
|
14
|
-
|
15
|
-
# @return [Thredded::BaseTopicView]
|
16
|
-
attr_reader :topic
|
17
|
+
to: :@posts_paginator
|
17
18
|
|
18
19
|
# @param user [Thredded.user_class] the user who is viewing the posts page
|
19
|
-
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>]
|
20
|
-
def initialize(user, paginated_scope
|
21
|
-
@
|
20
|
+
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>] a kaminari-decorated ".page" scope
|
21
|
+
def initialize(user, paginated_scope)
|
22
|
+
@posts_paginator = paginated_scope
|
22
23
|
@post_views = paginated_scope.map do |post|
|
23
|
-
Thredded::PostView.new(post, Pundit.policy!(user, post)
|
24
|
+
Thredded::PostView.new(post, Pundit.policy!(user, post))
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
@@ -3,7 +3,11 @@
|
|
3
3
|
module Thredded
|
4
4
|
# A view model for a page of BaseTopicViews.
|
5
5
|
class PrivateTopicsPageView
|
6
|
-
delegate :
|
6
|
+
delegate :each,
|
7
|
+
:each_with_index,
|
8
|
+
:map,
|
9
|
+
:size,
|
10
|
+
:to_a,
|
7
11
|
:to_ary,
|
8
12
|
:blank?,
|
9
13
|
:empty?,
|
@@ -11,13 +15,13 @@ module Thredded
|
|
11
15
|
delegate :total_pages,
|
12
16
|
:current_page,
|
13
17
|
:limit_value,
|
14
|
-
to: :@
|
18
|
+
to: :@topics_paginator
|
15
19
|
|
16
|
-
# @param user [Thredded.user_class] the user who is viewing the
|
17
|
-
# @param topics_page_scope [ActiveRecord::Relation<Thredded::
|
20
|
+
# @param user [Thredded.user_class] the user who is viewing the private topics page
|
21
|
+
# @param topics_page_scope [ActiveRecord::Relation<Thredded::PrivateTopic>] a kaminari-decorated ".page" scope
|
18
22
|
def initialize(user, topics_page_scope)
|
19
|
-
@
|
20
|
-
@topic_views = @
|
23
|
+
@topics_paginator = refine_scope(topics_page_scope)
|
24
|
+
@topic_views = @topics_paginator.with_read_states(user).map do |(topic, read_state)|
|
21
25
|
Thredded::PrivateTopicView.new(topic, read_state, Pundit.policy!(user, topic))
|
22
26
|
end
|
23
27
|
end
|
@@ -2,15 +2,28 @@
|
|
2
2
|
|
3
3
|
module Thredded
|
4
4
|
# A view model for a page of PostViews of a Topic.
|
5
|
-
class TopicPostsPageView
|
5
|
+
class TopicPostsPageView
|
6
|
+
delegate :each,
|
7
|
+
:each_with_index,
|
8
|
+
:map,
|
9
|
+
:size,
|
10
|
+
:to_a,
|
11
|
+
:to_ary,
|
12
|
+
:present?,
|
13
|
+
to: :@post_views
|
14
|
+
delegate :total_pages,
|
15
|
+
:current_page,
|
16
|
+
:limit_value,
|
17
|
+
to: :@posts_paginator
|
18
|
+
|
6
19
|
# @return [Thredded::BaseTopicView]
|
7
20
|
attr_reader :topic
|
8
21
|
|
9
22
|
# @param user [Thredded.user_class] the user who is viewing the posts page
|
10
23
|
# @param topic [Thredded::TopicCommon]
|
11
|
-
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>]
|
24
|
+
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>] a kaminari-decorated ".page" scope
|
12
25
|
def initialize(user, topic, paginated_scope)
|
13
|
-
@
|
26
|
+
@posts_paginator = paginated_scope
|
14
27
|
@topic = "#{paginated_scope.reflect_on_association(:postable).klass}View".constantize.from_user(topic, user)
|
15
28
|
prev_read = false
|
16
29
|
@post_views = paginated_scope.map.with_index do |post, i|
|
@@ -8,18 +8,21 @@ module Thredded
|
|
8
8
|
:blank?,
|
9
9
|
:empty?,
|
10
10
|
:[],
|
11
|
+
:each,
|
12
|
+
:map,
|
13
|
+
:size,
|
11
14
|
to: :@topic_views
|
12
15
|
delegate :total_pages,
|
13
16
|
:current_page,
|
14
17
|
:limit_value,
|
15
|
-
to: :@
|
18
|
+
to: :@topics_paginator
|
16
19
|
|
17
|
-
# @param user [Thredded.user_class] the user who is viewing the
|
18
|
-
# @param topics_page_scope [ActiveRecord::Relation<Thredded::Topic>]
|
19
|
-
# @param topic_view_class [Class] view_model for topic instances
|
20
|
+
# @param user [Thredded.user_class] the user who is viewing the topics page
|
21
|
+
# @param topics_page_scope [ActiveRecord::Relation<Thredded::Topic>] a kaminari-decorated ".page" scope
|
22
|
+
# @param topic_view_class [Class<TopicView>] view_model for topic instances
|
20
23
|
def initialize(user, topics_page_scope, topic_view_class: TopicView)
|
21
|
-
@
|
22
|
-
@topic_views = @
|
24
|
+
@topics_paginator = refine_scope(topics_page_scope)
|
25
|
+
@topic_views = @topics_paginator.with_read_and_follow_states(user).map do |(topic, read_state, follow)|
|
23
26
|
topic_view_class.new(topic, read_state, follow, Pundit.policy!(user, topic))
|
24
27
|
end
|
25
28
|
end
|
@@ -5,12 +5,12 @@
|
|
5
5
|
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
|
6
6
|
<%= stylesheet_link_tag 'thredded', 'data-turbolinks-track': 'reload' %>
|
7
7
|
<%= csrf_meta_tag %>
|
8
|
-
<%= csp_meta_tag
|
8
|
+
<%= csp_meta_tag %>
|
9
9
|
<%= javascript_include_tag 'thredded',
|
10
10
|
async: !Rails.application.config.assets.debug,
|
11
11
|
defer: true,
|
12
12
|
'data-turbolinks-track': 'reload' %>
|
13
|
-
|
13
|
+
<%= RailsGravatar.prefetch_dns_tag %>
|
14
14
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
15
15
|
</head>
|
16
16
|
<body>
|