thredded 0.11.0 → 0.12.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +69 -23
  3. data/app/assets/javascripts/thredded/components/post_form.es6 +4 -4
  4. data/app/assets/javascripts/thredded/components/quote_post.es6 +45 -0
  5. data/app/assets/javascripts/thredded/components/topic_form.es6 +4 -4
  6. data/app/assets/javascripts/thredded/core/on_page_load.es6 +8 -0
  7. data/app/assets/javascripts/thredded/dependencies.js +1 -1
  8. data/app/assets/stylesheets/thredded/_base.scss +1 -0
  9. data/app/assets/stylesheets/thredded/_email.scss +2 -3
  10. data/app/assets/stylesheets/thredded/base/_dropdown-menu.scss +83 -0
  11. data/app/assets/stylesheets/thredded/components/_post.scss +5 -60
  12. data/app/assets/stylesheets/thredded/components/_preferences.scss +17 -4
  13. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +4 -1
  14. data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +31 -6
  15. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +1 -0
  16. data/app/controllers/concerns/thredded/new_post_params.rb +20 -0
  17. data/app/controllers/concerns/thredded/new_private_post_params.rb +20 -0
  18. data/app/controllers/thredded/application_controller.rb +6 -0
  19. data/app/controllers/thredded/posts_controller.rb +28 -13
  20. data/app/controllers/thredded/preferences_controller.rb +1 -0
  21. data/app/controllers/thredded/private_posts_controller.rb +30 -12
  22. data/app/controllers/thredded/private_topics_controller.rb +11 -1
  23. data/app/controllers/thredded/theme_previews_controller.rb +4 -2
  24. data/app/controllers/thredded/topics_controller.rb +36 -3
  25. data/app/forms/thredded/post_form.rb +52 -0
  26. data/app/forms/thredded/private_post_form.rb +48 -0
  27. data/app/forms/thredded/private_topic_form.rb +8 -0
  28. data/app/forms/thredded/topic_form.rb +8 -0
  29. data/app/forms/thredded/user_preferences_form.rb +7 -1
  30. data/app/helpers/thredded/urls_helper.rb +18 -0
  31. data/app/models/thredded/topic.rb +3 -3
  32. data/app/policies/thredded/post_policy.rb +1 -1
  33. data/app/policies/thredded/private_topic_policy.rb +1 -1
  34. data/app/view_hooks/thredded/all_view_hooks.rb +3 -0
  35. data/app/view_models/thredded/messageboard_group_view.rb +1 -1
  36. data/app/view_models/thredded/post_view.rb +19 -3
  37. data/app/view_models/thredded/private_topic_view.rb +0 -4
  38. data/app/view_models/thredded/topic_view.rb +0 -4
  39. data/app/views/thredded/moderation/_users_search_form.html.erb +1 -1
  40. data/app/views/thredded/moderation/user.html.erb +13 -11
  41. data/app/views/thredded/moderation/users.html.erb +1 -0
  42. data/app/views/thredded/posts/_form.html.erb +0 -2
  43. data/app/views/thredded/posts/edit.html.erb +2 -5
  44. data/app/views/thredded/posts/new.html.erb +15 -0
  45. data/app/views/thredded/posts_common/_actions.html.erb +3 -0
  46. data/app/views/thredded/posts_common/_form.html.erb +5 -3
  47. data/app/views/thredded/posts_common/_header.html.erb +3 -1
  48. data/app/views/thredded/posts_common/actions/_quote.html.erb +4 -0
  49. data/app/views/thredded/preferences/_form.html.erb +3 -5
  50. data/app/views/thredded/preferences/_messageboards_nav.html.erb +8 -0
  51. data/app/views/thredded/preferences/_messageboards_nav_item.html.erb +2 -0
  52. data/app/views/thredded/preferences/edit.html.erb +13 -3
  53. data/app/views/thredded/private_posts/_form.html.erb +0 -2
  54. data/app/views/thredded/private_posts/edit.html.erb +2 -4
  55. data/app/views/thredded/private_posts/new.html.erb +11 -0
  56. data/app/views/thredded/private_topics/_form.html.erb +2 -2
  57. data/app/views/thredded/private_topics/index.html.erb +1 -2
  58. data/app/views/thredded/private_topics/new.html.erb +0 -1
  59. data/app/views/thredded/private_topics/show.html.erb +5 -3
  60. data/app/views/thredded/shared/_nav.html.erb +1 -7
  61. data/app/views/thredded/shared/nav/_notification_preferences.html.erb +1 -1
  62. data/app/views/thredded/shared/nav/_standalone.html.erb +4 -4
  63. data/app/views/thredded/shared/nav/_standalone_profile.html.erb +3 -0
  64. data/app/views/thredded/theme_previews/show.html.erb +3 -17
  65. data/app/views/thredded/topics/_form.html.erb +3 -2
  66. data/app/views/thredded/topics/index.html.erb +0 -2
  67. data/app/views/thredded/topics/new.html.erb +0 -2
  68. data/app/views/thredded/topics/search.html.erb +20 -2
  69. data/app/views/thredded/topics/show.html.erb +1 -3
  70. data/config/locales/en.yml +9 -5
  71. data/config/locales/es.yml +10 -6
  72. data/config/locales/pl.yml +9 -5
  73. data/config/locales/pt-BR.yml +9 -5
  74. data/config/locales/ru.yml +18 -10
  75. data/config/routes.rb +2 -0
  76. data/db/migrate/20160329231848_create_thredded.rb +1 -1
  77. data/db/upgrade_migrations/20170420163138_upgrade_thredded_v0_11_to_v0_12.rb +25 -0
  78. data/lib/generators/thredded/install/templates/initializer.rb +4 -4
  79. data/lib/thredded/content_formatter.rb +17 -3
  80. data/lib/thredded/html_pipeline/kramdown_filter.rb +1 -1
  81. data/lib/thredded/version.rb +1 -1
  82. data/lib/thredded.rb +13 -10
  83. data/vendor/assets/javascripts/autosize.js +290 -0
  84. metadata +31 -18
  85. data/app/views/thredded/preferences/_header.html.erb +0 -1
