thredded 0.4.0 → 0.5.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/CHANGELOG.mkdn +26 -0
- data/README.mkdn +52 -7
- data/app/assets/images/thredded/moderation.svg +4 -0
- data/app/assets/images/thredded/private-messages.svg +1 -1
- data/app/assets/images/thredded/settings.svg +1 -1
- data/app/assets/stylesheets/thredded/_base.scss +1 -1
- data/app/assets/stylesheets/thredded/_thredded.scss +1 -0
- data/app/assets/stylesheets/thredded/base/_buttons.scss +16 -0
- data/app/assets/stylesheets/thredded/base/_grid.scss +12 -0
- data/app/assets/stylesheets/thredded/components/_base.scss +4 -0
- data/app/assets/stylesheets/thredded/components/_messageboard.scss +1 -13
- data/app/assets/stylesheets/thredded/components/_topic-header.scss +27 -0
- data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +1 -1
- data/app/assets/stylesheets/thredded/layout/_moderation.scss +45 -0
- data/app/assets/stylesheets/thredded/layout/_navigation.scss +20 -6
- data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +2 -2
- data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +5 -3
- data/app/commands/thredded/autofollow_mentioned_users.rb +32 -0
- data/app/commands/thredded/moderate_post.rb +35 -0
- data/app/commands/thredded/notify_following_users.rb +18 -0
- data/app/commands/thredded/notify_private_topic_users.rb +4 -4
- data/app/controllers/thredded/application_controller.rb +6 -25
- data/app/controllers/thredded/messageboards_controller.rb +5 -3
- data/app/controllers/thredded/moderation_controller.rb +56 -0
- data/app/controllers/thredded/post_permalinks_controller.rb +1 -1
- data/app/controllers/thredded/posts_controller.rb +4 -2
- data/app/controllers/thredded/private_post_permalinks_controller.rb +1 -1
- data/app/controllers/thredded/private_topics_controller.rb +2 -3
- data/app/controllers/thredded/theme_previews_controller.rb +3 -3
- data/app/controllers/thredded/topics_controller.rb +32 -11
- data/app/forms/thredded/topic_form.rb +1 -0
- data/app/helpers/thredded/application_helper.rb +26 -1
- data/app/helpers/thredded/urls_helper.rb +7 -5
- data/app/jobs/thredded/auto_follow_and_notify_job.rb +13 -0
- data/app/jobs/thredded/notify_private_topic_users_job.rb +3 -4
- data/app/mailer_previews/thredded/post_mailer_preview.rb +2 -2
- data/app/mailers/thredded/post_mailer.rb +2 -2
- data/app/models/concerns/thredded/content_moderation_state.rb +53 -0
- data/app/models/concerns/thredded/moderation_state.rb +13 -0
- data/app/models/concerns/thredded/post_common.rb +6 -71
- data/app/models/concerns/thredded/topic_common.rb +26 -11
- data/app/models/concerns/thredded/user_topic_read_state_common.rb +4 -0
- data/app/models/thredded/messageboard.rb +2 -0
- data/app/models/thredded/post.rb +24 -0
- data/app/models/thredded/post_moderation_record.rb +45 -0
- data/app/models/thredded/private_post.rb +15 -0
- data/app/models/thredded/private_topic.rb +8 -0
- data/app/models/thredded/topic.rb +39 -0
- data/app/models/thredded/user_detail.rb +11 -0
- data/app/models/thredded/user_extender.rb +14 -0
- data/app/models/thredded/user_topic_follow.rb +20 -0
- data/app/policies/thredded/messageboard_policy.rb +15 -0
- data/app/policies/thredded/post_policy.rb +17 -1
- data/app/policies/thredded/private_post_policy.rb +1 -1
- data/app/policies/thredded/private_topic_policy.rb +1 -1
- data/app/policies/thredded/topic_policy.rb +18 -1
- data/app/view_models/thredded/base_topic_view.rb +0 -13
- data/app/view_models/thredded/post_view.rb +8 -1
- data/app/view_models/thredded/posts_page_view.rb +6 -8
- data/app/view_models/thredded/private_topic_view.rb +8 -0
- data/app/view_models/thredded/private_topics_page_view.rb +24 -0
- data/app/view_models/thredded/topic_posts_page_view.rb +17 -0
- data/app/view_models/thredded/topic_view.rb +27 -1
- data/app/view_models/thredded/topics_page_view.rb +2 -4
- data/app/views/thredded/moderation/_post.html.erb +7 -0
- data/app/views/thredded/moderation/_post_moderation_actions.html.erb +12 -0
- data/app/views/thredded/moderation/_post_moderation_record.html.erb +43 -0
- data/app/views/thredded/moderation/history.html.erb +19 -0
- data/app/views/thredded/moderation/pending.html.erb +29 -0
- data/app/views/thredded/post_mailer/{at_notification.html.erb → post_notification.html.erb} +1 -1
- data/app/views/thredded/post_mailer/{at_notification.text.erb → post_notification.text.erb} +1 -1
- data/app/views/thredded/posts/_post.html.erb +8 -1
- data/app/views/thredded/posts_common/_actions.html.erb +11 -0
- data/app/views/thredded/posts_common/_content.html.erb +5 -0
- data/app/views/thredded/posts_common/_header.html.erb +5 -0
- data/app/views/thredded/private_posts/_private_post.html.erb +5 -1
- data/app/views/thredded/shared/_nav.html.erb +1 -0
- data/app/views/thredded/shared/_page.html.erb +1 -1
- data/app/views/thredded/shared/nav/_moderation.html.erb +13 -0
- data/app/views/thredded/shared/nav/_private_topics.html.erb +1 -2
- data/app/views/thredded/topics/_header.html.erb +15 -0
- data/app/views/thredded/topics/index.html.erb +2 -2
- data/app/views/thredded/topics/new.html.erb +1 -1
- data/config/locales/en.yml +26 -5
- data/config/locales/pt-BR.yml +23 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20160329231848_create_thredded.rb +40 -5
- data/db/seeds.rb +5 -5
- data/db/upgrade_migrations/20160429222452_upgrade_v0_3_to_v0_4.rb +1 -2
- data/db/upgrade_migrations/20160501151908_upgrade_v0_4_to_v0_5.rb +56 -0
- data/heroku.gemfile.lock +20 -18
- data/lib/generators/thredded/install/templates/initializer.rb +15 -0
- data/lib/html/pipeline/at_mention_filter.rb +5 -2
- data/lib/thredded.rb +4 -0
- data/lib/thredded/at_users.rb +3 -2
- data/lib/thredded/content_formatter.rb +81 -0
- data/lib/thredded/version.rb +1 -1
- metadata +28 -10
- data/app/commands/thredded/notify_mentioned_users.rb +0 -55
- data/app/jobs/thredded/at_notifier_job.rb +0 -12
- data/app/mailer_previews/thredded/private_post_mailer_preview.rb +0 -12
- data/app/mailers/thredded/private_post_mailer.rb +0 -17
- data/app/views/thredded/posts_common/_post.html.erb +0 -26
- data/app/views/thredded/private_post_mailer/at_notification.html.erb +0 -13
|
@@ -14,6 +14,10 @@ module Thredded
|
|
|
14
14
|
belongs_to :user,
|
|
15
15
|
class_name: Thredded.user_class,
|
|
16
16
|
inverse_of: :thredded_private_topics
|
|
17
|
+
belongs_to :user_detail,
|
|
18
|
+
primary_key: :user_id,
|
|
19
|
+
foreign_key: :user_id,
|
|
20
|
+
inverse_of: :private_topics
|
|
17
21
|
|
|
18
22
|
has_many :posts,
|
|
19
23
|
class_name: 'Thredded::PrivatePost',
|
|
@@ -54,6 +58,10 @@ module Thredded
|
|
|
54
58
|
false
|
|
55
59
|
end
|
|
56
60
|
|
|
61
|
+
def user_detail
|
|
62
|
+
super || build_user_detail
|
|
63
|
+
end
|
|
64
|
+
|
|
57
65
|
def should_generate_new_friendly_id?
|
|
58
66
|
title_changed?
|
|
59
67
|
end
|
|
@@ -3,6 +3,7 @@ require_dependency 'thredded/topics_search'
|
|
|
3
3
|
module Thredded
|
|
4
4
|
class Topic < ActiveRecord::Base
|
|
5
5
|
include TopicCommon
|
|
6
|
+
include ContentModerationState
|
|
6
7
|
|
|
7
8
|
scope :for_messageboard, -> messageboard { where(messageboard_id: messageboard.id) }
|
|
8
9
|
|
|
@@ -53,6 +54,14 @@ module Thredded
|
|
|
53
54
|
foreign_key: :postable_id,
|
|
54
55
|
inverse_of: :postable,
|
|
55
56
|
dependent: :destroy
|
|
57
|
+
has_many :user_follows,
|
|
58
|
+
class_name: 'Thredded::UserTopicFollow',
|
|
59
|
+
inverse_of: :topic,
|
|
60
|
+
dependent: :destroy
|
|
61
|
+
has_many :following_users,
|
|
62
|
+
class_name: Thredded.user_class,
|
|
63
|
+
source: :user,
|
|
64
|
+
through: :user_follows
|
|
56
65
|
|
|
57
66
|
def self.find_by_slug!(slug)
|
|
58
67
|
friendly.find(slug)
|
|
@@ -60,10 +69,40 @@ module Thredded
|
|
|
60
69
|
raise Thredded::Errors::TopicNotFound
|
|
61
70
|
end
|
|
62
71
|
|
|
72
|
+
class << self
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# @param user [Thredded.user_class]
|
|
76
|
+
# @return [ByPostableLookup]
|
|
77
|
+
def follows_by_topic_hash(user)
|
|
78
|
+
Thredded::TopicCommon::CachingHash.from_relation(
|
|
79
|
+
Thredded::UserTopicFollow.where(user_id: user.id, topic_id: current_scope.map(&:id))
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
public
|
|
84
|
+
|
|
85
|
+
# @param user [Thredded.user_class]
|
|
86
|
+
# @return [Array<[TopicCommon, UserTopicReadStateCommon, UserTopicFollow]>]
|
|
87
|
+
def with_read_and_follow_states(user)
|
|
88
|
+
null_read_state = Thredded::NullUserTopicReadState.new
|
|
89
|
+
return current_scope.zip([null_read_state, nil]) if user.thredded_anonymous?
|
|
90
|
+
read_states_by_topic = read_states_by_postable_hash(user)
|
|
91
|
+
follows_by_topic = follows_by_topic_hash(user)
|
|
92
|
+
current_scope.map do |topic|
|
|
93
|
+
[topic, read_states_by_topic[topic] || null_read_state, follows_by_topic[topic]]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
63
98
|
def public?
|
|
64
99
|
true
|
|
65
100
|
end
|
|
66
101
|
|
|
102
|
+
def user_detail
|
|
103
|
+
super || build_user_detail
|
|
104
|
+
end
|
|
105
|
+
|
|
67
106
|
def should_generate_new_friendly_id?
|
|
68
107
|
title_changed?
|
|
69
108
|
end
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Thredded
|
|
3
3
|
class UserDetail < ActiveRecord::Base
|
|
4
|
+
include ModerationState
|
|
5
|
+
|
|
4
6
|
belongs_to :user, class_name: Thredded.user_class, inverse_of: :thredded_user_detail
|
|
5
7
|
validates :user_id, presence: true
|
|
6
8
|
|
|
7
9
|
has_many :topics, class_name: 'Thredded::Topic', foreign_key: :user_id, primary_key: :user_id
|
|
10
|
+
has_many :private_topics, class_name: 'Thredded::PrivateTopic', foreign_key: :user_id, primary_key: :user_id
|
|
8
11
|
has_many :posts, class_name: 'Thredded::Post', foreign_key: :user_id, primary_key: :user_id
|
|
9
12
|
has_many :private_posts, class_name: 'Thredded::PrivatePost', foreign_key: :user_id, primary_key: :user_id
|
|
10
13
|
|
|
11
14
|
scope :recently_active, -> { where(arel_table[:last_seen_at].gt(Thredded.active_user_threshold.ago)) }
|
|
15
|
+
|
|
16
|
+
before_save :set_moderation_state_changed_at
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def set_moderation_state_changed_at
|
|
21
|
+
self.moderation_state_changed_at = Time.current if moderation_state_changed?
|
|
22
|
+
end
|
|
12
23
|
end
|
|
13
24
|
end
|
|
@@ -27,6 +27,7 @@ module Thredded
|
|
|
27
27
|
opt.has_many :thredded_private_users, class_name: 'Thredded::PrivateUser'
|
|
28
28
|
opt.has_many :thredded_topic_read_states, class_name: 'Thredded::UserTopicReadState'
|
|
29
29
|
opt.has_many :thredded_private_topic_read_states, class_name: 'Thredded::UserPrivateTopicReadState'
|
|
30
|
+
opt.has_many :thredded_topic_follows, class_name: 'Thredded::UserTopicFollow'
|
|
30
31
|
opt.has_one :thredded_user_detail, class_name: 'Thredded::UserDetail'
|
|
31
32
|
opt.has_one :thredded_user_preference, class_name: 'Thredded::UserPreference'
|
|
32
33
|
end
|
|
@@ -35,14 +36,27 @@ module Thredded
|
|
|
35
36
|
through: :thredded_private_users,
|
|
36
37
|
class_name: 'Thredded::PrivateTopic',
|
|
37
38
|
source: :private_topic
|
|
39
|
+
|
|
40
|
+
with_options dependent: :nullify, class_name: 'Thredded::PostModerationRecord' do |opt|
|
|
41
|
+
opt.has_many :thredded_post_moderation_records, foreign_key: 'post_user_id', inverse_of: :post_user
|
|
42
|
+
opt.has_many :thredded_post_moderated_records, foreign_key: 'moderator_id', inverse_of: :moderator
|
|
43
|
+
end
|
|
38
44
|
end
|
|
39
45
|
|
|
40
46
|
def thredded_user_preference
|
|
41
47
|
super || build_thredded_user_preference
|
|
42
48
|
end
|
|
43
49
|
|
|
50
|
+
def thredded_user_detail
|
|
51
|
+
super || build_thredded_user_detail
|
|
52
|
+
end
|
|
53
|
+
|
|
44
54
|
def thredded_anonymous?
|
|
45
55
|
false
|
|
46
56
|
end
|
|
57
|
+
|
|
58
|
+
def following?(topic)
|
|
59
|
+
UserTopicFollow.find_by(topic_id: topic.id, user: self)
|
|
60
|
+
end
|
|
47
61
|
end
|
|
48
62
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Thredded
|
|
3
|
+
class UserTopicFollow < ActiveRecord::Base
|
|
4
|
+
enum reason: [:manual, :posted, :mentioned]
|
|
5
|
+
|
|
6
|
+
belongs_to :user, inverse_of: :thredded_topic_follows
|
|
7
|
+
belongs_to :topic, inverse_of: :user_follows
|
|
8
|
+
|
|
9
|
+
validates :user_id, presence: true
|
|
10
|
+
validates :topic_id, presence: true
|
|
11
|
+
|
|
12
|
+
# shim to behave like postable-related (though actually only ever related to topic)
|
|
13
|
+
alias_attribute :postable_id, :topic_id
|
|
14
|
+
alias_attribute :postable, :topic
|
|
15
|
+
|
|
16
|
+
def self.create_unless_exists(user_id, topic_id, reason = :manual)
|
|
17
|
+
create_with(reason: reason).find_or_create_by(user_id: user_id, topic_id: topic_id)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Thredded
|
|
3
3
|
class MessageboardPolicy
|
|
4
|
+
# The scope of readable messageboards
|
|
5
|
+
class Scope
|
|
6
|
+
# @param user [Thredded.user_class]
|
|
7
|
+
# @param scope [ActiveRecord::Relation<Thredded::Messageboard>]
|
|
8
|
+
def initialize(user, scope)
|
|
9
|
+
@user = user
|
|
10
|
+
@scope = scope
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [ActiveRecord::Relation<Thredded::Messageboards>]
|
|
14
|
+
def resolve
|
|
15
|
+
@scope.merge(@user.thredded_can_read_messageboards)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
4
19
|
# @param user [Thredded.user_class]
|
|
5
20
|
# @param messageboard [Thredded::Messageboard]
|
|
6
21
|
def initialize(user, messageboard)
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
require_dependency 'thredded/topic_policy'
|
|
3
3
|
module Thredded
|
|
4
4
|
class PostPolicy
|
|
5
|
+
# The scope of readable posts.
|
|
6
|
+
# MessageboardPolicy must be applied separately.
|
|
7
|
+
class Scope
|
|
8
|
+
# @param user [Thredded.user_class]
|
|
9
|
+
# @param scope [ActiveRecord::Relation<Thredded::Post>]
|
|
10
|
+
def initialize(user, scope)
|
|
11
|
+
@user = user
|
|
12
|
+
@scope = scope
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [ActiveRecord::Relation<Thredded::Post>]
|
|
16
|
+
def resolve
|
|
17
|
+
@scope.moderation_state_visible_to_user(@user)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
5
21
|
# @param user [Thredded.user_class]
|
|
6
22
|
# @param post [Thredded::Post]
|
|
7
23
|
def initialize(user, post)
|
|
@@ -14,7 +30,7 @@ module Thredded
|
|
|
14
30
|
end
|
|
15
31
|
|
|
16
32
|
def read?
|
|
17
|
-
TopicPolicy.new(@user, @post.postable).read?
|
|
33
|
+
TopicPolicy.new(@user, @post.postable).read? && @post.moderation_state_visible_to_user?(@user)
|
|
18
34
|
end
|
|
19
35
|
|
|
20
36
|
def update?
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require_dependency 'thredded/messageboard_policy'
|
|
2
3
|
module Thredded
|
|
3
4
|
class TopicPolicy
|
|
5
|
+
# The scope of readable topics.
|
|
6
|
+
# MessageboardPolicy must be applied separately.
|
|
7
|
+
class Scope
|
|
8
|
+
# @param user [Thredded.user_class]
|
|
9
|
+
# @param scope [ActiveRecord::Relation<Thredded::Topic>]
|
|
10
|
+
def initialize(user, scope)
|
|
11
|
+
@user = user
|
|
12
|
+
@scope = scope
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [ActiveRecord::Relation<Thredded::Topic>]
|
|
16
|
+
def resolve
|
|
17
|
+
@scope.moderation_state_visible_to_user(@user)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
4
21
|
# @param user [Thredded.user_class]
|
|
5
22
|
# @param topic [Thredded::Topic]
|
|
6
23
|
def initialize(user, topic)
|
|
@@ -14,7 +31,7 @@ module Thredded
|
|
|
14
31
|
end
|
|
15
32
|
|
|
16
33
|
def read?
|
|
17
|
-
@messageboard_user_permission.read?
|
|
34
|
+
@messageboard_user_permission.read? && @topic.moderation_state_visible_to_user?(@user)
|
|
18
35
|
end
|
|
19
36
|
|
|
20
37
|
def update?
|
|
@@ -39,18 +39,5 @@ module Thredded
|
|
|
39
39
|
def path
|
|
40
40
|
Thredded::UrlsHelper.topic_path(@topic, page: @read_state.page)
|
|
41
41
|
end
|
|
42
|
-
|
|
43
|
-
def self.inherited(subclass)
|
|
44
|
-
subclass.extend ClassMethods
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
module ClassMethods
|
|
48
|
-
def from_user(topic, user)
|
|
49
|
-
read_state = if user && !user.thredded_anonymous?
|
|
50
|
-
topic.association(:user_read_states).klass.find_by(user_id: user.id, postable_id: topic.id)
|
|
51
|
-
end
|
|
52
|
-
new(topic, read_state, Pundit.policy!(user, topic))
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
42
|
end
|
|
56
43
|
end
|
|
@@ -8,6 +8,9 @@ module Thredded
|
|
|
8
8
|
:created_at,
|
|
9
9
|
:user,
|
|
10
10
|
:to_model,
|
|
11
|
+
:pending_moderation?,
|
|
12
|
+
:approved?,
|
|
13
|
+
:blocked?,
|
|
11
14
|
to: :@post
|
|
12
15
|
|
|
13
16
|
# @param post [Thredded::PostCommon]
|
|
@@ -38,7 +41,11 @@ module Thredded
|
|
|
38
41
|
I18n.locale,
|
|
39
42
|
@post,
|
|
40
43
|
@post.user,
|
|
41
|
-
[
|
|
44
|
+
[
|
|
45
|
+
!@post.private_topic_post? && @post.pending_moderation? && !Thredded.content_visible_while_pending_moderation,
|
|
46
|
+
can_update?,
|
|
47
|
+
can_destroy?
|
|
48
|
+
].map { |p| p ? '+' : '-' } * ''
|
|
42
49
|
]
|
|
43
50
|
end
|
|
44
51
|
end
|
|
@@ -6,22 +6,20 @@ module Thredded
|
|
|
6
6
|
# A view model for a page of PostViews.
|
|
7
7
|
class PostsPageView
|
|
8
8
|
delegate :to_ary,
|
|
9
|
-
to: :@
|
|
9
|
+
to: :@post_views
|
|
10
10
|
delegate :total_pages,
|
|
11
11
|
:current_page,
|
|
12
12
|
:limit_value,
|
|
13
|
-
to: :@
|
|
13
|
+
to: :@paginated_scope
|
|
14
14
|
|
|
15
15
|
# @return [Thredded::BaseTopicView]
|
|
16
16
|
attr_reader :topic
|
|
17
17
|
|
|
18
18
|
# @param user [Thredded.user_class] the user who is viewing the posts page
|
|
19
|
-
# @param
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@
|
|
23
|
-
@topic_views = posts_page_scope.map { |post| PostView.new(post, Pundit.policy!(user, post)) }
|
|
24
|
-
@topic = "#{posts_page_scope.reflect_on_association(:postable).klass}View".constantize.from_user(topic, user)
|
|
19
|
+
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>]
|
|
20
|
+
def initialize(user, paginated_scope)
|
|
21
|
+
@paginated_scope = paginated_scope
|
|
22
|
+
@post_views = paginated_scope.map { |post| PostView.new(post, Pundit.policy!(user, post)) }
|
|
25
23
|
end
|
|
26
24
|
end
|
|
27
25
|
end
|
|
@@ -5,5 +5,13 @@ module Thredded
|
|
|
5
5
|
def edit_path
|
|
6
6
|
Thredded::UrlsHelper.edit_private_topic_path(@topic)
|
|
7
7
|
end
|
|
8
|
+
|
|
9
|
+
def self.from_user(topic, user)
|
|
10
|
+
read_state = if user && !user.thredded_anonymous?
|
|
11
|
+
UserPrivateTopicReadState
|
|
12
|
+
.find_by(user_id: user.id, postable_id: topic.id)
|
|
13
|
+
end
|
|
14
|
+
new(topic, read_state, Pundit.policy!(user, topic))
|
|
15
|
+
end
|
|
8
16
|
end
|
|
9
17
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_dependency 'thredded/private_topic_view'
|
|
3
|
+
module Thredded
|
|
4
|
+
# A view model for a page of BaseTopicViews.
|
|
5
|
+
class PrivateTopicsPageView
|
|
6
|
+
delegate :to_ary,
|
|
7
|
+
:blank?,
|
|
8
|
+
:empty?,
|
|
9
|
+
to: :@topic_views
|
|
10
|
+
delegate :total_pages,
|
|
11
|
+
:current_page,
|
|
12
|
+
:limit_value,
|
|
13
|
+
to: :@topics_page_scope
|
|
14
|
+
|
|
15
|
+
# @param user [Thredded.user_class] the user who is viewing the posts page
|
|
16
|
+
# @param topics_page_scope [ActiveRecord::Relation<Thredded::Topic>]
|
|
17
|
+
def initialize(user, topics_page_scope)
|
|
18
|
+
@topics_page_scope = topics_page_scope
|
|
19
|
+
@topic_views = @topics_page_scope.with_read_states(user).map do |(topic, read_state)|
|
|
20
|
+
PrivateTopicView.new(topic, read_state, Pundit.policy!(user, topic))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_dependency 'thredded/posts_page_view'
|
|
3
|
+
module Thredded
|
|
4
|
+
# A view model for a page of PostViews of a Topic.
|
|
5
|
+
class TopicPostsPageView < PostsPageView
|
|
6
|
+
# @return [Thredded::BaseTopicView]
|
|
7
|
+
attr_reader :topic
|
|
8
|
+
|
|
9
|
+
# @param user [Thredded.user_class] the user who is viewing the posts page
|
|
10
|
+
# @param topic [Thredded::TopicCommon]
|
|
11
|
+
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>]
|
|
12
|
+
def initialize(user, topic, paginated_scope)
|
|
13
|
+
super(user, paginated_scope)
|
|
14
|
+
@topic = "#{paginated_scope.reflect_on_association(:postable).klass}View".constantize.from_user(topic, user)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -2,13 +2,31 @@
|
|
|
2
2
|
module Thredded
|
|
3
3
|
# A view model for Topic.
|
|
4
4
|
class TopicView < BaseTopicView
|
|
5
|
-
delegate :categories,
|
|
5
|
+
delegate :categories, :id,
|
|
6
6
|
to: :@topic
|
|
7
7
|
|
|
8
|
+
# @param topic [TopicCommon]
|
|
9
|
+
# @param read_state [UserTopicReadStateCommon, nil]
|
|
10
|
+
# @param policy [#destroy?]
|
|
11
|
+
def initialize(topic, read_state, follow, policy)
|
|
12
|
+
super(topic, read_state, policy)
|
|
13
|
+
@follow = follow
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.from_user(topic, user)
|
|
17
|
+
read_state = follow = nil
|
|
18
|
+
if user && !user.thredded_anonymous?
|
|
19
|
+
read_state = UserTopicReadState.find_by(user_id: user.id, postable_id: topic.id)
|
|
20
|
+
follow = UserTopicFollow.find_by(user_id: user.id, topic_id: topic.id)
|
|
21
|
+
end
|
|
22
|
+
new(topic, read_state, follow, Pundit.policy!(user, topic))
|
|
23
|
+
end
|
|
24
|
+
|
|
8
25
|
def states
|
|
9
26
|
super + [
|
|
10
27
|
(:locked if @topic.locked?),
|
|
11
28
|
(:sticky if @topic.sticky?),
|
|
29
|
+
(@follow ? :following : :notfollowing)
|
|
12
30
|
].compact
|
|
13
31
|
end
|
|
14
32
|
|
|
@@ -19,5 +37,13 @@ module Thredded
|
|
|
19
37
|
def destroy_path
|
|
20
38
|
Thredded::UrlsHelper.messageboard_topic_path(@topic.messageboard, @topic)
|
|
21
39
|
end
|
|
40
|
+
|
|
41
|
+
def follow_path
|
|
42
|
+
Thredded::UrlsHelper.follow_messageboard_topic_path(@topic.messageboard, @topic)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def unfollow_path
|
|
46
|
+
Thredded::UrlsHelper.unfollow_messageboard_topic_path(@topic.messageboard, @topic)
|
|
47
|
+
end
|
|
22
48
|
end
|
|
23
49
|
end
|