thredded 0.2.2 → 0.3.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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.mkdn +63 -0
  3. data/Procfile +1 -0
  4. data/README.mkdn +42 -20
  5. data/app/assets/images/thredded/private-messages.svg +4 -0
  6. data/app/assets/images/thredded/settings.svg +4 -0
  7. data/app/assets/javascripts/thredded.es6 +2 -10
  8. data/app/assets/javascripts/thredded/{currently_online.es6 → components/currently_online.es6} +0 -0
  9. data/app/assets/javascripts/thredded/{post_form.es6 → components/post_form.es6} +0 -0
  10. data/app/assets/javascripts/thredded/{time_stamps.es6 → components/time_stamps.es6} +0 -0
  11. data/app/assets/javascripts/thredded/{topic_form.es6 → components/topic_form.es6} +1 -1
  12. data/app/assets/javascripts/thredded/components/topics.es6 +37 -0
  13. data/app/assets/javascripts/thredded/components/user_preferences_form.es6 +45 -0
  14. data/app/assets/javascripts/thredded/components/users_select.es6 +56 -0
  15. data/app/assets/javascripts/thredded/dependencies.js +9 -0
  16. data/app/assets/javascripts/thredded/thredded.es6 +1 -0
  17. data/app/assets/stylesheets/thredded/_base.scss +3 -2
  18. data/app/assets/stylesheets/thredded/_thredded.scss +4 -1
  19. data/app/assets/stylesheets/thredded/base/_buttons.scss +2 -1
  20. data/app/assets/stylesheets/thredded/base/_forms.scss +23 -18
  21. data/app/assets/stylesheets/thredded/base/_grid.scss +1 -1
  22. data/app/assets/stylesheets/thredded/base/_nav.scss +21 -0
  23. data/app/assets/stylesheets/thredded/base/_tables.scss +5 -14
  24. data/app/assets/stylesheets/thredded/base/_typography.scss +9 -4
  25. data/app/assets/stylesheets/thredded/base/_variables.scss +28 -9
  26. data/app/assets/stylesheets/thredded/components/_alerts.scss +19 -0
  27. data/app/assets/stylesheets/thredded/components/_currently-online.scss +1 -1
  28. data/app/assets/stylesheets/thredded/components/_form-list.scss +2 -4
  29. data/app/assets/stylesheets/thredded/components/_icons.scss +3 -0
  30. data/app/assets/stylesheets/thredded/components/_messageboard.scss +4 -4
  31. data/app/assets/stylesheets/thredded/components/_pagination.scss +2 -2
  32. data/app/assets/stylesheets/thredded/components/_post-form.scss +3 -0
  33. data/app/assets/stylesheets/thredded/components/_post.scss +14 -4
  34. data/app/assets/stylesheets/thredded/components/_select2.scss +79 -9
  35. data/app/assets/stylesheets/thredded/components/_topic-header.scss +11 -1
  36. data/app/assets/stylesheets/thredded/components/_topics.scss +13 -11
  37. data/app/assets/stylesheets/thredded/layout/_main-container.scss +3 -3
  38. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +11 -17
  39. data/app/assets/stylesheets/thredded/layout/_navigation.scss +72 -0
  40. data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +66 -0
  41. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +35 -61
  42. data/app/commands/thredded/at_notification_extractor.rb +1 -0
  43. data/app/commands/thredded/members_marked_notified.rb +1 -0
  44. data/app/commands/thredded/messageboard_destroyer.rb +7 -2
  45. data/app/commands/thredded/notify_mentioned_users.rb +8 -21
  46. data/app/commands/thredded/notify_private_topic_users.rb +3 -5
  47. data/app/controllers/thredded/application_controller.rb +76 -41
  48. data/app/controllers/thredded/autocomplete_users_controller.rb +46 -0
  49. data/app/controllers/thredded/messageboards_controller.rb +8 -5
  50. data/app/controllers/thredded/posts_controller.rb +20 -22
  51. data/app/controllers/thredded/preferences_controller.rb +19 -14
  52. data/app/controllers/thredded/private_topics_controller.rb +58 -23
  53. data/app/controllers/thredded/setups_controller.rb +1 -0
  54. data/app/controllers/thredded/theme_previews_controller.rb +24 -53
  55. data/app/controllers/thredded/topics_controller.rb +48 -77
  56. data/app/forms/thredded/private_topic_form.rb +1 -21
  57. data/app/forms/thredded/topic_form.rb +3 -7
  58. data/app/forms/thredded/user_preferences_form.rb +62 -0
  59. data/app/helpers/thredded/application_helper.rb +11 -12
  60. data/app/helpers/thredded/urls_helper.rb +103 -0
  61. data/app/jobs/thredded/activity_updater_job.rb +4 -3
  62. data/app/jobs/thredded/at_notifier_job.rb +1 -0
  63. data/app/jobs/thredded/notify_private_topic_users_job.rb +1 -0
  64. data/app/mailer_previews/thredded/base_mailer_preview.rb +101 -0
  65. data/app/mailer_previews/thredded/post_mailer_preview.rb +11 -0
  66. data/app/mailer_previews/thredded/private_post_mailer_preview.rb +11 -0
  67. data/app/mailer_previews/thredded/private_topic_mailer_preview.rb +15 -0
  68. data/app/mailers/thredded/base_mailer.rb +13 -0
  69. data/app/mailers/thredded/post_mailer.rb +4 -2
  70. data/app/mailers/thredded/private_post_mailer.rb +4 -2
  71. data/app/mailers/thredded/private_topic_mailer.rb +4 -2
  72. data/app/models/concerns/thredded/friendly_id_reserved_words_and_pagination.rb +16 -0
  73. data/app/models/concerns/thredded/post_common.rb +68 -63
  74. data/app/models/concerns/thredded/topic_common.rb +31 -8
  75. data/app/models/concerns/thredded/user_topic_read_state_common.rb +31 -0
  76. data/app/models/thredded/category.rb +1 -0
  77. data/app/models/thredded/messageboard.rb +24 -25
  78. data/app/models/thredded/messageboard_user.rb +1 -0
  79. data/app/models/thredded/null_preference.rb +1 -0
  80. data/app/models/thredded/null_user.rb +1 -6
  81. data/app/models/thredded/null_user_topic_read_state.rb +12 -0
  82. data/app/models/thredded/post.rb +6 -9
  83. data/app/models/thredded/post_notification.rb +1 -0
  84. data/app/models/thredded/private_post.rb +6 -2
  85. data/app/models/thredded/private_topic.rb +46 -32
  86. data/app/models/thredded/private_user.rb +3 -2
  87. data/app/models/thredded/stats.rb +1 -0
  88. data/app/models/thredded/topic.rb +40 -64
  89. data/app/models/thredded/topic_category.rb +1 -0
  90. data/app/models/thredded/user_detail.rb +2 -15
  91. data/app/models/thredded/user_extender.rb +29 -14
  92. data/app/models/thredded/user_messageboard_preference.rb +20 -0
  93. data/app/models/thredded/user_permissions/admin/if_admin_column_true.rb +1 -0
  94. data/app/models/thredded/user_permissions/admin/none.rb +1 -0
  95. data/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb +1 -0
  96. data/app/models/thredded/user_permissions/moderate/if_moderator_column_true.rb +1 -0
  97. data/app/models/thredded/user_permissions/moderate/none.rb +1 -0
  98. data/app/models/thredded/user_permissions/read/all.rb +1 -0
  99. data/app/models/thredded/user_permissions/write/all.rb +1 -0
  100. data/app/models/thredded/user_permissions/write/none.rb +1 -0
  101. data/app/models/thredded/user_preference.rb +7 -1
  102. data/app/models/thredded/user_private_topic_read_state.rb +12 -0
  103. data/app/models/thredded/user_topic_read_state.rb +12 -0
  104. data/app/policies/thredded/messageboard_policy.rb +27 -0
  105. data/app/policies/thredded/post_policy.rb +33 -0
  106. data/app/policies/thredded/private_post_policy.rb +29 -0
  107. data/app/policies/thredded/private_topic_policy.rb +23 -0
  108. data/app/policies/thredded/topic_policy.rb +32 -0
  109. data/app/view_models/thredded/base_topic_view.rb +56 -0
  110. data/app/view_models/thredded/post_view.rb +44 -0
  111. data/app/view_models/thredded/posts_page_view.rb +27 -0
  112. data/app/view_models/thredded/private_topic_view.rb +9 -0
  113. data/app/{decorators/thredded/topic_email_decorator.rb → view_models/thredded/topic_email_view.rb} +2 -1
  114. data/app/view_models/thredded/topic_view.rb +23 -0
  115. data/app/view_models/thredded/topics_page_view.rb +26 -0
  116. data/app/views/thredded/error_pages/forbidden.html.erb +6 -0
  117. data/app/views/thredded/error_pages/not_found.html.erb +6 -0
  118. data/app/views/thredded/messageboards/_messageboard.html.erb +13 -6
  119. data/app/views/thredded/messageboards/index.html.erb +2 -8
  120. data/app/views/thredded/messageboards/new.html.erb +8 -2
  121. data/app/views/thredded/post_mailer/at_notification.html.erb +3 -3
  122. data/app/views/thredded/post_mailer/at_notification.text.erb +1 -1
  123. data/app/views/thredded/posts/_content_field.html.erb +1 -1
  124. data/app/views/thredded/posts/_form.html.erb +5 -1
  125. data/app/views/thredded/posts/_post.html.erb +3 -1
  126. data/app/views/thredded/posts/edit.html.erb +7 -3
  127. data/app/views/thredded/posts_common/_form.html.erb +1 -1
  128. data/app/views/thredded/posts_common/_post.html.erb +14 -8
  129. data/app/views/thredded/preferences/_form.html.erb +37 -15
  130. data/app/views/thredded/preferences/_header.html.erb +1 -1
  131. data/app/views/thredded/preferences/edit.html.erb +4 -6
  132. data/app/views/thredded/private_post_mailer/at_notification.html.erb +6 -4
  133. data/app/views/thredded/private_posts/_form.html.erb +5 -1
  134. data/app/views/thredded/private_posts/_private_post.html.erb +3 -1
  135. data/app/views/thredded/private_topic_mailer/message_notification.html.erb +3 -7
  136. data/app/views/thredded/private_topic_mailer/message_notification.text.erb +1 -3
  137. data/app/views/thredded/private_topics/_breadcrumbs.html.erb +2 -2
  138. data/app/views/thredded/private_topics/_form.html.erb +15 -10
  139. data/app/views/thredded/private_topics/_header.html.erb +12 -0
  140. data/app/views/thredded/private_topics/_no_private_topics.html.erb +2 -2
  141. data/app/views/thredded/private_topics/_private_topic.html.erb +4 -6
  142. data/app/views/thredded/private_topics/edit.html.erb +32 -0
  143. data/app/views/thredded/private_topics/index.html.erb +5 -5
  144. data/app/views/thredded/private_topics/new.html.erb +1 -2
  145. data/app/views/thredded/private_topics/show.html.erb +12 -7
  146. data/app/views/thredded/search/_form.html.erb +9 -6
  147. data/app/views/thredded/shared/{_messageboard_topics_breadcrumbs.html.erb → _breadcrumbs.html.erb} +2 -2
  148. data/app/views/thredded/shared/_header.html.erb +2 -3
  149. data/app/views/thredded/shared/_nav.html.erb +20 -0
  150. data/app/views/thredded/shared/nav/_notification_preferences.html.erb +6 -0
  151. data/app/views/thredded/shared/nav/_private_topics.html.erb +11 -0
  152. data/app/views/thredded/shared/nav/_standalone.html.erb +12 -0
  153. data/app/views/thredded/theme_previews/_section_title.html.erb +2 -2
  154. data/app/views/thredded/theme_previews/show.html.erb +13 -17
  155. data/app/views/thredded/topics/_form.html.erb +8 -6
  156. data/app/views/thredded/topics/_header.html.erb +12 -0
  157. data/app/views/thredded/topics/_topic.html.erb +4 -8
  158. data/app/views/thredded/topics/_topic_form_admin_options.html.erb +1 -1
  159. data/app/views/thredded/topics/edit.html.erb +22 -18
  160. data/app/views/thredded/topics/index.html.erb +3 -3
  161. data/app/views/thredded/topics/new.html.erb +1 -1
  162. data/app/views/thredded/topics/search.html.erb +17 -5
  163. data/app/views/thredded/topics/show.html.erb +14 -11
  164. data/bin/rails +5 -0
  165. data/config.ru +3 -0
  166. data/config/i18n-tasks.yml +16 -0
  167. data/config/locales/en.yml +90 -0
  168. data/config/routes.rb +29 -15
  169. data/db/migrate/20160329231848_create_thredded.rb +29 -33
  170. data/db/seeds.rb +115 -0
  171. data/db/upgrade_migrations/20160410111522_upgrade_v0_2_to_v0_3.rb +59 -0
  172. data/heroku.gemfile +26 -0
  173. data/heroku.gemfile.lock +282 -0
  174. data/lib/generators/thredded/install/install_generator.rb +1 -0
  175. data/lib/generators/thredded/install/templates/initializer.rb +17 -0
  176. data/lib/html/pipeline/at_mention_filter.rb +2 -1
  177. data/lib/html/pipeline/bbcode_filter.rb +13 -4
  178. data/lib/tasks/thredded_tasks.rake +1 -0
  179. data/lib/thredded.rb +19 -17
  180. data/lib/thredded/at_users.rb +1 -0
  181. data/lib/thredded/engine.rb +14 -5
  182. data/lib/thredded/errors.rb +11 -11
  183. data/lib/thredded/main_app_route_delegator.rb +1 -0
  184. data/lib/thredded/search_parser.rb +2 -1
  185. data/lib/thredded/topics_search.rb +67 -0
  186. data/lib/thredded/version.rb +2 -1
  187. data/thredded.gemspec +12 -8
  188. metadata +146 -82
  189. data/app/assets/javascripts/thredded/users_select.es6 +0 -5
  190. data/app/assets/stylesheets/thredded/layout/_topic-navigation.scss +0 -53
  191. data/app/commands/thredded/user_reads_private_topic.rb +0 -22
  192. data/app/commands/thredded/user_resets_private_topic_to_unread.rb +0 -23
  193. data/app/decorators/thredded/base_topic_decorator.rb +0 -14
  194. data/app/decorators/thredded/base_user_topic_decorator.rb +0 -63
  195. data/app/decorators/thredded/messageboard_decorator.rb +0 -41
  196. data/app/decorators/thredded/post_decorator.rb +0 -40
  197. data/app/decorators/thredded/private_topic_decorator.rb +0 -23
  198. data/app/decorators/thredded/topic_decorator.rb +0 -25
  199. data/app/decorators/thredded/user_private_topic_decorator.rb +0 -13
  200. data/app/decorators/thredded/user_topic_decorator.rb +0 -37
  201. data/app/models/thredded/ability.rb +0 -60
  202. data/app/models/thredded/notification_preference.rb +0 -17
  203. data/app/models/thredded/null_topic.rb +0 -15
  204. data/app/models/thredded/null_topic_read.rb +0 -19
  205. data/app/models/thredded/user_topic_read.rb +0 -10
  206. data/app/views/thredded/shared/_notification_preferences.html.erb +0 -7
  207. data/app/views/thredded/shared/_top_nav.html.erb +0 -36
  208. data/app/views/thredded/shared/_topic_nav.html.erb +0 -22
  209. data/app/views/thredded/topics/_recent_topics_by_user.html.erb +0 -8
  210. data/app/views/thredded/topics/by_category.html.erb +0 -56
  211. data/app/views/thredded/topics_common/_header.html.erb +0 -6
  212. data/lib/thredded/messageboard_user_permissions.rb +0 -22
  213. data/lib/thredded/post_sql_builder.rb +0 -12
  214. data/lib/thredded/post_user_permissions.rb +0 -32
  215. data/lib/thredded/private_topic_user_permissions.rb +0 -26
  216. data/lib/thredded/search_sql_builder.rb +0 -21
  217. data/lib/thredded/seed_database.rb +0 -76
  218. data/lib/thredded/table_sql_builder.rb +0 -41
  219. data/lib/thredded/topic_sql_builder.rb +0 -11
  220. data/lib/thredded/topic_user_permissions.rb +0 -32