@@ -60,6 +60,12 @@ module Thredded
60
60
  end
61
61
  end
62
62
 
63
+ # @param given [Hash]
64
+ # @return [Boolean] whether the given params are a subset of the controller's {#params}.
65
+ def params_match?(given = {})
66
+ given.all? { |k, v| v == params[k] }
67
+ end
68
+
63
69
  private
64
70
 
65
71
  def thredded_layout
@@ -3,27 +3,39 @@ module Thredded
3
3
  # A controller for managing {Post}s.
4
4
  class PostsController < Thredded::ApplicationController
5
5
  include ActionView::RecordIdentifier
6
+ include Thredded::NewPostParams
6
7
 
7
8
  helper_method :topic
8
9
  after_action :update_user_activity
9
10
 
10
11
  after_action :verify_authorized
11
12
 
12
- def create
13
- post = parent_topic.posts.build(post_params)
14
- authorize_creating post
15
- post.save!
13
+ def new
14
+ @post_form = PostForm.new(user: thredded_current_user, topic: parent_topic, post_params: new_post_params)
15
+ authorize_creating @post_form.post
16
+ end
16
17
 
17
- redirect_to post_path(post, user: thredded_current_user)
18
+ def create
19
+ @post_form = PostForm.new(user: thredded_current_user, topic: parent_topic, post_params: new_post_params)
20
+ authorize_creating @post_form.post
21
+
22
+ if @post_form.save
23
+ redirect_to post_path(@post_form.post, user: thredded_current_user)
24
+ else
25
+ render :new
26
+ end
18
27
  end
19
28
 
20
29
  def edit
21
- authorize post, :update?
30
+ @post_form = PostForm.for_persisted(post)
31
+ authorize @post_form.post, :update?
32
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
33
+ render
22
34
  end
23
35
 
24
36
  def update
25
37
  authorize post, :update?
26
- post.update_attributes(post_params.except(:user, :ip))
38
+ post.update_attributes(new_post_params)
27
39
 
28
40
  redirect_to post_path(post, user: thredded_current_user)
29
41
  end
@@ -43,8 +55,17 @@ module Thredded
43
55
  after_mark_as_unread # customization hook
44
56
  end
45
57
 
58
+ def quote
59
+ authorize_reading post
60
+ render plain: Thredded::ContentFormatter.quote_content(post.content)
61
+ end
62
+
46
63
  private
47
64
 
65
+ def canonical_topic_params
66
+ { messageboard_id: messageboard.slug, topic_id: topic.slug }
67
+ end
68
+
48
69
  def after_mark_as_unread
