thredded 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.mkdn +26 -0
  3. data/README.mkdn +52 -7
  4. data/app/assets/images/thredded/moderation.svg +4 -0
  5. data/app/assets/images/thredded/private-messages.svg +1 -1
  6. data/app/assets/images/thredded/settings.svg +1 -1
  7. data/app/assets/stylesheets/thredded/_base.scss +1 -1
  8. data/app/assets/stylesheets/thredded/_thredded.scss +1 -0
  9. data/app/assets/stylesheets/thredded/base/_buttons.scss +16 -0
  10. data/app/assets/stylesheets/thredded/base/_grid.scss +12 -0
  11. data/app/assets/stylesheets/thredded/components/_base.scss +4 -0
  12. data/app/assets/stylesheets/thredded/components/_messageboard.scss +1 -13
  13. data/app/assets/stylesheets/thredded/components/_topic-header.scss +27 -0
  14. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +1 -1
  15. data/app/assets/stylesheets/thredded/layout/_moderation.scss +45 -0
  16. data/app/assets/stylesheets/thredded/layout/_navigation.scss +20 -6
  17. data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +2 -2
  18. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +5 -3
  19. data/app/commands/thredded/autofollow_mentioned_users.rb +32 -0
  20. data/app/commands/thredded/moderate_post.rb +35 -0
  21. data/app/commands/thredded/notify_following_users.rb +18 -0
  22. data/app/commands/thredded/notify_private_topic_users.rb +4 -4
  23. data/app/controllers/thredded/application_controller.rb +6 -25
  24. data/app/controllers/thredded/messageboards_controller.rb +5 -3
  25. data/app/controllers/thredded/moderation_controller.rb +56 -0
  26. data/app/controllers/thredded/post_permalinks_controller.rb +1 -1
  27. data/app/controllers/thredded/posts_controller.rb +4 -2
  28. data/app/controllers/thredded/private_post_permalinks_controller.rb +1 -1
  29. data/app/controllers/thredded/private_topics_controller.rb +2 -3
  30. data/app/controllers/thredded/theme_previews_controller.rb +3 -3
  31. data/app/controllers/thredded/topics_controller.rb +32 -11
  32. data/app/forms/thredded/topic_form.rb +1 -0
  33. data/app/helpers/thredded/application_helper.rb +26 -1
  34. data/app/helpers/thredded/urls_helper.rb +7 -5
  35. data/app/jobs/thredded/auto_follow_and_notify_job.rb +13 -0
  36. data/app/jobs/thredded/notify_private_topic_users_job.rb +3 -4
  37. data/app/mailer_previews/thredded/post_mailer_preview.rb +2 -2
  38. data/app/mailers/thredded/post_mailer.rb +2 -2
  39. data/app/models/concerns/thredded/content_moderation_state.rb +53 -0
  40. data/app/models/concerns/thredded/moderation_state.rb +13 -0
  41. data/app/models/concerns/thredded/post_common.rb +6 -71
  42. data/app/models/concerns/thredded/topic_common.rb +26 -11
  43. data/app/models/concerns/thredded/user_topic_read_state_common.rb +4 -0
  44. data/app/models/thredded/messageboard.rb +2 -0
  45. data/app/models/thredded/post.rb +24 -0
  46. data/app/models/thredded/post_moderation_record.rb +45 -0
  47. data/app/models/thredded/private_post.rb +15 -0
  48. data/app/models/thredded/private_topic.rb +8 -0
  49. data/app/models/thredded/topic.rb +39 -0
  50. data/app/models/thredded/user_detail.rb +11 -0
  51. data/app/models/thredded/user_extender.rb +14 -0
  52. data/app/models/thredded/user_topic_follow.rb +20 -0
  53. data/app/policies/thredded/messageboard_policy.rb +15 -0
  54. data/app/policies/thredded/post_policy.rb +17 -1
  55. data/app/policies/thredded/private_post_policy.rb +1 -1
  56. data/app/policies/thredded/private_topic_policy.rb +1 -1
  57. data/app/policies/thredded/topic_policy.rb +18 -1
  58. data/app/view_models/thredded/base_topic_view.rb +0 -13
  59. data/app/view_models/thredded/post_view.rb +8 -1
  60. data/app/view_models/thredded/posts_page_view.rb +6 -8
  61. data/app/view_models/thredded/private_topic_view.rb +8 -0
  62. data/app/view_models/thredded/private_topics_page_view.rb +24 -0
  63. data/app/view_models/thredded/topic_posts_page_view.rb +17 -0
  64. data/app/view_models/thredded/topic_view.rb +27 -1
  65. data/app/view_models/thredded/topics_page_view.rb +2 -4
  66. data/app/views/thredded/moderation/_post.html.erb +7 -0
  67. data/app/views/thredded/moderation/_post_moderation_actions.html.erb +12 -0
  68. data/app/views/thredded/moderation/_post_moderation_record.html.erb +43 -0
  69. data/app/views/thredded/moderation/history.html.erb +19 -0
  70. data/app/views/thredded/moderation/pending.html.erb +29 -0
  71. data/app/views/thredded/post_mailer/{at_notification.html.erb → post_notification.html.erb} +1 -1
  72. data/app/views/thredded/post_mailer/{at_notification.text.erb → post_notification.text.erb} +1 -1
  73. data/app/views/thredded/posts/_post.html.erb +8 -1
  74. data/app/views/thredded/posts_common/_actions.html.erb +11 -0
  75. data/app/views/thredded/posts_common/_content.html.erb +5 -0
  76. data/app/views/thredded/posts_common/_header.html.erb +5 -0
  77. data/app/views/thredded/private_posts/_private_post.html.erb +5 -1
  78. data/app/views/thredded/shared/_nav.html.erb +1 -0
  79. data/app/views/thredded/shared/_page.html.erb +1 -1
  80. data/app/views/thredded/shared/nav/_moderation.html.erb +13 -0
  81. data/app/views/thredded/shared/nav/_private_topics.html.erb +1 -2
  82. data/app/views/thredded/topics/_header.html.erb +15 -0
  83. data/app/views/thredded/topics/index.html.erb +2 -2
  84. data/app/views/thredded/topics/new.html.erb +1 -1
  85. data/config/locales/en.yml +26 -5
  86. data/config/locales/pt-BR.yml +23 -0
  87. data/config/routes.rb +7 -0
  88. data/db/migrate/20160329231848_create_thredded.rb +40 -5
  89. data/db/seeds.rb +5 -5
  90. data/db/upgrade_migrations/20160429222452_upgrade_v0_3_to_v0_4.rb +1 -2
  91. data/db/upgrade_migrations/20160501151908_upgrade_v0_4_to_v0_5.rb +56 -0
  92. data/heroku.gemfile.lock +20 -18
  93. data/lib/generators/thredded/install/templates/initializer.rb +15 -0
  94. data/lib/html/pipeline/at_mention_filter.rb +5 -2
  95. data/lib/thredded.rb +4 -0
  96. data/lib/thredded/at_users.rb +3 -2
  97. data/lib/thredded/content_formatter.rb +81 -0
  98. data/lib/thredded/version.rb +1 -1
  99. metadata +28 -10
  100. data/app/commands/thredded/notify_mentioned_users.rb +0 -55
  101. data/app/jobs/thredded/at_notifier_job.rb +0 -12
  102. data/app/mailer_previews/thredded/private_post_mailer_preview.rb +0 -12
  103. data/app/mailers/thredded/private_post_mailer.rb +0 -17
  104. data/app/views/thredded/posts_common/_post.html.erb +0 -26
  105. 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(private_topic)
