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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Thredded
|
|
3
|
+
class AutofollowMentionedUsers
|
|
4
|
+
def initialize(post)
|
|
5
|
+
@post = post
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
autofollowers.each do |user|
|
|
10
|
+
Thredded::UserTopicFollow.create_unless_exists(user.id, post.postable_id, :mentioned)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def autofollowers
|
|
15
|
+
user_names = Thredded::AtNotificationExtractor.new(post.content).run
|
|
16
|
+
autofollowers = post.readers_from_user_names(user_names).to_a
|
|
17
|
+
autofollowers.delete post.user
|
|
18
|
+
exclude_those_opting_out_of_at_notifications(autofollowers)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
attr_reader :post
|
|
24
|
+
|
|
25
|
+
def exclude_those_opting_out_of_at_notifications(members)
|
|
26
|
+
members.select do |member|
|
|
27
|
+
member.thredded_user_preference.notify_on_mention? &&
|
|
28
|
+
member.thredded_user_messageboard_preferences.in(post.messageboard).notify_on_mention?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Thredded
|
|
3
|
+
module ModeratePost
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
# @param [Post] post
|
|
7
|
+
# @param [Symbol] moderation_state
|
|
8
|
+
# @param [Thredded.user_class] moderator
|
|
9
|
+
# @return [Thredded::PostModerationRecord]
|
|
10
|
+
def run!(post:, moderation_state:, moderator:)
|
|
11
|
+
Thredded::Post.transaction do
|
|
12
|
+
post_moderation_record = Thredded::PostModerationRecord.record!(
|
|
13
|
+
moderator: moderator,
|
|
14
|
+
post: post,
|
|
15
|
+
previous_moderation_state: post.moderation_state,
|
|
16
|
+
moderation_state: moderation_state,
|
|
17
|
+
)
|
|
18
|
+
if post.user_detail.pending_moderation?
|
|
19
|
+
post.user_detail.update!(moderation_state: moderation_state)
|
|
20
|
+
end
|
|
21
|
+
if post.postable.first_post == post
|
|
22
|
+
post.postable.update!(moderation_state: moderation_state)
|
|
23
|
+
if moderation_state == :blocked
|
|
24
|
+
# When blocking the first post of a topic, also block all the other posts in the topic by this user.
|
|
25
|
+
post.postable.posts.where(user_id: post.user.id).where.not(id: post.id).each do |a_post|
|
|
26
|
+
a_post.update!(moderation_state: moderation_state)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
post.update!(moderation_state: moderation_state)
|
|
31
|
+
post_moderation_record
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Thredded
|
|
3
|
+
class NotifyFollowingUsers
|
|
4
|
+
def initialize(post)
|
|
5
|
+
@post = post
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
return if targeted_users.empty?
|
|
10
|
+
PostMailer.post_notification(@post.id, targeted_users.map(&:email)).deliver_now
|
|
11
|
+
MembersMarkedNotified.new(@post, targeted_users).run
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def targeted_users
|
|
15
|
+
@targeted_users ||= @post.postable.following_users.reject { |u| u == @post.user }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Thredded
|
|
3
3
|
class NotifyPrivateTopicUsers
|
|
4
|
-
def initialize(
|
|
5
|
-
@post =
|
|
6
|
-
@private_topic =
|
|
4
|
+
def initialize(private_post)
|
|
5
|
+
@post = private_post
|
|
6
|
+
@private_topic = private_post.postable
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def run
|
|
@@ -18,7 +18,7 @@ module Thredded
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def private_topic_recipients
|
|
21
|
-
members = private_topic.users - [
|
|
21
|
+
members = private_topic.users - [post.user]
|
|
22
22
|
members = exclude_those_opting_out_of_message_notifications(members)
|
|
23
23
|
members = exclude_previously_notified(members)
|
|
24
24
|
members
|
|
@@ -12,7 +12,6 @@ module Thredded
|
|
|
12
12
|
:messageboard,
|
|
13
13
|
:messageboard_or_nil,
|
|
14
14
|
:preferences,
|
|
15
|
-
:unread_private_topics_count,
|
|
16
15
|
:signed_in?
|
|
17
16
|
|
|
18
17
|
rescue_from Thredded::Errors::MessageboardNotFound,
|
|
@@ -64,34 +63,16 @@ module Thredded
|
|
|
64
63
|
Thredded.layout
|
|
65
64
|
end
|
|
66
65
|
|
|
67
|
-
def unread_private_topics_count
|
|
68
|
-
@unread_private_topics_count ||=
|
|
69
|
-
if signed_in?
|
|
70
|
-
Thredded::PrivateTopic
|
|
71
|
-
.for_user(thredded_current_user)
|
|
72
|
-
.unread(thredded_current_user)
|
|
73
|
-
.count
|
|
74
|
-
else
|
|
75
|
-
0
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
66
|
def authorize_reading(obj)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
error = class_name.gsub(/Thredded::/, 'Thredded::Errors::') + 'ReadDenied'
|
|
84
|
-
|
|
85
|
-
fail error.constantize
|
|
67
|
+
authorize obj, :read?
|
|
68
|
+
rescue Pundit::NotAuthorizedError
|
|
69
|
+
raise "#{obj.class.to_s.sub(/Thredded::/, 'Thredded::Errors::')}ReadDenied".constantize
|
|
86
70
|
end
|
|
87
71
|
|
|
88
72
|
def authorize_creating(obj)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
error = class_name.gsub(/Thredded::/, 'Thredded::Errors::') + 'CreateDenied'
|
|
93
|
-
|
|
94
|
-
fail error.constantize
|
|
73
|
+
authorize obj, :create?
|
|
74
|
+
rescue Pundit::NotAuthorizedError
|
|
75
|
+
raise "#{obj.class.to_s.sub(/Thredded::/, 'Thredded::Errors::')}CreateDenied".constantize
|
|
95
76
|
end
|
|
96
77
|
|
|
97
78
|
def update_user_activity
|
|
@@ -3,9 +3,11 @@ module Thredded
|
|
|
3
3
|
class MessageboardsController < Thredded::ApplicationController
|
|
4
4
|
before_action :thredded_require_login!, only: [:new, :create, :edit, :update]
|
|
5
5
|
|
|
6
|
+
after_action :verify_authorized, except: %i(index)
|
|
7
|
+
after_action :verify_policy_scoped, except: %i(new create edit update)
|
|
8
|
+
|
|
6
9
|
def index
|
|
7
|
-
@groups =
|
|
8
|
-
.thredded_can_read_messageboards
|
|
10
|
+
@groups = policy_scope(Messageboard.all)
|
|
9
11
|
.preload(:group).group_by(&:group)
|
|
10
12
|
.map { |(group, messageboards)| MessageboardGroupView.new(group, messageboards) }
|
|
11
13
|
end
|
|
@@ -41,7 +43,7 @@ module Thredded
|
|
|
41
43
|
if @messageboard.update(messageboard_params)
|
|
42
44
|
redirect_to messageboard_topics_path(@messageboard), notice: I18n.t('thredded.messageboard.updated_notice')
|
|
43
45
|
else
|
|
44
|
-
render :
|
|
46
|
+
render :edit
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_dependency 'thredded/moderate_post'
|
|
3
|
+
require_dependency 'thredded/posts_page_view'
|
|
4
|
+
module Thredded
|
|
5
|
+
class ModerationController < ApplicationController
|
|
6
|
+
before_action :thredded_require_login!
|
|
7
|
+
before_action :load_moderatable_messageboards
|
|
8
|
+
|
|
9
|
+
def pending
|
|
10
|
+
@posts = PostsPageView.new(
|
|
11
|
+
thredded_current_user,
|
|
12
|
+
moderatable_posts
|
|
13
|
+
.pending_moderation
|
|
14
|
+
.order_oldest_first
|
|
15
|
+
.page(params[:page] || 1)
|
|
16
|
+
)
|
|
17
|
+
if flash[:last_moderated_record_id]
|
|
18
|
+
@last_moderated_record = accessible_moderation_records.find(flash[:last_moderated_record_id].to_i)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def history
|
|
23
|
+
@post_moderation_records = accessible_moderation_records
|
|
24
|
+
.order(created_at: :desc)
|
|
25
|
+
.page(params[:page] || 1)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def moderate_post
|
|
29
|
+
return head(:bad_request) unless Thredded::Post.moderation_states.include?(params[:moderation_state])
|
|
30
|
+
flash[:last_moderated_record_id] = ModeratePost.run!(
|
|
31
|
+
post: moderatable_posts.find(params[:id]),
|
|
32
|
+
moderation_state: params[:moderation_state],
|
|
33
|
+
moderator: thredded_current_user,
|
|
34
|
+
).id
|
|
35
|
+
redirect_back fallback_location: pending_moderation_path
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def moderatable_posts
|
|
41
|
+
Thredded::Post.where(messageboard_id: @moderatable_messageboards)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def accessible_moderation_records
|
|
45
|
+
Thredded::PostModerationRecord
|
|
46
|
+
.where(messageboard_id: @moderatable_messageboards)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def load_moderatable_messageboards
|
|
50
|
+
@moderatable_messageboards = thredded_current_user.thredded_can_moderate_messageboards.to_a
|
|
51
|
+
if @moderatable_messageboards.empty?
|
|
52
|
+
fail Pundit::NotAuthorizedError, 'You are not authorized to perform this action.'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -6,12 +6,14 @@ module Thredded
|
|
|
6
6
|
helper_method :topic
|
|
7
7
|
before_action :update_user_activity
|
|
8
8
|
|
|
9
|
+
after_action :verify_authorized
|
|
10
|
+
|
|
9
11
|
def create
|
|
10
12
|
post = parent_topic.posts.build(post_params)
|
|
11
13
|
authorize_creating post
|
|
12
14
|
post.save!
|
|
13
15
|
|
|
14
|
-
redirect_to post_path(post)
|
|
16
|
+
redirect_to post_path(post, user: thredded_current_user)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def edit
|
|
@@ -22,7 +24,7 @@ module Thredded
|
|
|
22
24
|
authorize post, :update?
|
|
23
25
|
post.update_attributes(post_params.except(:user, :ip))
|
|
24
26
|
|
|
25
|
-
redirect_to post_path(post)
|
|
27
|
+
redirect_to post_path(post, user: thredded_current_user)
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def destroy
|
|
@@ -6,7 +6,7 @@ module Thredded
|
|
|
6
6
|
before_action :thredded_require_login!
|
|
7
7
|
|
|
8
8
|
def index
|
|
9
|
-
@private_topics = Thredded::
|
|
9
|
+
@private_topics = Thredded::PrivateTopicsPageView.new(
|
|
10
10
|
thredded_current_user,
|
|
11
11
|
PrivateTopic
|
|
12
12
|
.distinct
|
|
@@ -29,7 +29,7 @@ module Thredded
|
|
|
29
29
|
.includes(:user)
|
|
30
30
|
.order_oldest_first
|
|
31
31
|
.page(current_page)
|
|
32
|
-
@posts = Thredded::
|
|
32
|
+
@posts = Thredded::TopicPostsPageView.new(thredded_current_user, private_topic, page_scope)
|
|
33
33
|
|
|
34
34
|
if signed_in?
|
|
35
35
|
UserPrivateTopicReadState.touch!(thredded_current_user.id, private_topic.id, page_scope.last, current_page)
|
|
@@ -46,7 +46,6 @@ module Thredded
|
|
|
46
46
|
def create
|
|
47
47
|
@private_topic = PrivateTopicForm.new(new_private_topic_params)
|
|
48
48
|
if @private_topic.save
|
|
49
|
-
NotifyPrivateTopicUsersJob.perform_later(@private_topic.private_topic.id)
|
|
50
49
|
redirect_to @private_topic.private_topic
|
|
51
50
|
else
|
|
52
51
|
render :new
|
|
@@ -11,17 +11,17 @@ module Thredded
|
|
|
11
11
|
end
|
|
12
12
|
@messageboards = Messageboard.where(closed: false)
|
|
13
13
|
@topics = TopicsPageView.new(@user, @messageboard.topics.page(1).limit(3))
|
|
14
|
-
@private_topics =
|
|
14
|
+
@private_topics = PrivateTopicsPageView.new(@user, @user.thredded_private_topics.page(1).limit(3))
|
|
15
15
|
topic = Topic.new(messageboard: @messageboard, title: 'Hello', slug: 'hello', user: @user)
|
|
16
16
|
@topic = TopicView.from_user(topic, @user)
|
|
17
|
-
@posts =
|
|
17
|
+
@posts = TopicPostsPageView.new(@user, topic, topic.posts.page(1).limit(3))
|
|
18
18
|
@post = topic.posts.build(id: 1337, postable: topic, content: 'Hello world', user: @user)
|
|
19
19
|
@new_post = @messageboard.posts.build(postable: topic)
|
|
20
20
|
@new_topic = TopicForm.new(user: @user, messageboard: @messageboard)
|
|
21
21
|
@new_private_topic = PrivateTopicForm.new(user: @user)
|
|
22
22
|
private_topic = PrivateTopic.new(id: 1337, title: 'Hello', user: @user, last_user: @user, users: [@user])
|
|
23
23
|
@private_topic = PrivateTopicView.from_user(private_topic, @user)
|
|
24
|
-
@private_posts =
|
|
24
|
+
@private_posts = TopicPostsPageView.new(@user, private_topic, private_topic.posts.page(1).limit(3))
|
|
25
25
|
@private_post = private_topic.posts.build(
|
|
26
26
|
id: 1337, postable: private_topic, content: 'A private hello world', user: @user
|
|
27
27
|
)
|
|
@@ -4,15 +4,18 @@ require_dependency 'thredded/topics_page_view'
|
|
|
4
4
|
module Thredded
|
|
5
5
|
class TopicsController < Thredded::ApplicationController
|
|
6
6
|
before_action :thredded_require_login!,
|
|
7
|
-
only:
|
|
7
|
+
only: %i(edit new update create destroy follow unfollow)
|
|
8
8
|
after_action :update_user_activity
|
|
9
9
|
|
|
10
|
+
after_action :verify_authorized, except: %i(search)
|
|
11
|
+
after_action :verify_policy_scoped, except: %i(show new create edit update destroy follow unfollow)
|
|
12
|
+
|
|
10
13
|
def index
|
|
11
14
|
authorize_reading messageboard
|
|
12
15
|
|
|
13
16
|
@topics = Thredded::TopicsPageView.new(
|
|
14
17
|
thredded_current_user,
|
|
15
|
-
messageboard.topics
|
|
18
|
+
policy_scope(messageboard.topics)
|
|
16
19
|
.order_sticky_first.order_recently_updated_first
|
|
17
20
|
.includes(:categories, :last_user, :user)
|
|
18
21
|
.page(current_page)
|
|
@@ -24,11 +27,11 @@ module Thredded
|
|
|
24
27
|
|
|
25
28
|
def show
|
|
26
29
|
authorize topic, :read?
|
|
27
|
-
page_scope = topic.posts
|
|
28
|
-
.includes(:user, :messageboard, :postable)
|
|
30
|
+
page_scope = policy_scope(topic.posts)
|
|
29
31
|
.order_oldest_first
|
|
32
|
+
.includes(:user, :messageboard, :postable)
|
|
30
33
|
.page(current_page)
|
|
31
|
-
@posts = Thredded::
|
|
34
|
+
@posts = Thredded::TopicPostsPageView.new(thredded_current_user, topic, page_scope)
|
|
32
35
|
|
|
33
36
|
UserTopicReadState.touch!(thredded_current_user.id, topic.id, page_scope.last, current_page) if signed_in?
|
|
34
37
|
|
|
@@ -36,12 +39,15 @@ module Thredded
|
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
def search
|
|
42
|
+
authorize_reading messageboard if messageboard_or_nil
|
|
39
43
|
@query = params[:q].to_s
|
|
40
|
-
topics_scope =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
topics_scope = policy_scope(
|
|
45
|
+
if messageboard_or_nil
|
|
46
|
+
messageboard.topics
|
|
47
|
+
else
|
|
48
|
+
Topic.where(messageboard_id: policy_scope(Messageboard.all).pluck(:id))
|
|
49
|
+
end
|
|
50
|
+
)
|
|
45
51
|
@topics = Thredded::TopicsPageView.new(
|
|
46
52
|
thredded_current_user,
|
|
47
53
|
topics_scope
|
|
@@ -62,7 +68,7 @@ module Thredded
|
|
|
62
68
|
@category = messageboard.categories.friendly.find(params[:category_id])
|
|
63
69
|
@topics = Thredded::TopicsPageView.new(
|
|
64
70
|
thredded_current_user,
|
|
65
|
-
@category.topics
|
|
71
|
+
policy_scope(@category.topics)
|
|
66
72
|
.unstuck
|
|
67
73
|
.order_recently_updated_first
|
|
68
74
|
.page(current_page)
|
|
@@ -101,6 +107,21 @@ module Thredded
|
|
|
101
107
|
notice: t('thredded.topics.deleted_notice')
|
|
102
108
|
end
|
|
103
109
|
|
|
110
|
+
def follow
|
|
111
|
+
authorize topic, :read?
|
|
112
|
+
UserTopicFollow.create_unless_exists(thredded_current_user.id, topic.id)
|
|
113
|
+
redirect_to messageboard_topic_url(messageboard, topic),
|
|
114
|
+
notice: t('thredded.topics.followed_notice')
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def unfollow
|
|
118
|
+
authorize topic, :read?
|
|
119
|
+
follow = thredded_current_user.following?(topic)
|
|
120
|
+
follow.destroy if follow
|
|
121
|
+
redirect_to messageboard_topic_url(messageboard, topic),
|
|
122
|
+
notice: t('thredded.topics.unfollowed_notice')
|
|
123
|
+
end
|
|
124
|
+
|
|
104
125
|
private
|
|
105
126
|
|
|
106
127
|
def topic
|
|
@@ -20,7 +20,10 @@ module Thredded
|
|
|
20
20
|
# @param datetime [DateTime]
|
|
21
21
|
# @return [String] html_safe datetime presentation
|
|
22
22
|
def time_ago(datetime)
|
|
23
|
-
timeago_tag datetime,
|
|
23
|
+
timeago_tag datetime,
|
|
24
|
+
lang: I18n.locale.to_s.downcase,
|
|
25
|
+
format: -> (t, _opts) { t.year == Time.current.year ? :short : :long },
|
|
26
|
+
nojs: true
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
def paginate(collection, args = {})
|
|
@@ -36,5 +39,27 @@ module Thredded
|
|
|
36
39
|
*('thredded--private-topic' if topic.is_a?(Thredded::PrivateTopicView))
|
|
37
40
|
]
|
|
38
41
|
end
|
|
42
|
+
|
|
43
|
+
def unread_private_topics_count
|
|
44
|
+
@unread_private_topics_count ||=
|
|
45
|
+
if signed_in?
|
|
46
|
+
Thredded::PrivateTopic
|
|
47
|
+
.for_user(thredded_current_user)
|
|
48
|
+
.unread(thredded_current_user)
|
|
49
|
+
.count
|
|
50
|
+
else
|
|
51
|
+
0
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def moderatable_messageboards_ids
|
|
56
|
+
@moderatable_messageboards_ids ||=
|
|
57
|
+
thredded_current_user.thredded_can_moderate_messageboards.pluck(:id)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def posts_pending_moderation_count
|
|
61
|
+
@posts_pending_moderation_count ||=
|
|
62
|
+
Thredded::Post.where(messageboard_id: moderatable_messageboards_ids).pending_moderation.count
|
|
63
|
+
end
|
|
39
64
|
end
|
|
40
65
|
end
|