49
70
  redirect_to messageboard_topics_path(messageboard)
50
71
  end
@@ -53,12 +74,6 @@ module Thredded
53
74
  post.postable
54
75
  end
55
76
 
56
- def post_params
57
- params.require(:post)
58
- .permit(:content)
59
- .merge(user: thredded_current_user, ip: request.remote_ip, messageboard: messageboard)
60
- end
61
-
62
77
  def parent_topic
63
78
  Topic
64
79
  .where(messageboard: messageboard)
@@ -21,6 +21,7 @@ module Thredded
21
21
  @preferences = UserPreferencesForm.new(
22
22
  user: thredded_current_user,
23
23
  messageboard: messageboard_or_nil,
24
+ messageboards: policy_scope(Messageboard.all),
24
25
  params: preferences_params
25
26
  )
26
27
  end
@@ -3,22 +3,37 @@ module Thredded
3
3
  # A controller for managing {PrivatePost}s.
4
4
  class PrivatePostsController < Thredded::ApplicationController
5
5
  include ActionView::RecordIdentifier
6
+ include NewPrivatePostParams
6
7
 
7
8
  helper_method :topic
8
9
  after_action :update_user_activity
9
10
 
10
11
  after_action :verify_authorized
11
12
 
12
- def create
13
- post = parent_topic.posts.build(post_params)
14
- authorize_creating post
15
- post.save!
13
+ def new
14
+ @post_form = PrivatePostForm.new(
15
+ user: thredded_current_user, topic: parent_topic, post_params: new_private_post_params
16
+ )
17
+ authorize_creating @post_form.post
18
+ end
16
19
 
17
- redirect_to post_path(post, user: thredded_current_user)
20
+ def create
21
+ @post_form = PrivatePostForm.new(
22
+ user: thredded_current_user, topic: parent_topic, post_params: new_private_post_params
23
+ )
24
+ authorize_creating @post_form.post
25
+ if @post_form.save
26
+ redirect_to post_path(@post_form.post, user: thredded_current_user)
27
+ else
28
+ render :new
29
+ end
18
30
  end
19
31
 
20
32
  def edit
21
- authorize post, :update?
33
+ @post_form = PrivatePostForm.for_persisted(post)
34
+ authorize @post_form.post, :update?
35
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
36
+ render
22
37
  end
23
38
 
24
39
  def update
@@ -43,8 +58,17 @@ module Thredded
43
58
  after_mark_as_unread # customization hook
44
59
  end
45
60
 
61
+ def quote
62
+ authorize_reading post
63
+ render plain: Thredded::ContentFormatter.quote_content(post.content)
64
+ end
65
+
46
66
  private
47
67
 
68
+ def canonical_topic_params
69
+ { private_topic_id: topic.slug }
70
+ end
71
+
48
72
  def after_mark_as_unread
49
73
  redirect_to private_topics_path
50
74
  end
@@ -53,12 +77,6 @@ module Thredded
53
77
  post.postable
54
78
  end
55
79
 
56
- def post_params
57
- params.require(:post)
58
- .permit(:content)
59
- .merge(user: thredded_current_user, ip: request.remote_ip)
60
- end
61
-
62
80
  def parent_topic
63
81
  PrivateTopic
64
82
  .includes(:private_users)
@@ -2,6 +2,7 @@
2
2
  module Thredded
3
3
  class PrivateTopicsController < Thredded::ApplicationController
4
4
  include Thredded::NewPrivateTopicParams
5
+ include Thredded::NewPrivatePostParams
5
6
 
6
7
  before_action :thredded_require_login!
7
8
 
@@ -22,6 +23,7 @@ module Thredded
22
23
 
23
24
  def show
24
25
  authorize private_topic, :read?
26
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
25
27
 
26
28
  page_scope = private_topic
27
29
  .posts
@@ -36,7 +38,9 @@ module Thredded
36
38
  )
37
39
  end
38
40
 
39
- @post = private_topic.posts.build
41
+ @new_post = Thredded::PrivatePostForm.new(
42
+ user: thredded_current_user, topic: private_topic, post_params: new_private_post_params
43
+ )
40
44
  end
41
45
 
42
46
  def new
@@ -55,6 +59,8 @@ module Thredded
55
59
 
56
60
  def edit
57
61
  authorize private_topic, :update?
62
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
63
+ render
58
64
  end
59
65
 
60
66
  def update
@@ -69,6 +75,10 @@ module Thredded
69
75
 
