threddedDANIEL 0.14.5

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 (367) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +744 -0
  4. data/app/assets/images/favicons/README.md +3 -0
  5. data/app/assets/images/favicons/amazon.png +0 -0
  6. data/app/assets/images/favicons/github.png +0 -0
  7. data/app/assets/images/favicons/google_branding/logo_calendar_128px.png +0 -0
  8. data/app/assets/images/favicons/google_branding/logo_docs_48px.png +0 -0
  9. data/app/assets/images/favicons/google_branding/logo_drive_48px.png +0 -0
  10. data/app/assets/images/favicons/google_branding/logo_forms_48px.png +0 -0
  11. data/app/assets/images/favicons/google_branding/logo_sheets_48px.png +0 -0
  12. data/app/assets/images/favicons/google_branding/logo_slides_48px.png +0 -0
  13. data/app/assets/images/favicons/stackexchange.png +0 -0
  14. data/app/assets/images/favicons/twitter.png +0 -0
  15. data/app/assets/images/favicons/wikipedia.png +0 -0
  16. data/app/assets/images/thredded/breadcrumb-chevron.svg +1 -0
  17. data/app/assets/images/thredded/follow.svg +1 -0
  18. data/app/assets/images/thredded/lock.svg +1 -0
  19. data/app/assets/images/thredded/moderation.svg +1 -0
  20. data/app/assets/images/thredded/private-messages.svg +1 -0
  21. data/app/assets/images/thredded/settings.svg +1 -0
  22. data/app/assets/images/thredded/three-dot-menu.svg +3 -0
  23. data/app/assets/images/thredded/unfollow.svg +1 -0
  24. data/app/assets/javascripts/thredded.es6 +2 -0
  25. data/app/assets/javascripts/thredded/components/currently_online.es6 +32 -0
  26. data/app/assets/javascripts/thredded/components/flash_messages.es6 +9 -0
  27. data/app/assets/javascripts/thredded/components/mention_autocompletion.es6 +40 -0
  28. data/app/assets/javascripts/thredded/components/post_form.es6 +37 -0
  29. data/app/assets/javascripts/thredded/components/preview_area.es6 +56 -0
  30. data/app/assets/javascripts/thredded/components/quote_post.es6 +49 -0
  31. data/app/assets/javascripts/thredded/components/time_stamps.es6 +25 -0
  32. data/app/assets/javascripts/thredded/components/topic_form.es6 +94 -0
  33. data/app/assets/javascripts/thredded/components/topics.es6 +46 -0
  34. data/app/assets/javascripts/thredded/components/turboforms.es6 +25 -0
  35. data/app/assets/javascripts/thredded/components/user_preferences_form.es6 +66 -0
  36. data/app/assets/javascripts/thredded/components/user_textcomplete.es6 +50 -0
  37. data/app/assets/javascripts/thredded/components/users_select.es6 +122 -0
  38. data/app/assets/javascripts/thredded/core/csrf_tokens.es6 +9 -0
  39. data/app/assets/javascripts/thredded/core/debounce.es6 +32 -0
  40. data/app/assets/javascripts/thredded/core/escape_html.es6 +7 -0
  41. data/app/assets/javascripts/thredded/core/hide_soft_keyboard.es6 +7 -0
  42. data/app/assets/javascripts/thredded/core/on_page_load.es6 +54 -0
  43. data/app/assets/javascripts/thredded/core/serialize_form.es6 +9 -0
  44. data/app/assets/javascripts/thredded/core/thredded.es6 +1 -0
  45. data/app/assets/javascripts/thredded/dependencies.js +8 -0
  46. data/app/assets/javascripts/thredded/dependencies/autosize.js +1 -0
  47. data/app/assets/javascripts/thredded/dependencies/textcomplete.js +1 -0
  48. data/app/assets/javascripts/thredded/dependencies/timeago.js +1 -0
  49. data/app/assets/javascripts/thredded/dependencies/ujs.js +1 -0
  50. data/app/assets/javascripts/thredded/thredded.es6 +2 -0
  51. data/app/assets/stylesheets/thredded.scss +3 -0
  52. data/app/assets/stylesheets/thredded/_base.scss +13 -0
  53. data/app/assets/stylesheets/thredded/_dependencies.scss +0 -0
  54. data/app/assets/stylesheets/thredded/_email.scss +51 -0
  55. data/app/assets/stylesheets/thredded/_thredded.scss +33 -0
  56. data/app/assets/stylesheets/thredded/base/_alerts.scss +44 -0
  57. data/app/assets/stylesheets/thredded/base/_buttons.scss +73 -0
  58. data/app/assets/stylesheets/thredded/base/_dropdown-menu.scss +83 -0
  59. data/app/assets/stylesheets/thredded/base/_forms.scss +84 -0
  60. data/app/assets/stylesheets/thredded/base/_grid.scss +58 -0
  61. data/app/assets/stylesheets/thredded/base/_lists.scss +31 -0
  62. data/app/assets/stylesheets/thredded/base/_nav.scss +67 -0
  63. data/app/assets/stylesheets/thredded/base/_tables.scss +17 -0
  64. data/app/assets/stylesheets/thredded/base/_typography.scss +72 -0
  65. data/app/assets/stylesheets/thredded/base/_variables.scss +141 -0
  66. data/app/assets/stylesheets/thredded/components/_alerts.scss +19 -0
  67. data/app/assets/stylesheets/thredded/components/_base.scss +25 -0
  68. data/app/assets/stylesheets/thredded/components/_currently-online.scss +54 -0
  69. data/app/assets/stylesheets/thredded/components/_empty.scss +11 -0
  70. data/app/assets/stylesheets/thredded/components/_flash-message.scss +19 -0
  71. data/app/assets/stylesheets/thredded/components/_following.scss +14 -0
  72. data/app/assets/stylesheets/thredded/components/_form-list.scss +39 -0
  73. data/app/assets/stylesheets/thredded/components/_icons.scss +3 -0
  74. data/app/assets/stylesheets/thredded/components/_main-section.scss +9 -0
  75. data/app/assets/stylesheets/thredded/components/_mention-autocomplete.scss +57 -0
  76. data/app/assets/stylesheets/thredded/components/_messageboard.scss +155 -0
  77. data/app/assets/stylesheets/thredded/components/_onebox.scss +275 -0
  78. data/app/assets/stylesheets/thredded/components/_pagination.scss +35 -0
  79. data/app/assets/stylesheets/thredded/components/_post-form.scss +27 -0
  80. data/app/assets/stylesheets/thredded/components/_post.scss +138 -0
  81. data/app/assets/stylesheets/thredded/components/_preferences.scss +19 -0
  82. data/app/assets/stylesheets/thredded/components/_preview_area.scss +11 -0
  83. data/app/assets/stylesheets/thredded/components/_topic-delete.scss +8 -0
  84. data/app/assets/stylesheets/thredded/components/_topic-header.scss +111 -0
  85. data/app/assets/stylesheets/thredded/components/_topics.scss +186 -0
  86. data/app/assets/stylesheets/thredded/layout/_main-container.scss +16 -0
  87. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +79 -0
  88. data/app/assets/stylesheets/thredded/layout/_moderation.scss +97 -0
  89. data/app/assets/stylesheets/thredded/layout/_navigation.scss +87 -0
  90. data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +126 -0
  91. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +20 -0
  92. data/app/assets/stylesheets/thredded/layout/_user.scss +10 -0
  93. data/app/assets/stylesheets/thredded/utilities/_is-compact.scss +26 -0
  94. data/app/assets/stylesheets/thredded/utilities/_is-expanded.scss +16 -0
  95. data/app/commands/thredded/at_notification_extractor.rb +23 -0
  96. data/app/commands/thredded/autofollow_users.rb +62 -0
  97. data/app/commands/thredded/create_messageboard.rb +42 -0
  98. data/app/commands/thredded/mark_all_read.rb +22 -0
  99. data/app/commands/thredded/moderate_post.rb +48 -0
  100. data/app/commands/thredded/notify_following_users.rb +78 -0
  101. data/app/commands/thredded/notify_private_topic_users.rb +34 -0
  102. data/app/controllers/concerns/thredded/new_post_params.rb +21 -0
  103. data/app/controllers/concerns/thredded/new_private_post_params.rb +21 -0
  104. data/app/controllers/concerns/thredded/new_private_topic_params.rb +25 -0
  105. data/app/controllers/concerns/thredded/new_topic_params.rb +19 -0
  106. data/app/controllers/concerns/thredded/render_preview.rb +16 -0
  107. data/app/controllers/thredded/application_controller.rb +145 -0
  108. data/app/controllers/thredded/autocomplete_users_controller.rb +52 -0
  109. data/app/controllers/thredded/messageboard_groups_controller.rb +31 -0
  110. data/app/controllers/thredded/messageboards_controller.rb +53 -0
  111. data/app/controllers/thredded/moderation_controller.rb +103 -0
  112. data/app/controllers/thredded/post_permalinks_controller.rb +11 -0
  113. data/app/controllers/thredded/post_previews_controller.rb +29 -0
  114. data/app/controllers/thredded/posts_controller.rb +97 -0
  115. data/app/controllers/thredded/preferences_controller.rb +42 -0
  116. data/app/controllers/thredded/private_post_permalinks_controller.rb +12 -0
  117. data/app/controllers/thredded/private_post_previews_controller.rb +29 -0
  118. data/app/controllers/thredded/private_posts_controller.rb +96 -0
  119. data/app/controllers/thredded/private_topic_previews_controller.rb +15 -0
  120. data/app/controllers/thredded/private_topics_controller.rb +102 -0
  121. data/app/controllers/thredded/read_states_controller.rb +13 -0
  122. data/app/controllers/thredded/theme_previews_controller.rb +34 -0
  123. data/app/controllers/thredded/topic_previews_controller.rb +15 -0
  124. data/app/controllers/thredded/topics_controller.rb +205 -0
  125. data/app/forms/thredded/edit_topic_form.rb +51 -0
  126. data/app/forms/thredded/post_form.rb +54 -0
  127. data/app/forms/thredded/private_post_form.rb +50 -0
  128. data/app/forms/thredded/private_topic_form.rb +160 -0
  129. data/app/forms/thredded/topic_form.rb +95 -0
  130. data/app/forms/thredded/user_preferences_form.rb +110 -0
  131. data/app/helpers/thredded/application_helper.rb +129 -0
  132. data/app/helpers/thredded/nav_helper.rb +42 -0
  133. data/app/helpers/thredded/render_helper.rb +15 -0
  134. data/app/helpers/thredded/urls_helper.rb +134 -0
  135. data/app/jobs/thredded/activity_updater_job.rb +21 -0
  136. data/app/jobs/thredded/auto_follow_and_notify_job.rb +14 -0
  137. data/app/jobs/thredded/notify_private_topic_users_job.rb +12 -0
  138. data/app/mailer_previews/thredded/base_mailer_preview.rb +118 -0
  139. data/app/mailer_previews/thredded/post_mailer_preview.rb +13 -0
  140. data/app/mailer_previews/thredded/private_topic_mailer_preview.rb +13 -0
  141. data/app/mailers/thredded/base_mailer.rb +18 -0
  142. data/app/mailers/thredded/post_mailer.rb +21 -0
  143. data/app/mailers/thredded/private_topic_mailer.rb +21 -0
  144. data/app/models/concerns/thredded/content_moderation_state.rb +67 -0
  145. data/app/models/concerns/thredded/friendly_id_reserved_words_and_pagination.rb +17 -0
  146. data/app/models/concerns/thredded/moderation_state.rb +14 -0
  147. data/app/models/concerns/thredded/notifier_preference.rb +19 -0
  148. data/app/models/concerns/thredded/post_common.rb +76 -0
  149. data/app/models/concerns/thredded/search_parser.rb +41 -0
  150. data/app/models/concerns/thredded/topic_common.rb +94 -0
  151. data/app/models/concerns/thredded/topics_search.rb +67 -0
  152. data/app/models/concerns/thredded/user_topic_read_state_common.rb +42 -0
  153. data/app/models/thredded/category.rb +18 -0
  154. data/app/models/thredded/messageboard.rb +120 -0
  155. data/app/models/thredded/messageboard_group.rb +19 -0
  156. data/app/models/thredded/messageboard_notifications_for_followed_topics.rb +30 -0
  157. data/app/models/thredded/messageboard_user.rb +14 -0
  158. data/app/models/thredded/notifications_for_followed_topics.rb +25 -0
  159. data/app/models/thredded/notifications_for_private_topics.rb +22 -0
  160. data/app/models/thredded/null_user.rb +51 -0
  161. data/app/models/thredded/null_user_topic_read_state.rb +17 -0
  162. data/app/models/thredded/post.rb +77 -0
  163. data/app/models/thredded/post_moderation_record.rb +56 -0
  164. data/app/models/thredded/private_post.rb +63 -0
  165. data/app/models/thredded/private_topic.rb +89 -0
  166. data/app/models/thredded/private_user.rb +8 -0
  167. data/app/models/thredded/stats.rb +25 -0
  168. data/app/models/thredded/topic.rb +179 -0
  169. data/app/models/thredded/topic_category.rb +8 -0
  170. data/app/models/thredded/user_detail.rb +27 -0
  171. data/app/models/thredded/user_extender.rb +75 -0
  172. data/app/models/thredded/user_messageboard_preference.rb +45 -0
  173. data/app/models/thredded/user_permissions/admin/if_admin_column_true.rb +14 -0
  174. data/app/models/thredded/user_permissions/admin/none.rb +14 -0
  175. data/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb +15 -0
  176. data/app/models/thredded/user_permissions/moderate/if_moderator_column_true.rb +16 -0
  177. data/app/models/thredded/user_permissions/moderate/none.rb +16 -0
  178. data/app/models/thredded/user_permissions/read/all.rb +27 -0
  179. data/app/models/thredded/user_permissions/write/all.rb +16 -0
  180. data/app/models/thredded/user_permissions/write/none.rb +16 -0
  181. data/app/models/thredded/user_post_notification.rb +29 -0
  182. data/app/models/thredded/user_preference.rb +26 -0
  183. data/app/models/thredded/user_private_topic_read_state.rb +13 -0
  184. data/app/models/thredded/user_topic_follow.rb +34 -0
  185. data/app/models/thredded/user_topic_read_state.rb +13 -0
  186. data/app/notifiers/thredded/email_notifier.rb +25 -0
  187. data/app/policies/thredded/messageboard_group_policy.rb +16 -0
  188. data/app/policies/thredded/messageboard_policy.rb +49 -0
  189. data/app/policies/thredded/post_policy.rb +64 -0
  190. data/app/policies/thredded/private_post_policy.rb +38 -0
  191. data/app/policies/thredded/private_topic_policy.rb +24 -0
  192. data/app/policies/thredded/topic_policy.rb +49 -0
  193. data/app/view_hooks/thredded/all_view_hooks.rb +125 -0
  194. data/app/view_models/thredded/base_topic_view.rb +43 -0
  195. data/app/view_models/thredded/messageboard_group_view.rb +27 -0
  196. data/app/view_models/thredded/post_view.rb +89 -0
  197. data/app/view_models/thredded/posts_page_view.rb +27 -0
  198. data/app/view_models/thredded/private_topic_view.rb +20 -0
  199. data/app/view_models/thredded/private_topics_page_view.rb +31 -0
  200. data/app/view_models/thredded/topic_email_view.rb +18 -0
  201. data/app/view_models/thredded/topic_posts_page_view.rb +17 -0
  202. data/app/view_models/thredded/topic_view.rb +68 -0
  203. data/app/view_models/thredded/topics_page_view.rb +38 -0
  204. data/app/views/layouts/thredded/application.html.erb +18 -0
  205. data/app/views/thredded/categories/_category.html.erb +1 -0
  206. data/app/views/thredded/error_pages/forbidden.html.erb +6 -0
  207. data/app/views/thredded/error_pages/not_found.html.erb +6 -0
  208. data/app/views/thredded/kaminari/_first_page.html.erb +11 -0
  209. data/app/views/thredded/kaminari/_gap.html.erb +8 -0
  210. data/app/views/thredded/kaminari/_last_page.html.erb +11 -0
  211. data/app/views/thredded/kaminari/_next_page.html.erb +11 -0
  212. data/app/views/thredded/kaminari/_page.html.erb +12 -0
  213. data/app/views/thredded/kaminari/_paginator.html.erb +23 -0
  214. data/app/views/thredded/kaminari/_prev_page.html.erb +11 -0
  215. data/app/views/thredded/messageboard_groups/new.html.erb +28 -0
  216. data/app/views/thredded/messageboards/_form.html.erb +30 -0
  217. data/app/views/thredded/messageboards/_messageboard.html.erb +20 -0
  218. data/app/views/thredded/messageboards/_messageboard_meta.html.erb +13 -0
  219. data/app/views/thredded/messageboards/edit.html.erb +15 -0
  220. data/app/views/thredded/messageboards/index.html.erb +34 -0
  221. data/app/views/thredded/messageboards/new.html.erb +15 -0
  222. data/app/views/thredded/moderation/_nav.html.erb +19 -0
  223. data/app/views/thredded/moderation/_post.html.erb +19 -0
  224. data/app/views/thredded/moderation/_post_moderation_actions.html.erb +12 -0
  225. data/app/views/thredded/moderation/_post_moderation_record.html.erb +46 -0
  226. data/app/views/thredded/moderation/_user_moderation_state.html.erb +3 -0
  227. data/app/views/thredded/moderation/_user_post.html.erb +12 -0
  228. data/app/views/thredded/moderation/_users_search_form.html.erb +13 -0
  229. data/app/views/thredded/moderation/activity.html.erb +20 -0
  230. data/app/views/thredded/moderation/history.html.erb +13 -0
  231. data/app/views/thredded/moderation/pending.html.erb +24 -0
  232. data/app/views/thredded/moderation/user.html.erb +54 -0
  233. data/app/views/thredded/moderation/users.html.erb +41 -0
  234. data/app/views/thredded/post_mailer/post_notification.html.erb +26 -0
  235. data/app/views/thredded/post_mailer/post_notification.text.erb +14 -0
  236. data/app/views/thredded/post_previews/preview.html.erb +1 -0
  237. data/app/views/thredded/post_previews/update.html.erb +1 -0
  238. data/app/views/thredded/posts/_content.html.erb +1 -0
  239. data/app/views/thredded/posts/_form.html.erb +5 -0
  240. data/app/views/thredded/posts/_post.html.erb +13 -0
  241. data/app/views/thredded/posts/_user.html.erb +3 -0
  242. data/app/views/thredded/posts/edit.html.erb +16 -0
  243. data/app/views/thredded/posts/new.html.erb +15 -0
  244. data/app/views/thredded/posts_common/_actions.html.erb +28 -0
  245. data/app/views/thredded/posts_common/_content.html.erb +3 -0
  246. data/app/views/thredded/posts_common/_form.html.erb +22 -0
  247. data/app/views/thredded/posts_common/_header.html.erb +8 -0
  248. data/app/views/thredded/posts_common/_header_with_topic.html.erb +15 -0
  249. data/app/views/thredded/posts_common/_header_with_user_and_topic.html.erb +18 -0
  250. data/app/views/thredded/posts_common/actions/_delete.html.erb +4 -0
  251. data/app/views/thredded/posts_common/actions/_edit.html.erb +3 -0
  252. data/app/views/thredded/posts_common/actions/_mark_as_unread.html.erb +2 -0
  253. data/app/views/thredded/posts_common/actions/_quote.html.erb +4 -0
  254. data/app/views/thredded/posts_common/form/_after_content.html.erb +8 -0
  255. data/app/views/thredded/posts_common/form/_before_content.html.erb +8 -0
  256. data/app/views/thredded/posts_common/form/_content.html.erb +7 -0
  257. data/app/views/thredded/posts_common/form/_content_field.html.erb +8 -0
  258. data/app/views/thredded/posts_common/form/_preview_area.html.erb +16 -0
  259. data/app/views/thredded/preferences/_form.html.erb +95 -0
  260. data/app/views/thredded/preferences/_messageboards_nav.html.erb +8 -0
  261. data/app/views/thredded/preferences/_messageboards_nav_item.html.erb +2 -0
  262. data/app/views/thredded/preferences/edit.html.erb +20 -0
  263. data/app/views/thredded/private_post_previews/preview.html.erb +1 -0
  264. data/app/views/thredded/private_post_previews/update.html.erb +1 -0
  265. data/app/views/thredded/private_posts/_content.html.erb +1 -0
  266. data/app/views/thredded/private_posts/_form.html.erb +6 -0
  267. data/app/views/thredded/private_posts/_private_post.html.erb +6 -0
  268. data/app/views/thredded/private_posts/edit.html.erb +16 -0
  269. data/app/views/thredded/private_posts/new.html.erb +11 -0
  270. data/app/views/thredded/private_topic_mailer/message_notification.html.erb +26 -0
  271. data/app/views/thredded/private_topic_mailer/message_notification.text.erb +15 -0
  272. data/app/views/thredded/private_topic_previews/preview.html.erb +1 -0
  273. data/app/views/thredded/private_topics/_breadcrumbs.html.erb +4 -0
  274. data/app/views/thredded/private_topics/_form.html.erb +39 -0
  275. data/app/views/thredded/private_topics/_header.html.erb +17 -0
  276. data/app/views/thredded/private_topics/_no_private_topics.html.erb +6 -0
  277. data/app/views/thredded/private_topics/_private_topic.html.erb +23 -0
  278. data/app/views/thredded/private_topics/edit.html.erb +35 -0
  279. data/app/views/thredded/private_topics/header/_participant.html.erb +1 -0
  280. data/app/views/thredded/private_topics/index.html.erb +32 -0
  281. data/app/views/thredded/private_topics/new.html.erb +11 -0
  282. data/app/views/thredded/private_topics/private_topic/_participant.html.erb +1 -0
  283. data/app/views/thredded/private_topics/show.html.erb +28 -0
  284. data/app/views/thredded/search/_form.html.erb +13 -0
  285. data/app/views/thredded/shared/_breadcrumbs.html.erb +6 -0
  286. data/app/views/thredded/shared/_content_moderation_blocked_state.html.erb +8 -0
  287. data/app/views/thredded/shared/_currently_online.html.erb +6 -0
  288. data/app/views/thredded/shared/_flash_messages.html.erb +7 -0
  289. data/app/views/thredded/shared/_header.html.erb +3 -0
  290. data/app/views/thredded/shared/_nav.html.erb +19 -0
  291. data/app/views/thredded/shared/_page.html.erb +15 -0
  292. data/app/views/thredded/shared/currently_online/_header.html.erb +5 -0
  293. data/app/views/thredded/shared/currently_online/_user_list.html.erb +3 -0
  294. data/app/views/thredded/shared/currently_online/_user_list_item.html.erb +6 -0
  295. data/app/views/thredded/shared/nav/_moderation.html.erb +14 -0
  296. data/app/views/thredded/shared/nav/_notification_preferences.html.erb +8 -0
  297. data/app/views/thredded/shared/nav/_private_topics.html.erb +12 -0
  298. data/app/views/thredded/shared/nav/_standalone.html.erb +12 -0
  299. data/app/views/thredded/shared/nav/_standalone_profile.html.erb +3 -0
  300. data/app/views/thredded/shared/preview.html.erb +10 -0
  301. data/app/views/thredded/theme_previews/_section_title.html.erb +3 -0
  302. data/app/views/thredded/theme_previews/show.html.erb +99 -0
  303. data/app/views/thredded/topic_previews/preview.html.erb +1 -0
  304. data/app/views/thredded/topics/_followers.html.erb +12 -0
  305. data/app/views/thredded/topics/_form.html.erb +32 -0
  306. data/app/views/thredded/topics/_header.html.erb +32 -0
  307. data/app/views/thredded/topics/_sticky_topics_divider.html.erb +1 -0
  308. data/app/views/thredded/topics/_topic.html.erb +47 -0
  309. data/app/views/thredded/topics/_topic_form_admin_options.html.erb +12 -0
  310. data/app/views/thredded/topics/edit.html.erb +50 -0
  311. data/app/views/thredded/topics/index.html.erb +35 -0
  312. data/app/views/thredded/topics/new.html.erb +12 -0
  313. data/app/views/thredded/topics/search.html.erb +39 -0
  314. data/app/views/thredded/topics/show.html.erb +46 -0
  315. data/app/views/thredded/users/_link.html.erb +14 -0
  316. data/app/views/thredded/users/_post.html.erb +6 -0
  317. data/app/views/thredded/users/_posts.html.erb +7 -0
  318. data/bin/rails +6 -0
  319. data/config/i18n-tasks.yml +16 -0
  320. data/config/locales/de.yml +257 -0
  321. data/config/locales/en.yml +253 -0
  322. data/config/locales/es.yml +257 -0
  323. data/config/locales/fr.yml +255 -0
  324. data/config/locales/it.yml +257 -0
  325. data/config/locales/pl.yml +257 -0
  326. data/config/locales/pt-BR.yml +258 -0
  327. data/config/locales/ru.yml +255 -0
  328. data/config/locales/zh-CN.yml +246 -0
  329. data/config/routes.rb +87 -0
  330. data/db/migrate/20160329231848_create_thredded.rb +257 -0
  331. data/db/seeds.rb +4 -0
  332. data/db/upgrade_migrations/20160611094616_upgrade_v0_5_to_v0_6.rb +28 -0
  333. data/db/upgrade_migrations/20160723012349_upgrade_v0_6_to_v0_7.rb +46 -0
  334. data/db/upgrade_migrations/20161019150201_upgrade_v0_7_to_v0_8.rb +34 -0
  335. data/db/upgrade_migrations/20161113161801_upgrade_v0_8_to_v0_9.rb +60 -0
  336. data/db/upgrade_migrations/20170125033319_upgrade_v0_9_to_v0_10.rb +36 -0
  337. data/db/upgrade_migrations/20170312131417_upgrade_thredded_v0_10_to_v0_11.rb +23 -0
  338. data/db/upgrade_migrations/20170420163138_upgrade_thredded_v0_11_to_v0_12.rb +28 -0
  339. data/db/upgrade_migrations/20170811090735_upgrade_thredded_v0_13_to_v_014.rb +21 -0
  340. data/lib/generators/thredded/install/USAGE +8 -0
  341. data/lib/generators/thredded/install/install_generator.rb +20 -0
  342. data/lib/generators/thredded/install/templates/initializer.rb +160 -0
  343. data/lib/tasks/thredded_tasks.rake +14 -0
  344. data/lib/thredded.rb +190 -0
  345. data/lib/thredded/base_migration.rb +14 -0
  346. data/lib/thredded/base_notifier.rb +28 -0
  347. data/lib/thredded/collection_to_strings_with_cache_renderer.rb +86 -0
  348. data/lib/thredded/content_formatter.rb +129 -0
  349. data/lib/thredded/database_seeder.rb +290 -0
  350. data/lib/thredded/db_tools.rb +103 -0
  351. data/lib/thredded/email_transformer.rb +22 -0
  352. data/lib/thredded/email_transformer/base.rb +47 -0
  353. data/lib/thredded/email_transformer/onebox.rb +21 -0
  354. data/lib/thredded/engine.rb +28 -0
  355. data/lib/thredded/errors.rb +68 -0
  356. data/lib/thredded/formatting_demo_content.rb +30 -0
  357. data/lib/thredded/html_pipeline/at_mention_filter.rb +78 -0
  358. data/lib/thredded/html_pipeline/autolink_filter.rb +15 -0
  359. data/lib/thredded/html_pipeline/kramdown_filter.rb +39 -0
  360. data/lib/thredded/html_pipeline/onebox_filter.rb +143 -0
  361. data/lib/thredded/html_pipeline/wrap_iframes_filter.rb +13 -0
  362. data/lib/thredded/version.rb +5 -0
  363. data/lib/thredded/view_hooks/config.rb +37 -0
  364. data/lib/thredded/view_hooks/renderer.rb +30 -0
  365. data/vendor/assets/javascripts/autosize.min.js +6 -0
  366. data/vendor/assets/javascripts/textcomplete.min.js +2 -0
  367. metadata +1035 -0
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thredded/base_migration'
4
+
5
+ # rubocop:disable Metrics/MethodLength
6
+ class UpgradeV08ToV09 < Thredded::BaseMigration
7
+ def up
8
+ create_table :thredded_notifications_for_private_topics do |t|
9
+ t.references :user, null: false, index: false, type: user_id_type
10
+ t.string :notifier_key, null: false, limit: 90
11
+ t.boolean :enabled, default: true, null: false
12
+ t.index %i[user_id notifier_key],
13
+ name: 'thredded_notifications_for_private_topics_unique', unique: true
14
+ end
15
+ create_table :thredded_notifications_for_followed_topics do |t|
16
+ t.references :user, null: false, index: false, type: user_id_type
17
+ t.string :notifier_key, null: false, limit: 90
18
+ t.boolean :enabled, default: true, null: false
19
+ t.index %i[user_id notifier_key],
20
+ name: 'thredded_notifications_for_followed_topics_unique', unique: true
21
+ end
22
+ create_table :thredded_messageboard_notifications_for_followed_topics do |t|
23
+ t.references :user, null: false, index: false, type: user_id_type
24
+ t.references :messageboard, null: false, index: false, type: column_type(:thredded_messageboards, :id)
25
+ t.string :notifier_key, null: false, limit: 90
26
+ t.boolean :enabled, default: true, null: false
27
+ t.index %i[user_id messageboard_id notifier_key],
28
+ name: 'thredded_messageboard_notifications_for_followed_topics_unique', unique: true
29
+ end
30
+
31
+ Thredded::UserPreference.all.each do |pref|
32
+ pref.notifications_for_private_topics.create(notifier_key: 'email', enabled: pref.notify_on_message)
33
+ pref.notifications_for_followed_topics.create(notifier_key: 'email', enabled: pref.followed_topic_emails)
34
+ end
35
+ Thredded::UserMessageboardPreference.pluck(:user_id, :messageboard_id, :followed_topic_emails)
36
+ .each do |user_id, messageboard_id, emails|
37
+ Thredded::MessageboardNotificationsForFollowedTopics.create(
38
+ user_id: user_id,
39
+ messageboard_id: messageboard_id,
40
+ notifier_key: 'email',
41
+ enabled: emails
42
+ )
43
+ end
44
+
45
+ remove_column :thredded_user_preferences, :notify_on_message
46
+ remove_column :thredded_user_preferences, :followed_topic_emails
47
+ remove_column :thredded_user_messageboard_preferences, :followed_topic_emails
48
+ end
49
+
50
+ def down
51
+ add_column :thredded_user_preferences, :notify_on_message, :boolean, default: true, null: false
52
+ add_column :thredded_user_preferences, :followed_topic_emails, :boolean, default: true, null: false
53
+ add_column :thredded_user_messageboard_preferences, :followed_topic_emails, :boolean, default: true, null: false
54
+
55
+ drop_table :thredded_messageboard_notifications_for_followed_topics
56
+ drop_table :thredded_notifications_for_followed_topics
57
+ drop_table :thredded_notifications_for_private_topics
58
+ end
59
+ end
60
+ # rubocop:enable Metrics/MethodLength
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thredded/base_migration'
4
+
5
+ class UpgradeV09ToV010 < Thredded::BaseMigration
6
+ def up
7
+ remove_foreign_key :thredded_messageboard_users, :thredded_messageboards
8
+ add_foreign_key :thredded_messageboard_users, :thredded_messageboards,
9
+ column: :thredded_messageboard_id, on_delete: :cascade
10
+ remove_foreign_key :thredded_messageboard_users, :thredded_user_details
11
+ add_foreign_key :thredded_messageboard_users, :thredded_user_details,
12
+ column: :thredded_user_detail_id, on_delete: :cascade
13
+
14
+ create_table :thredded_user_post_notifications do |t|
15
+ t.references :user, null: false, index: false, type: user_id_type
16
+ t.references :post, null: false, index: false, type: column_type(:thredded_posts, :id)
17
+ t.datetime :notified_at, null: false
18
+ t.index :post_id, name: :index_thredded_user_post_notifications_on_post_id
19
+ t.index %i[user_id post_id], name: :index_thredded_user_post_notifications_on_user_id_and_post_id, unique: true
20
+ end
21
+
22
+ add_foreign_key :thredded_user_post_notifications,
23
+ Thredded.user_class.table_name, column: :user_id, on_delete: :cascade
24
+ add_foreign_key :thredded_user_post_notifications,
25
+ :thredded_posts, column: :post_id, on_delete: :cascade
26
+ end
27
+
28
+ def down
29
+ drop_table :thredded_user_post_notifications
30
+
31
+ remove_foreign_key :thredded_messageboard_users, :thredded_user_details
32
+ add_foreign_key :thredded_messageboard_users, :thredded_user_details
33
+ remove_foreign_key :thredded_messageboard_users, :thredded_messageboards
34
+ add_foreign_key :thredded_messageboard_users, :thredded_messageboards
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thredded/base_migration'
4
+
5
+ class UpgradeThreddedV010ToV011 < Thredded::BaseMigration
6
+ def up
7
+ drop_table :thredded_post_notifications
8
+ add_column :thredded_user_preferences, :auto_follow_topics, :boolean, default: false, null: false
9
+ add_column :thredded_user_messageboard_preferences, :auto_follow_topics, :boolean, default: false, null: false
10
+ end
11
+
12
+ def down
13
+ remove_column :thredded_user_messageboard_preferences, :auto_follow_topics
14
+ remove_column :thredded_user_preferences, :auto_follow_topics
15
+ create_table :thredded_post_notifications do |t|
16
+ t.string :email, limit: 191, null: false
17
+ t.references :post, null: false, index: false
18
+ t.timestamps null: false
19
+ t.string :post_type, limit: 191
20
+ t.index %i[post_id post_type], name: :index_thredded_post_notifications_on_post
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thredded/base_migration'
4
+
5
+ class UpgradeThreddedV011ToV012 < Thredded::BaseMigration
6
+ def up
7
+ FriendlyId::Slug.transaction do
8
+ FriendlyId::Slug.where(sluggable_type: 'Thredded::Topic').where(
9
+ slug: FriendlyId::Slug.group(:slug).having('count(id) > 1').select(:slug)
10
+ ).group_by(&:slug).each_value do |slugs|
11
+ slugs.from(1).each(&:delete)
12
+ end
13
+ FriendlyId::Slug.where(sluggable_type: 'Thredded::Topic')
14
+ .update_all(scope: nil)
15
+ end
16
+ Thredded::Topic.all.find_each do |topic|
17
+ # re-generate the slug
18
+ topic.title_will_change!
19
+ topic.save!
20
+ end
21
+ remove_index :thredded_topics, name: :index_thredded_topics_on_messageboard_id_and_slug
22
+ add_index :thredded_topics, [:slug], name: :index_thredded_topics_on_slug, unique: true
23
+ end
24
+
25
+ def down
26
+ fail ActiveRecord::MigrationError::IrreversibleMigration
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thredded/base_migration'
4
+
5
+ class UpgradeThreddedV013ToV014 < Thredded::BaseMigration
6
+ def change
7
+ add_column :thredded_messageboards, :locked, :boolean, null: false, default: false
8
+ remove_index :thredded_user_details,
9
+ name: :index_thredded_user_details_on_user_id
10
+ add_index :thredded_user_details,
11
+ :user_id,
12
+ name: :index_thredded_user_details_on_user_id,
13
+ unique: true
14
+ remove_index :thredded_user_preferences,
15
+ name: :index_thredded_user_preferences_on_user_id
16
+ add_index :thredded_user_preferences,
17
+ :user_id,
18
+ name: :index_thredded_user_preferences_on_user_id,
19
+ unique: true
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Create an initializer with description of configuration and defaults.
3
+
4
+ Example:
5
+ rails generate thredded:install
6
+
7
+ This will create:
8
+ config/initializers/thredded.rb
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ def set_source_paths
7
+ @source_paths = [
8
+ File.expand_path('../templates', __FILE__),
9
+ File.expand_path('../../../../..', __FILE__),
10
+ ]
11
+ end
12
+
13
+ def copy_initializer_file
14
+ copy_file \
15
+ 'initializer.rb',
16
+ 'config/initializers/thredded.rb'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Thredded configuration
4
+
5
+ # ==> User Configuration
6
+ # The name of the class your app uses for your users.
7
+ # By default the engine will use 'User' but if you have another name
8
+ # for your user class - change it here.
9
+ Thredded.user_class = 'User'
10
+
11
+ # User name column, used in @mention syntax and *must* be unique.
12
+ # This is the column used to search for users' names if/when someone is @ mentioned.
13
+ Thredded.user_name_column = :name
14
+
15
+ # User display name method, by default thredded uses the user_name_column defined above
16
+ # You may want to use :to_s or some more elaborate method
17
+ # Thredded.user_display_name_method = :to_s
18
+
19
+ # The path (or URL) you will use to link to your users' profiles.
20
+ # When linking to a user, Thredded will use this lambda to spit out
21
+ # the path or url to your user. This lambda is evaluated in the view context.
22
+ # If the lambda returns nil, a span element is returned instead of a link; so
23
+ # setting this to always return nil effectively disables all user links.
24
+ Thredded.user_path = lambda do |user|
25
+ user_path = :"#{Thredded.user_class_name.demodulize.underscore}_path"
26
+ main_app.respond_to?(user_path) ? main_app.send(user_path, user) : "/users/#{user.to_param}"
27
+ end
28
+
29
+ # This method is used by Thredded controllers and views to fetch the currently signed-in user
30
+ Thredded.current_user_method = :"current_#{Thredded.user_class_name.demodulize.underscore}"
31
+
32
+ # User avatar URL. rb-gravatar gem is used by default:
33
+ Thredded.avatar_url = ->(user) { Gravatar.src(user.email, 156, 'mm') }
34
+
35
+ # ==> Database Configuration
36
+ # By default, thredded uses integers for record ID route constraints.
37
+ # For integer based IDs (default):
38
+ # Thredded.routes_id_constraint = /[1-9]\d*/
39
+ # For UUID based IDs (example):
40
+ # Thredded.routes_id_constraint = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/
41
+
42
+ # ==> Permissions Configuration
43
+ # By default, thredded uses a simple permission model, where all the users can post to all message boards,
44
+ # and admins and moderators are determined by a flag on the users table.
45
+
46
+ # The name of the moderator flag column on the users table.
47
+ Thredded.moderator_column = :admin
48
+ # The name of the admin flag column on the users table.
49
+ Thredded.admin_column = :admin
50
+
51
+ # Whether posts and topics pending moderation are visible to regular users.
52
+ Thredded.content_visible_while_pending_moderation = true
53
+
54
+ # Whether users that are following a topic are listed on topic page.
55
+ Thredded.show_topic_followers = false
56
+
57
+ # This model can be customized further by overriding a handful of methods on the User model.
58
+ # For more information, see app/models/thredded/user_extender.rb.
59
+
60
+ # ==> Ordering configuration
61
+
62
+ # How to calculate the position of messageboards in a list:
63
+ # :position (default) set the position manually (new messageboards go to the bottom, by creation timestamp)
64
+ # :last_post_at_desc most recent post first
65
+ # :topics_count_desc most topics first
66
+ Thredded.messageboards_order = :position
67
+
68
+ # ==> Email Configuration
69
+ # Email "From:" field will use the following
70
+ # Thredded.email_from = 'no-reply@example.com'
71
+
72
+ # Emails going out will prefix the "Subject:" with the following string
73
+ # Thredded.email_outgoing_prefix = '[My Forum] '
74
+ #
75
+ # The parent mailer for all Thredded mailers
76
+ # Thredded.parent_mailer = 'ActionMailer::Base'
77
+
78
+ # ==> View Configuration
79
+ # Set the layout for rendering the thredded views.
80
+ Thredded.layout = 'thredded/application'
81
+
82
+ # ==> URLs
83
+ # How Thredded generates URL slugs from text.
84
+
85
+ # Default:
86
+ # Thredded.slugifier = ->(input) { input.parameterize }
87
+
88
+ # If your forum is in a language other than English, you might want to use the babosa gem instead
89
+ # Thredded.slugifier = ->(input) { Babosa::Identifier.new(input).normalize.transliterate(:russian).to_s }
90
+
91
+ # ==> Post Content Formatting
92
+ # Customize the way Thredded handles post formatting.
93
+
94
+ # Change the default html-pipeline filters used by thredded.
95
+ # E.g. to replace default emoji filter with your own:
96
+ # Thredded::ContentFormatter.after_markup_filters[
97
+ # Thredded::ContentFormatter.after_markup_filters.index(HTML::Pipeline::EmojiFilter)] = MyEmojiFilter
98
+
99
+ # Change the HTML sanitization settings used by Thredded.
100
+ # See the Sanitize docs for more information on the underlying library: https://github.com/rgrove/sanitize/#readme
101
+ # E.g. to allow a custom element <custom-element>:
102
+ # Thredded::ContentFormatter.whitelist[:elements] += %w(custom-element)
103
+
104
+ # ==> User autocompletion (Private messages and @-mentions)
105
+ # Thredded.autocomplete_min_length = 2 lower to 1 if have 1-letter names -- increase if you want
106
+
107
+ # ==> Error Handling
108
+ # By default Thredded just renders a flash alert on errors such as Topic not found, or Login required.
109
+ # Below is an example of overriding the default behavior on LoginRequired:
110
+ #
111
+ # Rails.application.config.to_prepare do
112
+ # Thredded::ApplicationController.module_eval do
113
+ # rescue_from Thredded::Errors::LoginRequired do |exception|
114
+ # @message = exception.message
115
+ # render template: 'sessions/new', status: :forbidden
116
+ # end
117
+ # end
118
+ # end
119
+
120
+ # ==> View hooks
121
+ #
122
+ # Customize the UI before/after/replacing individual components.
123
+ # See the full list of view hooks and their arguments by running:
124
+ #
125
+ # $ grep view_hooks -R --include '*.html.erb' "$(bundle show thredded)"
126
+ #
127
+ # Rails.application.config.to_prepare do
128
+ # Thredded.view_hooks.post_form.content_text_area.config.before do |form:, **args|
129
+ # # This is called in the Thredded view context, so all Thredded helpers and URLs are accessible here directly.
130
+ # 'hi'
131
+ # end
132
+ # end
133
+
134
+ # ==> Topic following
135
+ #
136
+ # By default, a user will be subscribed to a topic they've created. Uncomment this to not subscribe them:
137
+ #
138
+ # Thredded.auto_follow_when_creating_topic = false
139
+ #
140
+ # By default, a user will be subscribed to (follow) a topic they post in. Uncomment this to not subscribe them:
141
+ #
142
+ # Thredded.auto_follow_when_posting_in_topic = false
143
+ #
144
+ # By default, a user will be subscribed to the topic they get @-mentioned in.
145
+ # Individual users can disable this in the Notification Settings.
146
+ # To change the default for all users, simply change the default value of the `follow_topics_on_mention` column
147
+ # of the `thredded_user_preferences` and `thredded_user_messageboard_preferences` tables.
148
+
149
+ # ==> Notifiers
150
+ #
151
+ # Change how users can choose to be notified, by adding notifiers here, or removing the initializer altogether
152
+ #
153
+ # default:
154
+ # Thredded.notifiers = [Thredded::EmailNotifier.new]
155
+ #
156
+ # none:
157
+ # Thredded.notifiers = []
158
+ #
159
+ # add in (must install separate gem (under development) as well):
160
+ # Thredded.notifiers = [Thredded::EmailNotifier.new, Thredded::PushoverNotifier.new(ENV['PUSHOVER_APP_ID'])]
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :thredded do
4
+ namespace :install do
5
+ desc 'Copy emoji to the Rails `public/emoji` directory'
6
+ task :emoji do
7
+ require 'emoji'
8
+
9
+ target = Rails.application.root.join('public')
10
+ STDERR.puts "Copying emoji to #{target}"
11
+ `mkdir -p '#{target}' && cp -Rp '#{Emoji.images_path}/emoji' '#{target}'`
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Backend
4
+ require 'pundit'
5
+ require 'active_record_union'
6
+ require 'db_text_search'
7
+ require 'friendly_id'
8
+ require 'html/pipeline'
9
+ require 'html/pipeline/sanitization_filter'
10
+ require 'rinku'
11
+ require 'kaminari'
12
+ require 'rb-gravatar'
13
+ require 'active_job'
14
+ require 'inline_svg'
15
+
16
+ # Require these explictly to make sure they are not reloaded.
17
+ # This allows for configuring them by accessing class methods in the initializer.
18
+ require 'thredded/formatting_demo_content'
19
+ require 'thredded/html_pipeline/at_mention_filter'
20
+ require 'thredded/html_pipeline/autolink_filter'
21
+ require 'thredded/html_pipeline/kramdown_filter'
22
+ require 'thredded/html_pipeline/onebox_filter'
23
+ require 'thredded/html_pipeline/wrap_iframes_filter'
24
+
25
+ # Asset compilation
26
+ require 'autoprefixer-rails'
27
+ require 'timeago_js'
28
+ require 'sprockets/es6'
29
+
30
+ require 'thredded/version'
31
+ require 'thredded/engine'
32
+ require 'thredded/errors'
33
+
34
+ require 'thredded/view_hooks/config'
35
+ require 'thredded/view_hooks/renderer'
36
+
37
+ # Require these explicitly so that they do not need to be required if used in the initializer:
38
+ require 'thredded/content_formatter'
39
+ require 'thredded/email_transformer'
40
+ require 'thredded/base_notifier'
41
+
42
+ require 'thredded/collection_to_strings_with_cache_renderer'
43
+
44
+ module Thredded
45
+ mattr_accessor \
46
+ :autocomplete_min_length,
47
+ :active_user_threshold,
48
+ :avatar_url,
49
+ :email_from,
50
+ :email_outgoing_prefix,
51
+ :layout,
52
+ :messageboards_order,
53
+ :routes_id_constraint,
54
+ :user_display_name_method,
55
+ :user_name_column,
56
+ :user_path
57
+
58
+ # @return [Symbol] The name of the method used by Thredded controllers and views to fetch the currently signed-in user
59
+ mattr_accessor :current_user_method
60
+
61
+ # @return [Symbol] The name of the moderator flag column on the users table for the default permissions model
62
+ mattr_accessor :moderator_column
63
+
64
+ # @return [Symbol] The name of the admin flag column on the users table for the default permissions model
65
+ mattr_accessor :admin_column
66
+
67
+ # @return [Boolean] Whether posts that are pending moderation are visible to regular users.
68
+ mattr_accessor :content_visible_while_pending_moderation
69
+
70
+ # @return [Array] The notifiers, by default just the EmailNotifier
71
+ mattr_accessor :notifiers
72
+
73
+ # @return [Boolean] Whether users that are following a topic are listed on topic page.
74
+ mattr_accessor :show_topic_followers
75
+
76
+ # @return [Symbol] The name of the method used by Thredded to display users
77
+ mattr_accessor :user_display_name_method
78
+
79
+ # @return [String] The name of the parent mailer class for Thredded mailers.
80
+ mattr_accessor :parent_mailer
81
+ self.parent_mailer = 'ActionMailer::Base'
82
+
83
+ # @return [Proc] The proc that Thredded uses to generate URL slugs from text.
84
+ mattr_accessor :slugifier
85
+ self.slugifier = ->(input) { input.parameterize }
86
+
87
+ # @return [Boolean] Whether the user should get subscribed to a new topic they've created.
88
+ mattr_accessor :auto_follow_when_creating_topic
89
+ self.auto_follow_when_creating_topic = true
90
+
91
+ # @return [Boolean] Whether the user should get subscribed to a topic after posting in it.
92
+ mattr_accessor :auto_follow_when_posting_in_topic
93
+ self.auto_follow_when_posting_in_topic = true
94
+
95
+ # @return [String] The name of the user class
96
+ mattr_reader :user_class_name
97
+
98
+ self.active_user_threshold = 5.minutes
99
+ self.admin_column = :admin
100
+ self.avatar_url = ->(user) { Gravatar.src(user.email, 156, 'mm') }
101
+ self.layout = 'thredded/application'
102
+ self.moderator_column = :admin
103
+ self.user_name_column = :name
104
+ self.content_visible_while_pending_moderation = true
105
+ self.show_topic_followers = false
106
+ self.messageboards_order = :position
107
+ self.autocomplete_min_length = 2
108
+ self.routes_id_constraint = /[1-9]\d*/
109
+
110
+ # @return [Thredded::AllViewHooks] View hooks configuration.
111
+ def self.view_hooks
112
+ instance = Thredded::AllViewHooks.instance
113
+ unless instance
114
+ fail '`Thredded.view_hooks` must be configured in a `Rails.application.config.to_prepare` block!'
115
+ end
116
+ instance
117
+ end
118
+
119
+ def self.notifiers
120
+ @@notifiers ||= [Thredded::EmailNotifier.new] # rubocop:disable Style/ClassVars
121
+ end
122
+
123
+ def self.notifiers=(notifiers)
124
+ notifiers.each { |notifier| BaseNotifier.validate_notifier(notifier) }
125
+ @@notifiers = notifiers # rubocop:disable Style/ClassVars
126
+ end
127
+
128
+ def self.user_display_name_method
129
+ @@user_display_name_method || user_name_column
130
+ end
131
+
132
+ # @param value [:position, :topics_count_desc, :last_post_at_desc]
133
+ def self.messageboards_order=(value)
134
+ case value
135
+ when :position, :topics_count_desc, :last_post_at_desc
136
+ @@messageboards_order = value # rubocop:disable Style/ClassVars
137
+ else
138
+ fail ArgumentError, "Unexpected value for Thredded.messageboards_order: #{value}"
139
+ end
140
+ end
141
+
142
+ # @param user_class_name [String]
143
+ def self.user_class=(user_class_name)
144
+ unless user_class_name.is_a?(String)
145
+ fail "Thredded.user_class must be set to a String, got #{user_class_name.inspect}"
146
+ end
147
+ @@user_class_name = user_class_name # rubocop:disable Style/ClassVars
148
+ end
149
+
150
+ # @return [Class<Thredded::UserExtender>] the user class from the host application.
151
+ def self.user_class
152
+ # This is nil before the initializer is installed.
153
+ return nil if @@user_class_name.nil?
154
+ @@user_class_name.constantize
155
+ end
156
+
157
+ # @param view_context [Object] context to execute the lambda in.
158
+ # @param user [Thredded.user_class]
159
+ # @return [String] path to the user evaluated in the specified context.
160
+ def self.user_path(view_context, user)
161
+ view_context.instance_exec(user, &@@user_path)
162
+ end
163
+
164
+ # Whether the layout is a thredded layout as opposed to the application layout.
165
+ def self.standalone_layout?
166
+ layout.is_a?(String) && layout.start_with?('thredded/')
167
+ end
168
+
169
+ # Returns a view for the given posts' scope, applying read permission filters to the scope.
170
+ # Can be used in main_app, e.g. for showing the recent user posts on the profile page.
171
+ #
172
+ # @param scope [ActiveRecord::Relation<Thredded::Post>] the posts scope for which to return the view.
173
+ # @param current_user [Thredded.user_class, nil] the user viewing the posts.
174
+ # @return [PostsPageView]
175
+ def self.posts_page_view(scope:, current_user:)
176
+ current_user ||= Thredded::NullUser.new
177
+ PostsPageView.new(
178
+ current_user,
179
+ Pundit.policy_scope!(current_user, scope)
180
+ .where(messageboard_id: Pundit.policy_scope!(current_user, Thredded::Messageboard.all).pluck(:id))
181
+ .includes(:postable)
182
+ )
183
+ end
184
+
185
+ # @api private
186
+ def self.rails_gte_51?
187
+ @rails_gte_51 = (Rails.gem_version >= Gem::Version.new('5.1.0')) if @rails_gte_51.nil?
188
+ @rails_gte_51
189
+ end
190
+ end