thredded 0.16.11 → 0.16.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/controllers/thredded/moderation_controller.rb +2 -0
- data/app/helpers/thredded/moderation_helper.rb +23 -0
- data/app/models/concerns/thredded/post_common.rb +9 -2
- data/app/models/concerns/thredded/topic_common.rb +16 -4
- data/app/models/thredded/messageboard.rb +27 -10
- data/app/models/thredded/messageboard_group.rb +3 -1
- data/app/models/thredded/post_moderation_record.rb +25 -0
- data/app/models/thredded/user_detail.rb +3 -1
- data/app/views/thredded/moderation/_post_moderation_record.html.erb +9 -3
- data/app/views/thredded/moderation/_post_moderation_record_content.html.erb +3 -0
- data/app/views/thredded/moderation/activity.html.erb +1 -1
- data/app/views/thredded/moderation/history.html.erb +1 -1
- data/app/views/thredded/moderation/pending.html.erb +1 -1
- data/app/views/thredded/posts_common/_header_with_user_and_topic.html.erb +4 -2
- data/lib/thredded.rb +7 -0
- data/lib/thredded/db_tools.rb +6 -5
- data/lib/thredded/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd9dbf548a2ae13d2c77b2a49e4022af13b17e5df084dc22baf370e37d7b1a2f
|
4
|
+
data.tar.gz: 6f21adfcf7f040ab397637f03f47df3c4f9f15d3956dfd4fb3a2a09b9a871ddd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80692ab8668d1fdbcc60309774f2dcab3e8a6893b1a78892e9507ad4a9f70d9d91d174ce9277058622faba6d562c3187f4cf6dfa2aec92c97a9863a32b858b4f
|
7
|
+
data.tar.gz: dd5c3253a6df6f69512eb5acd778beb0ef7370be4b53b30fb03c865b6669af3e7e5217cc46e5feaf4695c1354cd9b748743b05f66edc94eff5c55a8ef810b886
|
data/README.md
CHANGED
@@ -95,7 +95,7 @@ Then, see the rest of this Readme for more information about using and customizi
|
|
95
95
|
Add the gem to your Gemfile:
|
96
96
|
|
97
97
|
```ruby
|
98
|
-
gem 'thredded', '~> 0.16.
|
98
|
+
gem 'thredded', '~> 0.16.12'
|
99
99
|
```
|
100
100
|
|
101
101
|
Add the Thredded [initializer] to your parent app by running the install generator.
|
@@ -19,6 +19,8 @@ module Thredded
|
|
19
19
|
@post_moderation_records = accessible_post_moderation_records
|
20
20
|
.order(created_at: :desc)
|
21
21
|
.send(Kaminari.config.page_method_name, current_page)
|
22
|
+
.preload(:messageboard, :post_user, :moderator, post: :postable)
|
23
|
+
.preload_first_topic_post
|
22
24
|
end
|
23
25
|
|
24
26
|
def activity
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thredded
|
4
|
+
module ModerationHelper
|
5
|
+
include ::Thredded::RenderHelper
|
6
|
+
|
7
|
+
# @param records [Array<Thredded::PostModerationRecord>]
|
8
|
+
def render_post_moderation_records(records)
|
9
|
+
records_with_post_contents = render_collection_to_strings_with_cache(
|
10
|
+
partial: 'thredded/moderation/post_moderation_record_content',
|
11
|
+
collection: records, as: :post_moderation_record, expires_in: 1.week,
|
12
|
+
locals: {
|
13
|
+
options: {
|
14
|
+
users_provider: ::Thredded::UsersProviderWithCache.new
|
15
|
+
}
|
16
|
+
}
|
17
|
+
)
|
18
|
+
render partial: 'thredded/moderation/post_moderation_record',
|
19
|
+
collection: records_with_post_contents,
|
20
|
+
as: :record_and_post_content
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -21,13 +21,20 @@ module Thredded
|
|
21
21
|
scope :preload_first_topic_post, -> {
|
22
22
|
posts_table_name = quoted_table_name
|
23
23
|
result = all
|
24
|
-
|
25
|
-
|
24
|
+
owners_by_id = result.each_with_object({}) { |r, h| h[r.postable_id] = r.postable }
|
25
|
+
next result if owners_by_id.empty?
|
26
|
+
preloader = ActiveRecord::Associations::Preloader.new.preload(
|
27
|
+
owners_by_id.values, :first_post,
|
26
28
|
unscoped.where(<<~SQL.delete("\n"))
|
27
29
|
#{posts_table_name}.created_at = (
|
28
30
|
SELECT MAX(p2.created_at) from #{posts_table_name} p2 WHERE p2.postable_id = #{posts_table_name}.postable_id)
|
29
31
|
SQL
|
30
32
|
)
|
33
|
+
preloader[0].preloaded_records.each do |post|
|
34
|
+
topic = owners_by_id.delete(post.postable_id)
|
35
|
+
next unless topic
|
36
|
+
topic.association(:first_post).target = post
|
37
|
+
end
|
31
38
|
result
|
32
39
|
}
|
33
40
|
|
@@ -14,7 +14,9 @@ module Thredded
|
|
14
14
|
scope :order_recently_posted_first, -> { order(last_post_at: :desc, id: :desc) }
|
15
15
|
scope :on_page, ->(page_num) { page(page_num) }
|
16
16
|
|
17
|
-
validates :hash_id,
|
17
|
+
validates :hash_id,
|
18
|
+
presence: true,
|
19
|
+
uniqueness: { case_sensitive: true }
|
18
20
|
validates :posts_count, numericality: true
|
19
21
|
|
20
22
|
validates :title, presence: true, length: { within: Thredded.topic_title_length_range }
|
@@ -53,9 +55,19 @@ module Thredded
|
|
53
55
|
topics = arel_table
|
54
56
|
reads_class = reflect_on_association(:user_read_states).klass
|
55
57
|
reads = reads_class.arel_table
|
56
|
-
|
57
|
-
|
58
|
-
.
|
58
|
+
|
59
|
+
joins_reads =
|
60
|
+
topics.outer_join(reads)
|
61
|
+
.on(topics[:id].eq(reads[:postable_id]).and(reads[:user_id].eq(user.id))).join_sources
|
62
|
+
|
63
|
+
unread_scope = reads_class.where(reads[:id].eq(nil).or(reads[:unread_posts_count].not_eq(0)))
|
64
|
+
|
65
|
+
# Work around https://github.com/rails/rails/issues/36761
|
66
|
+
if Thredded.rails_gte_600_rc_2?
|
67
|
+
merge(unread_scope).joins(joins_reads)
|
68
|
+
else
|
69
|
+
joins(joins_reads).merge(unread_scope)
|
70
|
+
end
|
59
71
|
end
|
60
72
|
|
61
73
|
private
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Thredded
|
4
|
-
class Messageboard < ActiveRecord::Base
|
4
|
+
class Messageboard < ActiveRecord::Base # rubocop:disable Metrics/ClassLength
|
5
5
|
extend FriendlyId
|
6
6
|
friendly_id :slug_candidates,
|
7
7
|
use: %i[slugged reserved],
|
@@ -21,7 +21,10 @@ module Thredded
|
|
21
21
|
]
|
22
22
|
)
|
23
23
|
|
24
|
-
validates :name,
|
24
|
+
validates :name,
|
25
|
+
uniqueness: { case_sensitive: false },
|
26
|
+
length: { within: Thredded.messageboard_name_length_range },
|
27
|
+
presence: true
|
25
28
|
validates :topics_count, numericality: true
|
26
29
|
validates :position, presence: true, on: :update
|
27
30
|
before_save :ensure_position
|
@@ -128,14 +131,28 @@ module Thredded
|
|
128
131
|
messageboards = arel_table
|
129
132
|
read_states = Thredded::UserTopicReadState.arel_table
|
130
133
|
topics = topics_scope.arel_table
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
134
|
+
|
135
|
+
read_states_join_cond =
|
136
|
+
messageboards[:id].eq(read_states[:messageboard_id])
|
137
|
+
.and(read_states[:postable_id].eq(topics[:id]))
|
138
|
+
.and(read_states[:user_id].eq(user.id))
|
139
|
+
.and(read_states[:unread_posts_count].eq(0))
|
140
|
+
|
141
|
+
scope =
|
142
|
+
# Work around https://github.com/rails/rails/issues/36761
|
143
|
+
if Thredded.rails_gte_600_rc_2?
|
144
|
+
merge(topics_scope).joins(
|
145
|
+
messageboards.join(topics)
|
146
|
+
.on(topics[:messageboard_id].eq(messageboards[:id]))
|
147
|
+
.outer_join(read_states).on(read_states_join_cond).join_sources
|
148
|
+
)
|
149
|
+
else
|
150
|
+
joins(:topics).merge(topics_scope).joins(
|
151
|
+
messageboards.outer_join(read_states).on(read_states_join_cond).join_sources
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
scope.group(messageboards[:id]).pluck(
|
139
156
|
:id,
|
140
157
|
Arel::Nodes::Subtraction.new(topics[:id].count, read_states[:id].count)
|
141
158
|
).to_h
|
@@ -8,7 +8,9 @@ module Thredded
|
|
8
8
|
dependent: :nullify
|
9
9
|
|
10
10
|
scope :ordered, -> { order(position: :asc, id: :asc) }
|
11
|
-
validates :name,
|
11
|
+
validates :name,
|
12
|
+
presence: true,
|
13
|
+
uniqueness: { case_sensitive: false }
|
12
14
|
validates :position, presence: true, on: :update
|
13
15
|
before_save :ensure_position
|
14
16
|
|
@@ -27,8 +27,33 @@ module Thredded
|
|
27
27
|
record.errors.add attr, "Post moderation_state is already #{value}" if record.previous_moderation_state == value
|
28
28
|
end
|
29
29
|
|
30
|
+
scope :preload_first_topic_post, -> {
|
31
|
+
posts_table_name = Thredded::Post.quoted_table_name
|
32
|
+
result = all
|
33
|
+
owners_by_id = result.each_with_object({}) { |r, h| h[r.post.postable_id] = r.post.postable }
|
34
|
+
next result if owners_by_id.empty?
|
35
|
+
preloader = ActiveRecord::Associations::Preloader.new.preload(
|
36
|
+
owners_by_id.values, :first_post,
|
37
|
+
Thredded::Post.unscoped.where(<<~SQL.delete("\n"))
|
38
|
+
#{posts_table_name}.created_at = (
|
39
|
+
SELECT MAX(p2.created_at) from #{posts_table_name} p2 WHERE p2.postable_id = #{posts_table_name}.postable_id)
|
40
|
+
SQL
|
41
|
+
)
|
42
|
+
preloader[0].preloaded_records.each do |post|
|
43
|
+
topic = owners_by_id.delete(post.postable_id)
|
44
|
+
next unless topic
|
45
|
+
topic.association(:first_post).target = post
|
46
|
+
end
|
47
|
+
result
|
48
|
+
}
|
49
|
+
|
30
50
|
paginates_per Thredded.posts_per_page
|
31
51
|
|
52
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] users that can read the moderated post.
|
53
|
+
def post_readers
|
54
|
+
Thredded.user_class.thredded_messageboards_readers([messageboard])
|
55
|
+
end
|
56
|
+
|
32
57
|
# @param [Thredded.user_class] moderator
|
33
58
|
# @param [Thredded::Post] post
|
34
59
|
# @param [Symbol, String] previous_moderation_state
|
@@ -5,7 +5,9 @@ module Thredded
|
|
5
5
|
include Thredded::ModerationState
|
6
6
|
|
7
7
|
belongs_to :user, class_name: Thredded.user_class_name, inverse_of: :thredded_user_detail
|
8
|
-
validates :user_id,
|
8
|
+
validates :user_id,
|
9
|
+
uniqueness: { case_sensitive: true },
|
10
|
+
**(Thredded.rails_gte_51? ? {} : { presence: true })
|
9
11
|
|
10
12
|
with_options foreign_key: :user_id, primary_key: :user_id, inverse_of: :user_detail, dependent: :nullify do
|
11
13
|
has_many :topics, class_name: 'Thredded::Topic'
|
@@ -1,5 +1,9 @@
|
|
1
1
|
<%
|
2
|
-
|
2
|
+
if local_assigns.key?(:record_and_post_content)
|
3
|
+
record, post_content = record_and_post_content
|
4
|
+
else
|
5
|
+
record = post_moderation_record
|
6
|
+
end
|
3
7
|
post = record.post
|
4
8
|
if post
|
5
9
|
post_view = Thredded::PostView.new(post, policy(post))
|
@@ -34,12 +38,14 @@
|
|
34
38
|
<% end %>
|
35
39
|
<% end %>
|
36
40
|
<% if post %>
|
37
|
-
<%= render 'thredded/posts_common/header_with_user_and_topic',
|
41
|
+
<%= render 'thredded/posts_common/header_with_user_and_topic',
|
42
|
+
post: post_view, user: record.post_user, post_user_link: post_user_link %>
|
38
43
|
<% else %>
|
39
44
|
<header><h2 class="thredded--post--user"><%= post_user_link %></h2></header>
|
40
45
|
<% end %>
|
41
46
|
<div class="thredded--post--content">
|
42
|
-
<%=
|
47
|
+
<%= post_content ||
|
48
|
+
render('thredded/moderation/post_moderation_record_content', post_moderation_record: record) %>
|
43
49
|
</div>
|
44
50
|
</article>
|
45
51
|
<%= render 'post_moderation_actions', post: post if post %>
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<h1><%= t 'thredded.recent_activity' %></h1>
|
8
8
|
<% if @last_moderated_record %>
|
9
9
|
<div class="thredded--moderated-notice">
|
10
|
-
<%=
|
10
|
+
<%= render_post_moderation_records([@last_moderated_record]) %>
|
11
11
|
</div>
|
12
12
|
<% end %>
|
13
13
|
<% if @posts.present? %>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= thredded_page do %>
|
7
7
|
<section class="thredded--main-section">
|
8
8
|
<% if @post_moderation_records.present? %>
|
9
|
-
<%=
|
9
|
+
<%= render_post_moderation_records @post_moderation_records %>
|
10
10
|
<%= paginate @post_moderation_records %>
|
11
11
|
<% end %>
|
12
12
|
</section>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<section class="thredded--main-section">
|
7
7
|
<% if @last_moderated_record %>
|
8
8
|
<div class="thredded--moderated-notice">
|
9
|
-
<%=
|
9
|
+
<%= render_post_moderation_records([@last_moderated_record]) %>
|
10
10
|
</div>
|
11
11
|
<% end %>
|
12
12
|
<% if @posts.present? %>
|
@@ -1,9 +1,11 @@
|
|
1
1
|
<%# @param post [Thredded::PostView] %>
|
2
|
+
<%# @param user [Thredded.user_class] optional %>
|
2
3
|
<%# @param post_user_link [String] optional %>
|
3
4
|
<% topic = post.to_model.postable %>
|
4
|
-
<%
|
5
|
+
<% user ||= post.user %>
|
6
|
+
<% post_user_link ||= user_link(user) %>
|
5
7
|
<header>
|
6
|
-
<%= image_tag
|
8
|
+
<%= image_tag Thredded.avatar_url.call(user), class: 'thredded--post--avatar' if user %>
|
7
9
|
<h2 class="thredded--post--user-and-topic">
|
8
10
|
<%=
|
9
11
|
topic_link = link_to(topic.title, post.permalink_path)
|
data/lib/thredded.rb
CHANGED
@@ -251,6 +251,13 @@ module Thredded # rubocop:disable Metrics/ModuleLength
|
|
251
251
|
@rails_gte_51
|
252
252
|
end
|
253
253
|
|
254
|
+
# @api private
|
255
|
+
# Mainly to work around https://github.com/rails/rails/issues/36761
|
256
|
+
def rails_gte_600_rc_2?
|
257
|
+
@rails_gte_600_rc_2 = (Rails.gem_version >= Gem::Version.new('6.0.0.rc2')) if @rails_gte_600_rc_2.nil?
|
258
|
+
@rails_gte_600_rc_2
|
259
|
+
end
|
260
|
+
|
254
261
|
# @api private
|
255
262
|
def rails_supports_csp_nonce?
|
256
263
|
@rails_supports_csp_nonce = (Rails.gem_version >= Gem::Version.new('5.2.0')) if @rails_supports_csp_nonce.nil?
|
data/lib/thredded/db_tools.rb
CHANGED
@@ -9,13 +9,14 @@ module Thredded
|
|
9
9
|
def migrate(paths:, quiet:, &filter)
|
10
10
|
verbose_was = ActiveRecord::Migration.verbose
|
11
11
|
ActiveRecord::Migration.verbose = !quiet
|
12
|
-
migrate =
|
13
|
-
if Rails
|
14
|
-
ActiveRecord::MigrationContext.new(paths).migrate(nil, &filter)
|
12
|
+
migrate =
|
13
|
+
if Rails.gem_version >= Gem::Version.new('6.0.0.rc2')
|
14
|
+
-> { ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration).migrate(nil, &filter) }
|
15
|
+
elsif Rails::VERSION::STRING >= '5.2'
|
16
|
+
-> { ActiveRecord::MigrationContext.new(paths).migrate(nil, &filter) }
|
15
17
|
else
|
16
|
-
ActiveRecord::Migrator.migrate(paths, &filter)
|
18
|
+
-> { ActiveRecord::Migrator.migrate(paths, &filter) }
|
17
19
|
end
|
18
|
-
}
|
19
20
|
if quiet
|
20
21
|
silence_active_record(&migrate)
|
21
22
|
else
|
data/lib/thredded/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thredded
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Oliveira
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-07-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: active_record_union
|
@@ -130,6 +130,9 @@ dependencies:
|
|
130
130
|
- - ">="
|
131
131
|
- !ruby/object:Gem::Version
|
132
132
|
version: 4.2.10
|
133
|
+
- - "<="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: 6.0.0.rc2
|
133
136
|
type: :runtime
|
134
137
|
prerelease: false
|
135
138
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -137,6 +140,9 @@ dependencies:
|
|
137
140
|
- - ">="
|
138
141
|
- !ruby/object:Gem::Version
|
139
142
|
version: 4.2.10
|
143
|
+
- - "<="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 6.0.0.rc2
|
140
146
|
- !ruby/object:Gem::Dependency
|
141
147
|
name: rb-gravatar
|
142
148
|
requirement: !ruby/object:Gem::Requirement
|
@@ -751,6 +757,7 @@ files:
|
|
751
757
|
- app/forms/thredded/user_preferences_form.rb
|
752
758
|
- app/helpers/thredded/application_helper.rb
|
753
759
|
- app/helpers/thredded/icon_helper.rb
|
760
|
+
- app/helpers/thredded/moderation_helper.rb
|
754
761
|
- app/helpers/thredded/nav_helper.rb
|
755
762
|
- app/helpers/thredded/render_helper.rb
|
756
763
|
- app/helpers/thredded/urls_helper.rb
|
@@ -854,6 +861,7 @@ files:
|
|
854
861
|
- app/views/thredded/moderation/_post.html.erb
|
855
862
|
- app/views/thredded/moderation/_post_moderation_actions.html.erb
|
856
863
|
- app/views/thredded/moderation/_post_moderation_record.html.erb
|
864
|
+
- app/views/thredded/moderation/_post_moderation_record_content.html.erb
|
857
865
|
- app/views/thredded/moderation/_user_moderation_state.html.erb
|
858
866
|
- app/views/thredded/moderation/_user_post.html.erb
|
859
867
|
- app/views/thredded/moderation/_users_search_form.html.erb
|