70
76
  private
71
77
 
78
+ def canonical_topic_params
79
+ { id: private_topic.slug }
80
+ end
81
+
72
82
  def current_page
73
83
  (params[:page] || 1).to_i
74
84
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Thredded
3
3
  class ThemePreviewsController < Thredded::ApplicationController
4
- def show
4
+ def show # rubocop:disable Metrics/MethodLength
5
5
  @messageboard = Messageboard.first
6
6
  fail Thredded::Errors::DatabaseEmpty unless @messageboard
7
7
  @user = if thredded_current_user.thredded_anonymous?
@@ -16,7 +16,8 @@ module Thredded
16
16
  @topic = TopicView.from_user(topic, @user)
17
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
- @new_post = @messageboard.posts.build(postable: topic)
19
+ @post_form = PostForm.for_persisted(@post)
20
+ @new_post = PostForm.new(user: @user, topic: topic)
20
21
  @new_topic = TopicForm.new(user: @user, messageboard: @messageboard)
21
22
  @new_private_topic = PrivateTopicForm.new(user: @user)
22
23
  private_topic = PrivateTopic.new(id: 1337, title: 'Hello', user: @user, last_user: @user, users: [@user])
@@ -25,6 +26,7 @@ module Thredded
25
26
  @private_post = private_topic.posts.build(
26
27
  id: 1337, postable: private_topic, content: 'A private hello world', user: @user
27
28
  )
29
+ @private_post_form = PrivatePostForm.for_persisted(@private_post)
28
30
  @preferences = UserPreferencesForm.new(user: @user, messageboard: @messageboard)
29
31
  end
30
32
  end
@@ -2,9 +2,14 @@
2
2
  module Thredded
3
3
  class TopicsController < Thredded::ApplicationController # rubocop:disable Metrics/ClassLength
4
4
  include Thredded::NewTopicParams
5
+ include Thredded::NewPostParams
5
6
 
6
7
  before_action :thredded_require_login!,
7
8
  only: %i(edit new update create destroy follow unfollow)
9
+
10
+ before_action :use_topic_messageboard,
11
+ only: %i(show edit update destroy follow unfollow)
12
+
8
13
  after_action :update_user_activity
9
14
 
10
15
  after_action :verify_authorized, except: %i(search)
@@ -12,6 +17,10 @@ module Thredded
12
17
 
13
18
  def index
14
19
  authorize_reading messageboard
20
+ unless params_match?(canonical_messageboard_params)
21
+ skip_policy_scope
22
+ return redirect_to(canonical_messageboard_params)
23
+ end
15
24
 
16
25
  @topics = Thredded::TopicsPageView.new(
17
26
  thredded_current_user,
@@ -26,6 +35,7 @@ module Thredded
26
35
 
27
36
  def show
28
37
  authorize topic, :read?
38
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
29
39
  page_scope = policy_scope(topic.posts)
30
40
  .order_oldest_first
31
41
  .includes(:user, :messageboard, :postable)
@@ -38,12 +48,18 @@ module Thredded
38
48
  )
39
49
  end
40
50
 
41
- @new_post = messageboard.posts.build(postable: topic)
51
+ @new_post = Thredded::PostForm.new(user: thredded_current_user, topic: topic, post_params: new_post_params)
42
52
  end
43
53
 
44
54
  def search
45
55
  in_messageboard = params.key?(:messageboard_id)
46
- authorize_reading messageboard if in_messageboard
56
+ if in_messageboard
57
+ authorize_reading messageboard
58
+ unless params_match?(canonical_messageboard_params)
59
+ skip_policy_scope
60
+ return redirect_to(canonical_messageboard_params)
61
+ end
62
+ end
47
63
  @query = params[:q].to_s
