thredded 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class UserTopicReadState < ActiveRecord::Base
4
+ include UserTopicReadStateCommon
5
+ belongs_to :user,
6
+ class_name: Thredded.user_class,
7
+ inverse_of: :thredded_topic_read_states
8
+ belongs_to :postable,
9
+ class_name: 'Thredded::Topic',
10
+ inverse_of: :user_read_states
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class MessageboardPolicy
4
+ # @param user [Thredded.user_class]
5
+ # @param messageboard [Thredded::Messageboard]
6
+ def initialize(user, messageboard)
7
+ @user = user
8
+ @messageboard = messageboard
9
+ end
10
+
11
+ def create?
12
+ @user.thredded_admin?
13
+ end
14
+
15
+ def read?
16
+ @user.thredded_admin? || @user.thredded_can_read_messageboards.include?(@messageboard)
17
+ end
18
+
19
+ def post?
20
+ @user.thredded_admin? || @user.thredded_can_write_messageboards.include?(@messageboard)
21
+ end
22
+
23
+ def moderate?
24
+ @user.thredded_admin? || @user.thredded_can_moderate_messageboards.include?(@messageboard)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class PostPolicy
4
+ # @param user [Thredded.user_class]
5
+ # @param post [Thredded::Post]
6
+ def initialize(user, post)
7
+ @user = user
8
+ @post = post
9
+ end
10
+
11
+ def create?
12
+ @user.thredded_admin? || !@post.postable.locked? && messageboard_policy.post?
13
+ end
14
+
15
+ def update?
16
+ @user.thredded_admin? || own_post? || messageboard_policy.moderate?
17
+ end
18
+
19
+ def destroy?
20
+ @post.postable.first_post != @post && update?
21
+ end
22
+
23
+ private
24
+
25
+ def messageboard_policy
26
+ @messageboard_policy ||= MessageboardPolicy.new(@user, @post.messageboard)
27
+ end
28
+
29
+ def own_post?
30
+ @user.id == @post.user_id
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class PrivatePostPolicy
4
+ # @param user [Thredded.user_class]
5
+ # @param post [Thredded::PrivatePost]
6
+ def initialize(user, post)
7
+ @user = user
8
+ @post = post
9
+ end
10
+
11
+ def create?
12
+ @user.thredded_admin? || @post.postable.users.include?(@user)
13
+ end
14
+
15
+ def update?
16
+ @user.thredded_admin? || own_post?
17
+ end
18
+
19
+ def destroy?
20
+ @post.postable.first_post != @post && update?
21
+ end
22
+
23
+ private
24
+
25
+ def own_post?
26
+ @user.id == @post.user_id
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class PrivateTopicPolicy
4
+ # @param user [Thredded.user_class]
5
+ # @param private_topic [Thredded::PrivateTopic]
6
+ def initialize(user, private_topic)
7
+ @private_topic = private_topic
8
+ @user = user
9
+ end
10
+
11
+ def create?
12
+ !@user.thredded_anonymous?
13
+ end
14
+
15
+ def read?
16
+ @private_topic.users.include?(@user)
17
+ end
18
+
19
+ def update?
20
+ @user.id == @private_topic.user_id
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ class TopicPolicy
4
+ # @param user [Thredded.user_class]
5
+ # @param topic [Thredded::Topic]
6
+ def initialize(user, topic)
7
+ @user = user
8
+ @topic = topic
9
+ @messageboard_user_permission = MessageboardPolicy.new(user, topic.messageboard)
10
+ end
11
+
12
+ def create?
13
+ @messageboard_user_permission.post?
14
+ end
15
+
16
+ def read?
17
+ @messageboard_user_permission.read?
18
+ end
19
+
20
+ def update?
21
+ @user.thredded_admin? || @topic.user_id == @user.id || moderate?
22
+ end
23
+
24
+ def destroy?
25
+ @user.thredded_admin?
26
+ end
27
+
28
+ def moderate?
29
+ @messageboard_user_permission.moderate?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'thredded/urls_helper'
3
+ module Thredded
4
+ # A view model for TopicCommon.
5
+ class BaseTopicView
6
+ delegate :title,
7
+ :posts_count,
8
+ :updated_at,
9
+ :created_at,
10
+ :user,
11
+ :last_user,
12
+ :to_model,
13
+ to: :@topic
14
+
15
+ delegate :read?,
16
+ to: :@read_state
17
+
18
+ # @param topic [TopicCommon]
19
+ # @param read_state [UserTopicReadStateCommon, nil]
20
+ # @param policy [#destroy?]
21
+ def initialize(topic, read_state, policy)
22
+ @read_state = read_state || Thredded::NullUserTopicReadState.new
23
+ @topic = topic
24
+ @policy = policy
25
+ end
26
+
27
+ def states
28
+ [@read_state.read? ? :read : :unread]
29
+ end
30
+
31
+ def can_update?
32
+ @policy.update?
33
+ end
34
+
35
+ def can_destroy?
36
+ @policy.destroy?
37
+ end
38
+
39
+ def path
40
+ Thredded::UrlsHelper.topic_path(@topic, page: @read_state.page)
41
+ end
42
+
43
+ def self.inherited(subclass)
44
+ subclass.extend ClassMethods
45
+ end
46
+
47
+ module ClassMethods
48
+ def from_user(topic, user)
49
+ read_state = if user && !user.thredded_anonymous?
50
+ topic.association(:user_read_states).klass.where(user_id: user.id, postable_id: topic.id).first
51
+ end
52
+ new(topic, read_state, Pundit.policy!(user, topic))
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'thredded/urls_helper'
3
+ module Thredded
4
+ # A view model for PostCommon.
5
+ class PostView
6
+ delegate :filtered_content,
7
+ :avatar_url,
8
+ :created_at,
9
+ :user,
10
+ :to_model,
11
+ to: :@post
12
+
13
+ # @param post [Thredded::PostCommon]
14
+ # @param policy [#update? #destroy?]
15
+ def initialize(post, policy)
16
+ @post = post
17
+ @policy = policy
18
+ end
19
+
20
+ def can_update?
21
+ @can_update ||= @policy.update?
22
+ end
23
+
24
+ def can_destroy?
25
+ @can_destroy ||= @policy.destroy?
26
+ end
27
+
28
+ def edit_path
29
+ Thredded::UrlsHelper.edit_post_path(@post)
30
+ end
31
+
32
+ def destroy_path
33
+ Thredded::UrlsHelper.delete_post_path(@post)
34
+ end
35
+
36
+ def cache_key
37
+ [
38
+ @post,
39
+ @post.user,
40
+ [can_update?, can_destroy?].map { |p| p ? '+' : '-' } * ''
41
+ ]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'thredded/post_view'
3
+ require_dependency 'thredded/topic_view'
4
+ require_dependency 'thredded/private_topic_view'
5
+ module Thredded
6
+ # A view model for a page of PostViews.
7
+ class PostsPageView
8
+ delegate :to_ary,
9
+ to: :@topic_views
10
+ delegate :total_pages,
11
+ :current_page,
12
+ :limit_value,
13
+ to: :@topics_page_scope
14
+
15
+ # @return [Thredded::BaseTopicView]
16
+ attr_reader :topic
17
+
18
+ # @param user [Thredded.user_class] the user who is viewing the posts page
19
+ # @param topic [Thredded::TopicCommon]
20
+ # @param posts_page_scope [ActiveRecord::Relation<Thredded::PostCommon>]
21
+ def initialize(user, topic, posts_page_scope)
22
+ @topics_page_scope = posts_page_scope
23
+ @topic_views = posts_page_scope.map { |post| PostView.new(post, Pundit.policy!(user, post)) }
24
+ @topic = "#{posts_page_scope.reflect_on_association(:postable).klass}View".constantize.from_user(topic, user)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ # A view model for PrivateTopic.
4
+ class PrivateTopicView < BaseTopicView
5
+ def edit_path
6
+ Thredded::UrlsHelper.edit_private_topic_path(@topic)
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Thredded
2
- class TopicEmailDecorator
3
+ class TopicEmailView
3
4
  # @param [Thredded::TopicCommon] topic