@@ -1,7 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
3
  class NotifyMentionedUsers
3
- DELIVER_METHOD = Rails.version < '4.2.0' ? :deliver : :deliver_later
4
-
5
4
  def initialize(post)
6
5
  @post = post
7
6
  end
@@ -13,13 +12,13 @@ module Thredded
13
12
  user_emails = members.map(&:email)
14
13
  (post.private_topic_post? ? PrivatePostMailer : PostMailer)
15
14
  .at_notification(post.id, user_emails)
16
- .send(DELIVER_METHOD)
15
+ .deliver_later
17
16
  MembersMarkedNotified.new(post, members).run
18
17
  end
19
18
 
20
19
  def at_notifiable_members
21
20
  user_names = AtNotificationExtractor.new(post.content).run
22
- members = post.readers_from_user_names(user_names).to_a
21
+ members = post.readers_from_user_names(user_names).to_a
23
22
 
24
23
  members.delete post.user
25
24
  members = exclude_previously_notified(members)
@@ -34,31 +33,19 @@ module Thredded
34
33
  attr_reader :post
35
34
 
36
35
  def exclude_those_opting_out_of_at_notifications(members)
37
- # TODO: implement global notification preferences for private topics.
38
- return members if private_topic?
39
36
  members.select do |member|
40
- Thredded::NotificationPreference
41
- .for(member)
42
- .in(post.messageboard)
43
- .first_or_create
44
- .notify_on_mention?
37
+ member.thredded_user_preference.notify_on_mention? &&
38
+ (private_topic? || member.thredded_user_messageboard_preferences.in(post.messageboard).notify_on_mention?)
45
39
  end