48
64
  topics_scope = policy_scope(
49
65
  if in_messageboard
@@ -65,6 +81,8 @@ module Thredded
65
81
  def new
66
82
  @new_topic = Thredded::TopicForm.new(new_topic_params)
67
83
  authorize_creating @new_topic.topic
84
+ return redirect_to(canonical_messageboard_params) unless params_match?(canonical_messageboard_params)
85
+ render
68
86
  end
69
87
 
70
88
  def category
@@ -92,6 +110,7 @@ module Thredded
92
110
 
93
111
  def edit
94
112
  authorize topic, :update?
113
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
95
114
  @edit_topic = Thredded::EditTopicForm.new(user: thredded_current_user, topic: topic)
96
115
  end
97
116
 
@@ -136,6 +155,14 @@ module Thredded
136
155
 
137
156
  private
138
157
 
158
+ def canonical_messageboard_params
159
+ { messageboard_id: messageboard.slug }
160
+ end
161
+
162
+ def canonical_topic_params
163
+ { messageboard_id: messageboard.slug, id: topic.slug }
164
+ end
165
+
139
166
  def follow_change_response(following:)
140
167
  notice = following ? t('thredded.topics.followed_notice') : t('thredded.topics.unfollowed_notice')
141
168
  respond_to do |format|
@@ -150,7 +177,13 @@ module Thredded
150
177
  # @return [Thredded::Topic]
151
178
  # @raise [Thredded::Errors::TopicNotFound] if the topic with the given slug does not exist.
152
179
  def topic
153
- @topic ||= messageboard.topics.friendly_find!(params[:id])
180
+ @topic ||= Thredded::Topic.friendly_find!(params[:id])
181
+ end
182
+
183
+ # Use the topic's messageboard instead of the one specified in the URL,
184
+ # to account for `params[:messageboard_id]` pointing to the wrong messageboard
185
+ def use_topic_messageboard
186
+ @messageboard = topic.messageboard
154
187
  end
155
188
 
156
189
  def topic_params
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class PostForm
4
+ attr_reader :post, :topic
5
+ delegate :id,
6
+ :persisted?,
7
+ :content,
8
+ :content=,
9
+ to: :@post
10
+
11
+ # @param user [Thredded.user_class]
12
+ # @param topic [Topic]
13
+ # @param post [PrivatePost]
14
+ # @param post_params [Hash]
15
+ def initialize(user:, topic:, post: nil, post_params: {})
16
+ @messageboard = topic.messageboard
17
+ @topic = topic
18
+ @post = post ? post : topic.posts.build
19
+
20
+ if post_params.include?(:quote_post)
21
+ post_params[:content] =
22
+ Thredded::ContentFormatter.quote_content(post_params.delete(:quote_post).content)
23
+ end
24
+ @post.attributes = post_params.merge(
25
+ user: (user unless user.thredded_anonymous?),
26
+ messageboard: topic.messageboard
27
+ )
28
+ end
29
+
30
+ def self.for_persisted(post)
31
+ new(user: post.user, topic: post.postable, post: post)
32
+ end
33
+
34
+ def submit_path
35
+ Thredded::UrlsHelper.url_for([@messageboard, @topic, @post, only_path: true])
36
+ end
37
+
38
+ def preview_path
39
+ if @post.persisted?
40
+ Thredded::UrlsHelper.messageboard_topic_post_preview_path(@messageboard, @topic, @post)
41
+ else
42
+ Thredded::UrlsHelper.preview_new_messageboard_topic_post_path(@messageboard, @topic)
43
+ end
44
+ end
45
+
46
+ def save
47
+ return false unless @post.valid?
48
+ @post.save!
49
+ true
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class PrivatePostForm
4
+ attr_reader :post, :topic
5
+ delegate :id,
6
+ :persisted?,
7
+ :content,
8
+ :content=,
9
+ to: :@post
10
+
11
+ # @param user [Thredded.user_class]
12
+ # @param topic [PrivateTopic]
13
+ # @param post [Post]
14
+ # @param post_params [Hash]
15
+ def initialize(user:, topic:, post: nil, post_params: {})
16
+ @topic = topic
17
+ @post = post ? post : topic.posts.build
18
+
19
+ if post_params.include?(:quote_post)
20
+ post_params[:content] =
21
+ Thredded::ContentFormatter.quote_content(post_params.delete(:quote_post).content)
22
+ end
23
+ @post.attributes = post_params.merge(user: (user unless user.thredded_anonymous?))
24
+ end
25
+
26
+ def self.for_persisted(post)
27
+ new(user: post.user, topic: post.postable, post: post)
28
+ end
29
+
30
+ def submit_path
31
+ Thredded::UrlsHelper.url_for([@topic, @post, only_path: true])
32
+ end
33
+
34
+ def preview_path
35
+ if @post.persisted?
36
+ Thredded::UrlsHelper.private_topic_private_post_preview_path(@topic, @post)
37
+ else
38
+ Thredded::UrlsHelper.preview_new_private_topic_private_post_path(@topic)
39
+ end
40
+ end
41
+
42
+ def save
43
+ return false unless @post.valid?
44
+ @post.save!
45
+ true
46
+ end
47
+ end
48
+ end
@@ -60,6 +60,14 @@ module Thredded
60
60
  )