5
- @post = private_topic.posts.order_oldest_first.first
6
- @private_topic = 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 - [private_topic.user]
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
- return if policy(obj).read?
81
-
82
- class_name = obj.class.to_s
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
- return if policy(obj).create?
90
-
91
- class_name = obj.class.to_s
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 = thredded_current_user
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 :new
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
@@ -4,7 +4,7 @@ module Thredded
4
4
  def show
5
5
  post = Post.find(params[:id])
6
6
  authorize post, :read?
7
- redirect_to post_url(post), status: :found
7
+ redirect_to post_url(post, user: thredded_current_user), status: :found
8
8
  end
9
9
  end
10
10
  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
@@ -5,7 +5,7 @@ module Thredded
5
5
  def show
6
6
  private_post = PrivatePost.find(params[:id])
7
7
  authorize private_post, :read?
8
- redirect_to post_url(private_post), status: :found
8
+ redirect_to post_url(private_post, user: thredded_current_user), status: :found
9
9
  end
10
10
  end
11
11
  end
@@ -6,7 +6,7 @@ module Thredded
6
6
  before_action :thredded_require_login!
7
7
 
8
8
  def index
9
- @private_topics = Thredded::TopicsPageView.new(
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::PostsPageView.new(thredded_current_user, private_topic, page_scope)
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 = TopicsPageView.new(@user, @user.thredded_private_topics.page(1).limit(3))
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 = PostsPageView.new(@user, topic, topic.posts.page(1).limit(3))
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 = PostsPageView.new(@user, private_topic, private_topic.posts.page(1).limit(3))
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: [:edit, :new, :update, :create, :destroy]
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::PostsPageView.new(thredded_current_user, topic, page_scope)
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 = if messageboard_or_nil
41
- messageboard.topics
42
- else
43
- Topic.where(messageboard_id: thredded_current_user.thredded_can_read_messageboards.pluck(:id))
44
- end
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
@@ -36,6 +36,7 @@ module Thredded
36
36
  ActiveRecord::Base.transaction do
37
37
  topic.save!
38
38
  post.save!
39
+ UserTopicReadState.read_on_first_post!(user, topic) if topic.previous_changes.include?(:id)
39
40
  end
40
41
  true
41
42
  end
@@ -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, lang: I18n.locale.to_s.downcase, format: :short, nojs: true
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