46
40
  end
47
41
 
48
42
  def exclude_those_that_are_not_private(members)
49
- members.reject do |member|
50
- private_topic? && post.postable.users.exclude?(member)
51
- end
43
+ members.reject { |member| private_topic? && post.postable.users.exclude?(member) }
52
44
  end
53
45
 
54
46
  def exclude_previously_notified(members)
55
- emails_notified = Thredded::PostNotification
56
- .where(post: post)
57
- .pluck(:email)
58
-
59
- members.reject do |member|
60
- emails_notified.include? member.email
61
- end
47
+ emails_notified = Thredded::PostNotification.where(post: post).pluck(:email)
48
+ members.reject { |member| emails_notified.include? member.email }
62
49
  end
63
50
 
64
51
  def private_topic?
@@ -1,7 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
3
  class NotifyPrivateTopicUsers
3
- DELIVER_METHOD = Rails.version < '4.2.0' ? :deliver : :deliver_later
4
-
5
4
  def initialize(private_topic)
6
5
  @post = private_topic.posts.first || Post.new
7
6
  @private_topic = private_topic
@@ -14,7 +13,7 @@ module Thredded
14
13
  user_emails = members.map(&:email)
15
14
  PrivateTopicMailer
16
15
  .message_notification(private_topic.id, user_emails)