61
61
  end
62
62
 
63
+ def submit_path
64
+ Thredded::UrlsHelper.url_for([private_topic, only_path: true])
65
+ end
66
+
67
+ def preview_path
68
+ Thredded::UrlsHelper.preview_new_private_topic_path
69
+ end
70
+
63
71
  private
64
72
 
65
73
  def topic_categories
@@ -55,6 +55,14 @@ module Thredded
55
55
  )
56
56
  end
57
57
 
58
+ def submit_path
59
+ Thredded::UrlsHelper.url_for([messageboard, topic, only_path: true])
60
+ end
61
+
62
+ def preview_path
63
+ Thredded::UrlsHelper.preview_new_messageboard_topic_path(messageboard)
64
+ end
65
+
58
66
  private
59
67
 
60
68
  # @return [Thredded.user_class, nil] return a user or nil if the user is a NullUser
@@ -22,9 +22,11 @@ module Thredded
22
22
 
23
23
  # @param user [Thredded.user_class]
24
24
  # @param messageboard [Thredded::Messageboard, nil]
25
- def initialize(user:, messageboard: nil, params: {})
25
+ # @param messageboards [ActiveRecord::Relation<Thredded::Messageboard>]
26
+ def initialize(user:, messageboard: nil, messageboards: nil, params: {})
26
27
  @user = user
27
28
  @messageboard = messageboard
29
+ @messageboards = messageboards
28
30
  super(params)
29
31
  end
30
32
 
@@ -46,6 +48,10 @@ module Thredded
46
48
  true
47
49
  end
48
50
 
51
+ def messageboard_groups
52
+ @messageboard_groups ||= MessageboardGroupView.grouped(@messageboards)
53
+ end
54
+
49
55
  def notifications_for_private_topics
50
56
  for_every_notifier(user_preference.notifications_for_private_topics)
51
57
  end
@@ -104,6 +104,14 @@ module Thredded
104
104
  end
105
105
  end
106
106
 
107
+ def quote_post_path(post)
108
+ if post.private_topic_post?
109
+ quote_private_topic_private_post_path(post.postable, post)
110
+ else
111
+ quote_messageboard_topic_post_path(post.messageboard, post.postable, post)
112
+ end
113
+ end
114
+
107
115
  def mark_unread_path(post, _params = {})
108
116
  if post.private_topic_post?
109
117
  mark_as_unread_private_topic_private_post_path(post.postable, post)
@@ -111,5 +119,15 @@ module Thredded
111
119
  mark_as_unread_messageboard_topic_post_path(post.messageboard, post.postable, post)
112
120
  end
113
121
  end
122
+
123
+ # @param post [Post, PrivatePost]
124
+ # @return [String] post permalink path
125
+ def permalink_path(post)
126
+ if post.private_topic_post?
127
+ private_post_permalink_path(post)
128
+ else
129
+ post_permalink_path(post)
130
+ end
131
+ end
114
132
  end
115
133
  end
@@ -22,8 +22,7 @@ module Thredded
22
22
 
23
23
  extend FriendlyId
24
24
  friendly_id :slug_candidates,
25
- use: [:history, :reserved, :scoped],
26
- scope: :messageboard,
25
+ use: %i(history reserved),
27
26
  # Avoid route conflicts
28
27
  reserved_words: ::Thredded::FriendlyIdReservedWordsAndPagination.new(%w(topics))
29
28
 
@@ -153,7 +152,8 @@ module Thredded
153
152
  def slug_candidates
154
153
  [
155
154
  :title,
156
- [:title, '-topic'],
155
+ [:title, '-', messageboard.try(:name)],
156
+ [:title, '-', messageboard.try(:name), '-topic']
157
157
  ]
158
158
  end
159
159
 
@@ -53,7 +53,7 @@ module Thredded
53
53
  end
54
54
 
55
55
  def own_post?
56
- @user.id == @post.user_id
56
+ !anonymous? && @user.id == @post.user_id
57
57
  end
58
58
  end
59
59
  end
@@ -17,7 +17,7 @@ module Thredded
17
17
  end
18
18
 
19
19
  def update?