4
5
  def initialize(topic)
5
6
  @topic = topic
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ # A view model for Topic.
4
+ class TopicView < BaseTopicView
5
+ delegate :categories,
6
+ to: :@topic
7
+
8
+ def states
9
+ super + [
10
+ (:locked if @topic.locked?),
11
+ (:sticky if @topic.sticky?),
12
+ ].compact
13
+ end
14
+
15
+ def edit_path
16
+ Thredded::UrlsHelper.edit_messageboard_topic_path(@topic.messageboard, @topic)
17
+ end
18
+
19
+ def destroy_path
20
+ Thredded::UrlsHelper.messageboard_topic_path(@topic.messageboard, @topic)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'thredded/topic_view'
3
+ require_dependency 'thredded/private_topic_view'
4
+ module Thredded
5
+ # A view model for a page of BaseTopicViews.
6
+ class TopicsPageView
7
+ delegate :to_ary,
8
+ :blank?,
9
+ :empty?,
10
+ to: :@topic_views
11
+ delegate :total_pages,
12
+ :current_page,
13
+ :limit_value,
14
+ to: :@topics_page_scope
15
+
16
+ # @param user [Thredded.user_class] the user who is viewing the posts page
17
+ # @param topics_page_scope [ActiveRecord::Relation<Thredded::Topic>]
18
+ def initialize(user, topics_page_scope)
19
+ @topics_page_scope = topics_page_scope
20
+ topic_view_class = "#{topics_page_scope.klass}View".constantize
21
+ @topic_views = @topics_page_scope.with_read_states(user).map do |(topic, read_state)|
22
+ topic_view_class.new(topic, read_state, Pundit.policy!(user, topic))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ <% content_for :thredded_page_title, @message %>
2
+ <% content_for :thredded_page_id, 'thredded--error-forbidden' %>
3
+ <% content_for :thredded_breadcrumbs, render('thredded/shared/breadcrumbs') %>
4
+ <%= thredded_page do %>
5
+ <p class="thredded--alert thredded--alert-warning"><%= @message %></p>
6
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <% content_for :thredded_page_title, @message %>
2
+ <% content_for :thredded_page_id, 'thredded--error-not-found' %>
3
+ <% content_for :thredded_breadcrumbs, render('thredded/shared/breadcrumbs') %>
4
+ <%= thredded_page do %>
5
+ <p class="thredded--alert thredded--alert-danger"><%= @message %></p>
6
+ <% end %>
@@ -1,15 +1,22 @@
1
- <% if current_ability.can? :read, messageboard.original %>
1
+ <% if policy(messageboard).read? %>
2
2
  <%= link_to messageboard_topics_path(messageboard), class: 'thredded--messageboard' do %>