17
- .send(DELIVER_METHOD)
16
+ .deliver_later
18
17
  mark_notified(members)
19
18
  end
20
19
 
@@ -36,8 +35,7 @@ module Thredded
36
35
  end
37
36
 
38
37
  def exclude_those_opting_out_of_message_notifications(members)
39
- # TODO: implement global notification preferences for private topics.
40
- members
38
+ members.select { |member| member.thredded_user_preference.notify_on_message? }
41
39
  end
42
40
 
43
41
  def exclude_previously_notified(members)
@@ -1,68 +1,95 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
3
  class ApplicationController < ::ApplicationController
3
- layout Thredded.layout
4
+ layout :thredded_layout
5
+ include ::Thredded::UrlsHelper
6
+ include Pundit
4
7
 
5
8
  helper Thredded::Engine.helpers
6
9
  helper_method \
7
10
  :active_users,
11
+ :thredded_current_user,
8
12
  :messageboard,
13
+ :messageboard_or_nil,
9
14
  :preferences,
10
15
  :unread_private_topics_count,
11
16
  :signed_in?
12
17
 
13
- rescue_from \
14
- CanCan::AccessDenied,
15
- Thredded::Errors::MessageboardNotFound,
16
- Thredded::Errors::MessageboardReadDenied,
17
- Thredded::Errors::TopicCreateDenied,
18
- Thredded::Errors::MessageboardCreateDenied,
19
- Thredded::Errors::PrivateTopicCreateDenied do |exception|
20
- redirect_to root_path,
21
- flash: { alert: exception.message }
22
- end
18
+ rescue_from Thredded::Errors::MessageboardNotFound,
19
+ Thredded::Errors::PrivateTopicNotFound,
20
+ Thredded::Errors::TopicNotFound,
21
+ Thredded::Errors::UserNotFound do |exception|
22
+ @error = exception
23
+ @message = exception.message
24
+ render template: 'thredded/error_pages/not_found', status: :not_found
25
+ end
23
26
 
