thredded 0.16.14 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|