20
- @user.id == @private_topic.user_id
20
+ !@user.thredded_anonymous? && @user.id == @private_topic.user_id
21
21
  end
22
22
  end
23
23
  end
@@ -94,11 +94,14 @@ module Thredded
94
94
  # @return [Thredded::AllViewHooks::ViewHook]
95
95
  attr_reader :user_info
96
96
  # @return [Thredded::AllViewHooks::ViewHook]
97
+ attr_reader :user_info_list_items
98
+ # @return [Thredded::AllViewHooks::ViewHook]
97
99
  attr_reader :user_moderation_actions
98
100
 
99
101
  def initialize
100
102
  @user_title = ViewHook.new
101
103
  @user_info = ViewHook.new
104
+ @user_info_list_items = ViewHook.new
102
105
  @user_moderation_actions = ViewHook.new
103
106
  end
104
107
  end
@@ -5,7 +5,7 @@ module Thredded
5
5
  delegate :name, to: :@group, allow_nil: true
6
6
  attr_reader :group, :messageboards
7
7
 
8
- # @param messageboard_scope [ActiveRecord::Relation]
8
+ # @param messageboard_scope [ActiveRecord::Relation<Thredded::Messageboard>]
9
9
  # @return [Array<MessageboardGroupView>]
10
10
  def self.grouped(messageboard_scope)
11
11
  messageboard_scope.preload(last_topic: [:last_user])
@@ -14,14 +14,18 @@ module Thredded
14
14
  to: :@post
15
15
 
16
16
  # @param post [Thredded::PostCommon]
17
- # @param policy [#update? #destroy?]
18
- # @param policy [Thredded::TopicView]
17
+ # @param policy [#create? #update? #destroy? #moderate?]
18
+ # @param topic_view [Thredded::TopicView]
19
19
  def initialize(post, policy, topic_view: nil)
20
20
  @post = post
21
21
  @policy = policy
22
22
  @topic_view = topic_view
23
23
  end
24
24
 
25
+ def can_reply?
26
+ @can_reply ||= @policy.create?
27
+ end
28
+
25
29
  def can_update?
26
30
  @can_update ||= @policy.update?
27
31
  end
@@ -34,6 +38,18 @@ module Thredded
34
38
  @can_moderate ||= @policy.moderate?
35
39
  end
36
40
 
41
+ def quote_url_params
42
+ if @post.private_topic_post?
43
+ { post: { quote_private_post_id: @post.id } }
44
+ else
45
+ { post: { quote_post_id: @post.id } }
46
+ end.update(anchor: 'post_content')
47
+ end
48
+
49
+ def quote_path
50
+ Thredded::UrlsHelper.quote_post_path(@post)
51
+ end
52
+
37
53
  def edit_path
38
54
  Thredded::UrlsHelper.edit_post_path(@post)
39
55
  end
@@ -47,7 +63,7 @@ module Thredded
47
63
  end
48
64
 
49
65
  def permalink_path
50
- Thredded::UrlsHelper.post_permalink_path(@post.id)
66
+ Thredded::UrlsHelper.permalink_path(@post)
51
67
  end
52
68
 
53
69
  # This cache key is used only for caching the content.
@@ -15,9 +15,5 @@ module Thredded
15
15
  end
16
16
  new(topic, read_state, Pundit.policy!(user, topic))
17
17
  end
18
-
19
- def new_post_preview_path
20
- Thredded::UrlsHelper.preview_new_private_topic_private_post_path(@topic)
21
- end
22
18
  end
23
19
  end
@@ -63,9 +63,5 @@ module Thredded
63
63
  def messageboard_path
64
64
  Thredded::UrlsHelper.messageboard_topics_path(@topic.messageboard)
65
65
  end
66
-
67
- def new_post_preview_path
68
- Thredded::UrlsHelper.preview_new_messageboard_topic_post_path(@topic.messageboard, @topic)
69
- end
70
66
  end
71
67
  end
@@ -1,6 +1,6 @@
1
1
  <%= form_tag users_moderation_path,
2
2
  method: 'get',
3
- class: 'thredded--form thredded--navigation--search',
3
+ class: 'thredded--form thredded--navigation--search thredded--navigation--search--right',
4
4
  'data-thredded-turboform' => true do %>
5
5
  <%= label_tag :q, t('thredded.moderation.search_users.form_label') %>
6
6
  <%= text_field_tag :q, @query,