24
- rescue_from \
25
- Thredded::Errors::EmptySearchResults,
26
- Thredded::Errors::TopicNotFound do |exception|
27
- redirect_to messageboard_topics_path(messageboard),
28
- flash: { error: exception.message }
29
- end
27
+ rescue_from Pundit::NotAuthorizedError,
28
+ Thredded::Errors::LoginRequired,
29
+ Thredded::Errors::TopicCreateDenied,
30
+ Thredded::Errors::MessageboardCreateDenied,
31
+ Thredded::Errors::PrivateTopicCreateDenied,
32
+ Thredded::Errors::MessageboardReadDenied do |exception|
33
+ @error = exception
34
+ @message = if @error.is_a?(Pundit::NotAuthorizedError)
35
+ t('thredded.errors.not_authorized')
36
+ else
37
+ exception.message
38
+ end
39
+ render template: 'thredded/error_pages/forbidden', status: :forbidden
40
+ end
41
+
42
+ protected
43
+
44
+ def thredded_current_user
45
+ send(Thredded.current_user_method) || NullUser.new
46
+ end
30
47
 
31
48
  def signed_in?
32
49
  !thredded_current_user.thredded_anonymous?
33
50
  end
34
51
 
52
+ if Rails::VERSION::MAJOR < 5
53
+ # redirect_back polyfill
54
+ def redirect_back(fallback_location:, **args)
55
+ redirect_to :back, args
56
+ rescue ActionController::RedirectBackError
57
+ redirect_to fallback_location, args
58
+ end
59
+ end
60
+
35
61
  private
