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,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserExtender
5
+ extend ActiveSupport::Concern
6
+
7
+ include ::Thredded::UserPermissions::Read::All
8
+ include ::Thredded::UserPermissions::Write::All
9
+ include ::Thredded::UserPermissions::Message::ReadersOfWriteableBoards
10
+ include ::Thredded::UserPermissions::Moderate::IfModeratorColumnTrue
11
+ include ::Thredded::UserPermissions::Admin::IfAdminColumnTrue
12
+
13
+ included do # rubocop:disable Metrics/BlockLength
14
+ with_options dependent: :nullify, foreign_key: 'user_id', inverse_of: :user do |opt|
15
+ opt.has_many :thredded_posts, class_name: 'Thredded::Post'
16
+ opt.has_many :thredded_topics, class_name: 'Thredded::Topic'
17
+ opt.has_many :thredded_private_posts, class_name: 'Thredded::PrivatePost'
18
+ opt.has_many :thredded_started_private_topics, class_name: 'Thredded::PrivateTopic'
19
+ end
20
+
21
+ with_options dependent: :nullify, foreign_key: 'last_user_id', inverse_of: :last_user do |opt|
22
+ opt.has_many :thredded_last_user_topics, class_name: 'Thredded::Topic'
23
+ opt.has_many :thredded_last_user_private_topics, class_name: 'Thredded::PrivateTopic'
24
+ end
25
+
26
+ with_options dependent: :destroy, foreign_key: 'user_id', inverse_of: :user do |opt|
27
+ opt.has_many :thredded_user_messageboard_preferences, class_name: 'Thredded::UserMessageboardPreference'
28
+ opt.has_many :thredded_notifications_for_followed_topics, class_name: 'Thredded::NotificationsForFollowedTopics'
29
+ opt.has_many :thredded_notifications_for_private_topics, class_name: 'Thredded::NotificationsForPrivateTopics'
30
+ opt.has_many :thredded_post_notifications, class_name: 'Thredded::UserPostNotification'
31
+ opt.has_many :thredded_private_users, class_name: 'Thredded::PrivateUser'
32
+ opt.has_many :thredded_topic_read_states, class_name: 'Thredded::UserTopicReadState'
33
+ opt.has_many :thredded_private_topic_read_states, class_name: 'Thredded::UserPrivateTopicReadState'
34
+ opt.has_many :thredded_topic_follows, class_name: 'Thredded::UserTopicFollow'
35
+ opt.has_one :thredded_user_detail, class_name: 'Thredded::UserDetail'
36
+ opt.has_one :thredded_user_preference, class_name: 'Thredded::UserPreference'
37
+ end
38
+
39
+ has_many :thredded_private_topics,
40
+ through: :thredded_private_users,
41
+ class_name: 'Thredded::PrivateTopic',
42
+ source: :private_topic
43
+
44
+ with_options dependent: :nullify, class_name: 'Thredded::PostModerationRecord' do |opt|
45
+ opt.has_many :thredded_post_moderation_records, foreign_key: 'post_user_id', inverse_of: :post_user
46
+ opt.has_many :thredded_post_moderated_records, foreign_key: 'moderator_id', inverse_of: :moderator
47
+ end
48
+
49
+ scope :left_join_thredded_user_details, (lambda do
50
+ users = arel_table
51
+ user_details = Thredded::UserDetail.arel_table
52
+ joins(users.join(user_details, Arel::Nodes::OuterJoin)
53
+ .on(users[:id].eq(user_details[:user_id])).join_sources)
54
+ end)
55
+ end
56
+
57
+ def thredded_user_preference
58
+ super || build_thredded_user_preference
59
+ end
60
+
61
+ def thredded_user_detail
62
+ super || build_thredded_user_detail
63
+ end
64
+
65
+ def thredded_anonymous?
66
+ false
67
+ end
68
+
69
+ def thredded_display_name
70
+ send(Thredded.user_display_name_method).presence || fail(<<-ERROR)
71
+ User.#{Thredded.user_display_name_method} must not be empty: please set make sure non nil or configure Thredded.user_display_name_method")
72
+ ERROR
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class UserMessageboardPreference < ActiveRecord::Base
5
+ belongs_to :user_preference,
6
+ primary_key: :user_id,
7
+ foreign_key: :user_id,
8
+ inverse_of: :messageboard_preferences
9
+ belongs_to :user,
10
+ class_name: Thredded.user_class_name,
11
+ inverse_of: :thredded_user_messageboard_preferences
12
+ belongs_to :messageboard
13
+
14
+ validates :user_id, presence: true
15
+ validates :messageboard_id, presence: true
16
+
17
+ after_initialize :set_auto_follow_from_user_preference, unless: :persisted?
18
+
19
+ scope :auto_followers, -> { where(auto_follow_topics: true) }
20
+
21
+ def self.in(messageboard)
22
+ find_or_initialize_by(messageboard_id: messageboard.id)
23
+ end
24
+
25
+ def user_preference
26
+ super || build_user_preference
27
+ end
28
+
29
+ def user_id=(value)
30
+ super
31
+ set_auto_follow_from_user_preference
32
+ end
33
+
34
+ def user=(value)
35
+ super
36
+ set_auto_follow_from_user_preference
37
+ end
38
+
39
+ private
40
+
41
+ def set_auto_follow_from_user_preference
42
+ self.auto_follow_topics = user_preference.auto_follow_topics if user_id && !id
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Admin
6
+ module IfAdminColumnTrue
7
+ # @return [boolean] Whether this user has full admin rights on Thredded.
8
+ def thredded_admin?
9
+ send(Thredded.admin_column)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Admin
6
+ module None
7
+ # @return [boolean] Whether this user has full admin rights on Thredded.
8
+ def thredded_admin?
9
+ false
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Message
6
+ module ReadersOfWriteableBoards
7
+ # @return [ActiveRecord::Relation<Thredded.user_class>] the users this user can include in a private topic
8
+ def thredded_can_message_users
9
+ # By default, return everyone who can read the messageboards this user can post in
10
+ Thredded.user_class.thredded_messageboards_readers(thredded_can_write_messageboards)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Moderate
6
+ module IfModeratorColumnTrue
7
+ extend ActiveSupport::Concern
8
+
9
+ # @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can moderate
10
+ def thredded_can_moderate_messageboards
11
+ send(Thredded.moderator_column) ? Thredded::Messageboard.all : Thredded::Messageboard.none
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Moderate
6
+ module None
7
+ extend ActiveSupport::Concern
8
+
9
+ # @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can moderate
10
+ def thredded_can_moderate_messageboards
11
+ Thredded::Messageboard.none
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Read
6
+ module All
7
+ extend ActiveSupport::Concern
8
+ included { extend ClassMethods }
9
+
10
+ # @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can read
11
+ def thredded_can_read_messageboards
12
+ Thredded::Messageboard.all
13
+ end
14
+
15
+ module ClassMethods
16
+ # Users that can read some of the given messageboards.
17
+ #
18
+ # @param _messageboards [Array<Thredded::Messageboard>]
19
+ # @return [ActiveRecord::Relation<Thredded.user_class>] users that can read the given messageboards
20
+ def thredded_messageboards_readers(_messageboards)
21
+ all
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Write
6
+ module All
7
+ extend ActiveSupport::Concern
8
+
9
+ # @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can post in
10
+ def thredded_can_write_messageboards
11
+ Thredded::Messageboard.all
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module UserPermissions
5
+ module Write
6
+ module None
7
+ extend ActiveSupport::Concern
8
+
9
+ # @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can post in
10
+ def thredded_can_write_messageboards
11
+ Thredded::Messageboard.none
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ # Delivery records for Thredded::Post notifications.
5
+ class UserPostNotification < ActiveRecord::Base
6
+ belongs_to :user, class_name: Thredded.user_class_name, inverse_of: :thredded_post_notifications
7
+ belongs_to :post, class_name: 'Thredded::Post', inverse_of: :user_notifications
8
+
9
+ # @param post [Thredded::Post]
10
+ # @return [Array<Integer>] The IDs of users who were already notified about the given post.
11
+ def self.notified_user_ids(post)
12
+ where(post_id: post.id).pluck(:user_id)
13
+ end
14
+
15
+ # Create a user-post notification record for a given post and a user.
16
+ # @param post [Thredded::Post]
17
+ # @param user [Thredded.user_class]
18
+ # @return [Boolean] true if a new record was created, false otherwise (e.g. if a record had already existed).
19
+ def self.create_from_post_and_user(post, user)
20
+ create(
21
+ post_id: post.id,
22
+ user_id: user.id,
23
+ notified_at: Time.zone.now
24
+ )
25
+ rescue ActiveRecord::RecordNotUnique
26
+ false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class UserPreference < ActiveRecord::Base
5
+ belongs_to :user, class_name: Thredded.user_class_name, inverse_of: :thredded_user_preference
6
+
7
+ with_options(inverse_of: :user_preference, primary_key: :user_id, foreign_key: :user_id,
8
+ dependent: :destroy) do |opt|
9
+ opt.has_many :messageboard_preferences,
10
+ class_name: 'Thredded::UserMessageboardPreference'
11
+ opt.has_many :messageboard_notifications_for_followed_topics,
12
+ class_name: 'Thredded::MessageboardNotificationsForFollowedTopics'
13
+ opt.has_many :notifications_for_followed_topics,
14
+ class_name: 'Thredded::NotificationsForFollowedTopics'
15
+ opt.has_many :notifications_for_private_topics,
16
+ class_name: 'Thredded::NotificationsForPrivateTopics'
17
+ end
18
+ validates :user_id, presence: true
19
+
20
+ scope :auto_followers, -> { where(auto_follow_topics: true) }
21
+
22
+ accepts_nested_attributes_for :notifications_for_followed_topics,
23
+ :notifications_for_private_topics,
24
+ :messageboard_notifications_for_followed_topics
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class UserPrivateTopicReadState < ActiveRecord::Base
5
+ include Thredded::UserTopicReadStateCommon
6
+ belongs_to :user,
7
+ class_name: Thredded.user_class_name,
8
+ inverse_of: :thredded_private_topic_read_states
9
+ belongs_to :postable,
10
+ class_name: 'Thredded::PrivateTopic',
11
+ inverse_of: :user_read_states
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class UserTopicFollow < ActiveRecord::Base
5
+ enum reason: %i[manual posted mentioned auto]
6
+
7
+ belongs_to :user, inverse_of: :thredded_topic_follows, class_name: Thredded.user_class_name
8
+ belongs_to :topic, inverse_of: :user_follows
9
+
10
+ validates :user_id, presence: true
11
+ validates :topic_id, presence: true
12
+
13
+ # shim to behave like postable-related (though actually only ever related to topic)
14
+ alias_attribute :postable_id, :topic_id
15
+ alias_attribute :postable, :topic
16
+
17
+ # Creates a follow or finds the existing one.
18
+ #
19
+ # This method is safe to call concurrently from different processes. Lookup and creation happen in a transaction.
20
+ # If an ActiveRecord::RecordNotUnique error is raised, the find is retried.
21
+ #
22
+ # @return [Thredded::UserTopicFollow]
23
+ def self.create_unless_exists(user_id, topic_id, reason = :manual)
24
+ uncached do
25
+ transaction(requires_new: true) do
26
+ create_with(reason: reason).find_or_create_by(user_id: user_id, topic_id: topic_id)
27
+ end
28
+ end
29
+ rescue ActiveRecord::RecordNotUnique
30
+ # The record has been created from another connection, retry to find it.
31
+ retry
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class UserTopicReadState < ActiveRecord::Base
5
+ include Thredded::UserTopicReadStateCommon
6
+ belongs_to :user,
7
+ class_name: Thredded.user_class_name,
8
+ inverse_of: :thredded_topic_read_states
9
+ belongs_to :postable,
10
+ class_name: 'Thredded::Topic',
11
+ inverse_of: :user_read_states
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class EmailNotifier
5
+ def initialize
6
+ fail 'Please set Thredded.email_from in config/initializers/thredded.rb' if Thredded.email_from.blank?
7
+ end
8
+
9
+ def human_name
10
+ I18n.t('thredded.email_notifier.by_email')
11
+ end
12
+
13
+ def key
14
+ 'email'
15
+ end
16
+
17
+ def new_post(post, users)
18
+ Thredded::PostMailer.post_notification(post.id, users.map(&:email)).deliver_now
19
+ end
20
+
21
+ def new_private_post(post, users)
22
+ Thredded::PrivateTopicMailer.message_notification(post.id, users.map(&:email)).deliver_now
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class MessageboardGroupPolicy
5
+ # @param user [Thredded.user_class]
6
+ # @param group [Thredded::MessageboardGroup]
7
+ def initialize(user, group)
8
+ @user = user
9
+ @group = group
10
+ end
11
+
12
+ def create?
13
+ @user.thredded_admin?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ class MessageboardPolicy
5
+ # The scope of readable messageboards
6
+ class Scope
7
+ # @param user [Thredded.user_class]
8
+ # @param scope [ActiveRecord::Relation<Thredded::Messageboard>]
9
+ def initialize(user, scope)
10
+ @user = user
11
+ @scope = scope
12
+ end
13
+
14
+ # @return [ActiveRecord::Relation<Thredded::Messageboards>]
15
+ def resolve
16
+ @scope.merge(@user.thredded_can_read_messageboards)
17
+ end
18
+ end
19
+
20
+ # @param user [Thredded.user_class]
21
+ # @param messageboard [Thredded::Messageboard]
22
+ def initialize(user, messageboard)
23
+ @user = user
24
+ @messageboard = messageboard
25
+ end
26
+
27
+ def create?
28
+ @user.thredded_admin?
29
+ end
30
+
31
+ def read?
32
+ @user.thredded_admin? || @user.thredded_can_read_messageboards.include?(@messageboard)
33
+ end
34
+
35
+ def update?
36
+ @user.thredded_admin?
37
+ end
38
+
39
+ def post?
40
+ @user.thredded_admin? ||
41
+ (!@messageboard.locked? || moderate?) &&
42
+ @user.thredded_can_write_messageboards.include?(@messageboard)
43
+ end
44
+
45
+ def moderate?
46
+ @user.thredded_admin? || @user.thredded_can_moderate_messageboards.include?(@messageboard)
47
+ end
48
+ end
49
+ end