3
3
  <header>
4
4
  <h2 class="thredded--messageboard--title"><%= messageboard.name %></h2>
5
- <h3 class="thredded--messageboard--meta"><%= messageboard.meta %></h3>
5
+ <h3 class="thredded--messageboard--meta">
6
+ <%= t 'thredded.messageboard.topics_and_posts_counts',
7
+ topics_count: number_to_human(messageboard.topics_count).downcase,
8
+ posts_count: number_to_human(messageboard.posts_count).downcase %>
9
+ </h3>
6
10
  </header>
7
11
 
8
12
  <p class="thredded--messageboard--description"><%= messageboard.description %></p>
9
13
 
10
- <p class="thredded--messageboard--byline">
11
- Updated <%= time_ago messageboard.latest_topic.updated_at %>
12
- <cite>by <%= messageboard.latest_user %></cite>
13
- </p>
14
+ <% if messageboard.latest_topic %>
15
+ <p class="thredded--messageboard--byline">
16
+ <%= t 'thredded.messageboard.last_updated_by_html',
17
+ time_ago: time_ago(messageboard.latest_topic.updated_at),
18
+ user: messageboard.latest_user %>
19
+ </p>
20
+ <% end %>
14
21
  <% end %>
15
22
  <% end %>
@@ -1,18 +1,12 @@
1
1
  <% content_for :thredded_page_title, 'Messageboards' %>
2
2
  <% content_for :thredded_page_id, 'thredded--messageboards-index' %>
3
- <% content_for :thredded_breadcrumbs do %>
4
- <ul class="thredded--navigation-breadcrumbs">
5
- <li>
6
- <%= link_to 'All Message Boards', messageboards_path %>
7
- </li>
8
- </ul>
9
- <% end %>
3
+ <% content_for :thredded_breadcrumbs, render('thredded/shared/breadcrumbs') %>
10
4
  <%= thredded_page do %>
11
5
  <section class="thredded--main-section thredded--messageboards">
12
6
  <%= render @messageboards %>
13
7
  </section>
14
8
 
15
- <% if current_ability.can? :create, Thredded::Messageboard %>
9
+ <% if policy(Thredded::Messageboard.new).create? %>
16
10
  <div class="thredded--messageboard--create">
17
11
  <a class="thredded--button" href="<%= new_messageboard_path %>">Create a New Messageboard</a>
18
12
  </div>
@@ -1,11 +1,17 @@
1
1
  <% content_for :thredded_page_title, 'Create a New Messageboard' %>
2
2
  <% content_for :thredded_page_id, 'thredded--messageboards-new' %>
3
+ <% content_for :thredded_breadcrumbs do %>
4
+ <ul class="thredded--navigation-breadcrumbs">
5
+ <li>Create a New Messageboard</li>
6
+ </ul>
7
+ <% end %>
8
+
3
9
  <%= thredded_page do %>
4
- <%= form_for @messageboard, class: 'thredded--form' do |f| %>
10
+ <%= form_for @messageboard, html: { class: 'thredded--form' } do |f| %>
5
11
  <ul class="thredded--form-list">
6
12
  <li>
7
13
  <%= f.label :name %>
8
- <%= f.text_field :name %>
14
+ <%= f.text_field :name, required: true %>
9
15
  </li>
10
16
  <li>
11
17
  <%= f.label :description %>