36
62
 
63
+ def thredded_layout
64
+ Thredded.layout
65
+ end
66
+
37
67
  def unread_private_topics_count
38
- @unread_private_topics_count ||= Thredded::PrivateTopic
39
- .joins(:private_users)
40
- .where(
41
- thredded_private_users: {
42
- user_id: thredded_current_user.id,
43
- read: false
44
- })
45
- .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
46
77
  end
47
78
 
48
79
  def authorize_reading(obj)
49
- return if current_ability.can? :read, obj
80
+ return if policy(obj).read?
50
81
 
51
82
  class_name = obj.class.to_s
52
- error = class_name
53
- .gsub(/Thredded::/, 'Thredded::Errors::') + 'ReadDenied'
83
+ error = class_name.gsub(/Thredded::/, 'Thredded::Errors::') + 'ReadDenied'
54
84
 
55
85
  fail error.constantize
56
86
  end
57
87
 
58
88
  def authorize_creating(obj)
59
- obj = obj.new if obj.class == Class
60
-
61
- return if current_ability.can? :create, obj
89
+ return if policy(obj).create?
62
90
 
63
91
  class_name = obj.class.to_s
64
- error = class_name
65
- .gsub(/Thredded::/, 'Thredded::Errors::') + 'CreateDenied'
92
+ error = class_name.gsub(/Thredded::/, 'Thredded::Errors::') + 'CreateDenied'
66
93
 
67
94
  fail error.constantize
68
95
  end
@@ -76,24 +103,28 @@ module Thredded
76
103
  )
77
104
  end
78
105
 
79
- def current_ability
80
- @current_ability ||= Ability.new(thredded_current_user)
106
+ def pundit_user
107
+ thredded_current_user
81
108
  end
82
109
 
83
110
  def messageboard
84
- @messageboard ||= params[:messageboard_id].presence && Messageboard.find_by_slug!(params[:messageboard_id])
111
+ @messageboard ||= params[:messageboard_id].presence && Messageboard.friendly.find(params[:messageboard_id])
112
+ rescue ActiveRecord::RecordNotFound
113
+ raise Thredded::Errors::MessageboardNotFound
85
114
  end
86
115
 
87
- def preferences
88
- @preferences ||= thredded_current_user.thredded_user_preference
116
+ def messageboard_or_nil
117
+ messageboard
118
+ rescue Thredded::Errors::MessageboardNotFound
119
+ nil
89
120
  end
90
121
 
91
- def thredded_current_user
92
- current_user || NullUser.new
122
+ def preferences
123
+ @preferences ||= thredded_current_user.thredded_user_preference
93
124
  end
94
125
 
95
126
  def active_users
96
- users = if messageboard
127
+ users = if messageboard_or_nil
97
128
  messageboard.recently_active_users
98
129
  else
99
130
  Thredded.user_class.joins(:thredded_user_detail).merge(Thredded::UserDetail.recently_active).to_a
@@ -101,5 +132,9 @@ module Thredded
101
132
  users.push(thredded_current_user) unless thredded_current_user.is_a?(NullUser)
102
133
  users.uniq
103
134
  end
135
+
136
+ def thredded_require_login!
137
+ fail Thredded::Errors::LoginRequired if thredded_current_user.thredded_anonymous?
138
+ end
104
139
  end
105
140
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class AutocompleteUsersController < Thredded::ApplicationController
4
+ MIN_QUERY_LENGTH = 2
5
+ MAX_RESULTS = 20
6
+
7
+ def index
8
+ authorize_creating PrivateTopicForm.new(user: thredded_current_user).private_topic
9
+ users = params.key?(:q) ? users_by_prefix : users_by_ids
10
+ render json: {
11
+ results: users.map do |user|
12
+ { id: user.id,
13
+ name: user.send(Thredded.user_name_column),
14
+ avatar_url: Thredded.avatar_url.call(user) }
15
+ end
16
+ }
17
+ end
18
+
19
+ private
20
+
21
+ def users_by_prefix
22
+ query = params[:q].to_s.strip
23
+ if query.length >= MIN_QUERY_LENGTH
24
+ DbTextSearch::CaseInsensitive.new(users_scope, Thredded.user_name_column).prefix(query)
25
+ .where.not(id: thredded_current_user.id)
26
+ .limit(MAX_RESULTS)
27
+ else
28
+ []
29
+ end
30
+ end
31
+
32
+ # This method is used by select2 do fetch users by ids, e.g. in case of a browser-prefilled field.
33
+ def users_by_ids
34
+ ids = params[:ids].to_s.split(',')
35
+ if ids.present?
36
+ users_scope.where(id: ids)
37
+ else
38
+ []
39
+ end
40
+ end
41
+
42
+ def users_scope
43
+ thredded_current_user.thredded_can_message_users
44
+ end
45
+ end
46
+ end
@@ -1,21 +1,24 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
3
  class MessageboardsController < Thredded::ApplicationController
3
4
  def index
4
- @messageboards = Messageboard.where(closed: false).decorate
5
+ @messageboards = thredded_current_user.thredded_can_read_messageboards
5
6
  end
6
7
 
7
8
  def new
8
- authorize_creating Messageboard
9
-
10
9
  @messageboard = Messageboard.new
10
+ authorize_creating @messageboard
11
11
  end
12
12
 
13
13
  def create
14
14
  @messageboard = Messageboard.new(messageboard_params)
15
+ authorize_creating @messageboard
15
16
 
16
17
  if signed_in? && @messageboard.save
17
- @topic = Topic.create!(topic_params)
18
- @post = Post.create!(post_params)
18
+ Topic.transaction do
19
+ @topic = Topic.create!(topic_params)
20
+ @post = Post.create!(post_params)
21
+ end
19
22
 
20
23
  redirect_to root_path
21
24
  else
@@ -1,52 +1,50 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
3
  class PostsController < Thredded::ApplicationController
3
4
  include ActionView::RecordIdentifier
4
5
 
5
- load_and_authorize_resource only: [:index, :show]
6
- helper_method :messageboard, :topic
7
- before_filter :update_user_activity
6
+ helper_method :topic
7
+ before_action :update_user_activity
8
8
 
9
9
  def create
10
- post = parent_topic.posts.create!(post_params)
10
+ post = parent_topic.posts.build(post_params)
11
+ authorize_creating post
12
+ post.save!
11
13
 
12
- reset_read_status if for_a_private_topic?
13
14
  redirect_to post_path(post)
14
15
  end
15
16
 
16
17
  def edit
17
- authorize! :edit, post
18
+ authorize post, :update?
18
19
  end
19
20
 
20
21
  def update
22
+ authorize post, :update?
21
23
  post.update_attributes(post_params.except(:user, :ip))
22
24
 
23
25
  redirect_to post_path(post)
24
26
  end
25
27
 
26
- def topic
27
- post.postable
28
+ def destroy
29
+ authorize post, :destroy?
30
+ post.destroy!
31
+
32
+ redirect_back fallback_location: topic_url(topic),
33
+ notice: I18n.t('thredded.posts.deleted_notice')
28
34
  end
29
35
 
30
36
  private
31
37
 
32
- def post_path(post)
33
- if for_a_private_topic?
34
- private_topic_path(post.postable, anchor: dom_id(post))
35
- else
36
- messageboard_topic_path(messageboard, post.postable, anchor: dom_id(post))
37
- end
38
- end
39
-
40
- def reset_read_status
41
- Thredded::UserResetsPrivateTopicToUnread.new(parent_topic, thredded_current_user).run
38
+ def topic
39
+ post.postable
42
40
  end
43
41
 
44
42
  def post_params
45
- params
46
- .require(:post)
43
+ p = params.require(:post)
47
44
  .permit(:content)
48
- .merge!(user: thredded_current_user, ip: request.remote_ip)
49
- .tap { |p| p.merge!(messageboard: messageboard) unless for_a_private_topic? }
45
+ .merge(user: thredded_current_user, ip: request.remote_ip)
46
+ p = p.merge(messageboard: messageboard) unless for_a_private_topic?
47
+ p
50
48
  end
51
49
 
52
50
  def parent_topic
@@ -1,28 +1,33 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
3
  class PreferencesController < Thredded::ApplicationController
3
- helper_method :preference
4
+ before_action :thredded_require_login!,
5
+ :init_preferences
4
6
 
5
7
  def edit
6
8
  end
7
9
 
8
10
  def update
9
- preference.update_attributes(preference_params)
10
-
11
- redirect_to :back, flash: { notice: 'Your settings have been updated.' }
12
- end
13
-
14
- def preference
15
- @preference ||= NotificationPreference
16
- .where(messageboard_id: messageboard.id, user_id: thredded_current_user.id)
17
- .first_or_create!
11
+ if @preferences.save
12
+ flash[:notice] = t('thredded.preferences.updated_notice')
13
+ redirect_back fallback_location: edit_preferences_url(@preferences.messageboard)
14
+ else
15
+ render :edit
16
+ end
18
17
  end
19
18
 
20
19
  private
21
20
 
22
- def preference_params
23
- params
24
- .require(:notification_preference)
25
- .permit(:notify_on_mention, :notify_on_message, :filter)
21
+ def init_preferences
22
+ @preferences = UserPreferencesForm.new(
23
+ user: thredded_current_user,
24
+ messageboard: messageboard_or_nil,
25
+ params: params.fetch(:user_preferences_form, {}).permit(
26
+ :notify_on_mention,
27
+ :notify_on_message,
28
+ :messageboard_notify_on_mention,
29
+ )
30
+ )
26
31
  end
27
32
  end
28
33
  end