rails_den 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +652 -0
  3. data/README.md +74 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/javascript/rails_den/attachments.js +733 -0
  6. data/app/assets/javascript/rails_den/bookmarks.js +58 -0
  7. data/app/assets/javascript/rails_den/cable.js +18 -0
  8. data/app/assets/javascript/rails_den/chat.js +3008 -0
  9. data/app/assets/javascript/rails_den/chat_3d_management.js +1230 -0
  10. data/app/assets/javascript/rails_den/composer.js +1785 -0
  11. data/app/assets/javascript/rails_den/content.js +1337 -0
  12. data/app/assets/javascript/rails_den/emoji_catalog.js +136 -0
  13. data/app/assets/javascript/rails_den/licenses/react-LICENSE.txt +21 -0
  14. data/app/assets/javascript/rails_den/licenses/react-dom-LICENSE.txt +21 -0
  15. data/app/assets/javascript/rails_den/licenses/scheduler-LICENSE.txt +21 -0
  16. data/app/assets/javascript/rails_den/licenses/three-LICENSE.txt +21 -0
  17. data/app/assets/javascript/rails_den/members.js +187 -0
  18. data/app/assets/javascript/rails_den/notifications.js +211 -0
  19. data/app/assets/javascript/rails_den/presence.js +757 -0
  20. data/app/assets/javascript/rails_den/private_messages.js +92 -0
  21. data/app/assets/javascript/rails_den/react_runtime.js +43 -0
  22. data/app/assets/javascript/rails_den/reactions.js +139 -0
  23. data/app/assets/javascript/rails_den/spatial.js +4338 -0
  24. data/app/assets/stylesheets/rails_den/advertising.css +91 -0
  25. data/app/assets/stylesheets/rails_den/application.css +1724 -0
  26. data/app/assets/stylesheets/rails_den/attachments.css +255 -0
  27. data/app/assets/stylesheets/rails_den/board_presence.css +38 -0
  28. data/app/assets/stylesheets/rails_den/bookmarks.css +36 -0
  29. data/app/assets/stylesheets/rails_den/chat.css +1555 -0
  30. data/app/assets/stylesheets/rails_den/chat_3d.css +1283 -0
  31. data/app/assets/stylesheets/rails_den/chat_3d_management.css +294 -0
  32. data/app/assets/stylesheets/rails_den/chat_reactions.css +79 -0
  33. data/app/assets/stylesheets/rails_den/community_presence.css +51 -0
  34. data/app/assets/stylesheets/rails_den/composer.css +358 -0
  35. data/app/assets/stylesheets/rails_den/emoji_catalog.css +33 -0
  36. data/app/assets/stylesheets/rails_den/member_profiles.css +662 -0
  37. data/app/assets/stylesheets/rails_den/moderation.css +561 -0
  38. data/app/assets/stylesheets/rails_den/notifications.css +222 -0
  39. data/app/assets/stylesheets/rails_den/onebox.css +126 -0
  40. data/app/assets/stylesheets/rails_den/post_links.css +37 -0
  41. data/app/assets/stylesheets/rails_den/post_presence.css +47 -0
  42. data/app/assets/stylesheets/rails_den/presence.css +96 -0
  43. data/app/assets/stylesheets/rails_den/presence_directory.css +217 -0
  44. data/app/assets/stylesheets/rails_den/presence_live.css +15 -0
  45. data/app/assets/stylesheets/rails_den/private_messages.css +41 -0
  46. data/app/assets/stylesheets/rails_den/reactions.css +53 -0
  47. data/app/assets/stylesheets/rails_den/search.css +100 -0
  48. data/app/assets/stylesheets/rails_den/tags.css +136 -0
  49. data/app/channels/rails_den/chat_spatial_channel.rb +203 -0
  50. data/app/channels/rails_den/chat_spatial_occupancy_channel.rb +69 -0
  51. data/app/channels/rails_den/chat_stream_channel.rb +108 -0
  52. data/app/channels/rails_den/notifications_channel.rb +30 -0
  53. data/app/channels/rails_den/presence_channel.rb +205 -0
  54. data/app/controllers/admin/rails_den/administrators_controller.rb +26 -0
  55. data/app/controllers/admin/rails_den/advertising_management_controller.rb +337 -0
  56. data/app/controllers/admin/rails_den/application_controller.rb +116 -0
  57. data/app/controllers/admin/rails_den/badges_controller.rb +106 -0
  58. data/app/controllers/admin/rails_den/board_access_controller.rb +143 -0
  59. data/app/controllers/admin/rails_den/boards_controller.rb +89 -0
  60. data/app/controllers/admin/rails_den/categories_controller.rb +89 -0
  61. data/app/controllers/admin/rails_den/member_badge_awards_controller.rb +92 -0
  62. data/app/controllers/admin/rails_den/members_controller.rb +495 -0
  63. data/app/controllers/admin/rails_den/plugins_controller.rb +25 -0
  64. data/app/controllers/admin/rails_den/profile_fields_controller.rb +104 -0
  65. data/app/controllers/admin/rails_den/reaction_types_controller.rb +127 -0
  66. data/app/controllers/admin/rails_den/report_reasons_controller.rb +15 -0
  67. data/app/controllers/admin/rails_den/roles_controller.rb +190 -0
  68. data/app/controllers/admin/rails_den/tags_controller.rb +11 -0
  69. data/app/controllers/admin/rails_den/themes_controller.rb +60 -0
  70. data/app/controllers/admin/rails_den/trust_levels_controller.rb +97 -0
  71. data/app/controllers/rails_den/advertising_controller.rb +14 -0
  72. data/app/controllers/rails_den/application_controller.rb +218 -0
  73. data/app/controllers/rails_den/attachments_controller.rb +128 -0
  74. data/app/controllers/rails_den/board_follows_controller.rb +119 -0
  75. data/app/controllers/rails_den/board_read_states_controller.rb +36 -0
  76. data/app/controllers/rails_den/boards_controller.rb +103 -0
  77. data/app/controllers/rails_den/bookmarks_controller.rb +91 -0
  78. data/app/controllers/rails_den/chat_channel_memberships_controller.rb +193 -0
  79. data/app/controllers/rails_den/chat_channel_read_states_controller.rb +46 -0
  80. data/app/controllers/rails_den/chat_channels_controller.rb +556 -0
  81. data/app/controllers/rails_den/chat_message_pins_controller.rb +78 -0
  82. data/app/controllers/rails_den/chat_messages_controller.rb +166 -0
  83. data/app/controllers/rails_den/chat_reaction_types_controller.rb +24 -0
  84. data/app/controllers/rails_den/community_read_states_controller.rb +12 -0
  85. data/app/controllers/rails_den/home_controller.rb +35 -0
  86. data/app/controllers/rails_den/member_profiles_controller.rb +286 -0
  87. data/app/controllers/rails_den/member_reports_controller.rb +22 -0
  88. data/app/controllers/rails_den/members_controller.rb +42 -0
  89. data/app/controllers/rails_den/mention_candidates_controller.rb +14 -0
  90. data/app/controllers/rails_den/moderation/audit_events_controller.rb +14 -0
  91. data/app/controllers/rails_den/moderation/member_histories_controller.rb +37 -0
  92. data/app/controllers/rails_den/moderation/member_notes_controller.rb +26 -0
  93. data/app/controllers/rails_den/moderation/report_notes_controller.rb +27 -0
  94. data/app/controllers/rails_den/moderation/reports_controller.rb +97 -0
  95. data/app/controllers/rails_den/moderation/restrictions_controller.rb +71 -0
  96. data/app/controllers/rails_den/moderation/topics_controller.rb +61 -0
  97. data/app/controllers/rails_den/moderation/warnings_controller.rb +50 -0
  98. data/app/controllers/rails_den/notification_preferences_controller.rb +116 -0
  99. data/app/controllers/rails_den/notifications_controller.rb +67 -0
  100. data/app/controllers/rails_den/post_bookmarks_controller.rb +29 -0
  101. data/app/controllers/rails_den/post_drafts_controller.rb +125 -0
  102. data/app/controllers/rails_den/post_reports_controller.rb +31 -0
  103. data/app/controllers/rails_den/posts_controller.rb +318 -0
  104. data/app/controllers/rails_den/presence_controller.rb +12 -0
  105. data/app/controllers/rails_den/presence_snapshots_controller.rb +83 -0
  106. data/app/controllers/rails_den/previews_controller.rb +10 -0
  107. data/app/controllers/rails_den/private_conversations_controller.rb +120 -0
  108. data/app/controllers/rails_den/private_messages_controller.rb +45 -0
  109. data/app/controllers/rails_den/reactions_controller.rb +124 -0
  110. data/app/controllers/rails_den/reports_controller.rb +63 -0
  111. data/app/controllers/rails_den/search_controller.rb +64 -0
  112. data/app/controllers/rails_den/tags_controller.rb +70 -0
  113. data/app/controllers/rails_den/topic_bookmarks_controller.rb +35 -0
  114. data/app/controllers/rails_den/topic_follows_controller.rb +117 -0
  115. data/app/controllers/rails_den/topic_read_positions_controller.rb +40 -0
  116. data/app/controllers/rails_den/topic_reports_controller.rb +18 -0
  117. data/app/controllers/rails_den/topics_controller.rb +583 -0
  118. data/app/dashboards/rails_den/administrator_dashboard.rb +51 -0
  119. data/app/dashboards/rails_den/board_dashboard.rb +57 -0
  120. data/app/dashboards/rails_den/category_dashboard.rb +50 -0
  121. data/app/dashboards/rails_den/profile_field_dashboard.rb +53 -0
  122. data/app/dashboards/rails_den/reaction_type_dashboard.rb +26 -0
  123. data/app/dashboards/rails_den/report_reason_dashboard.rb +57 -0
  124. data/app/dashboards/rails_den/tag_dashboard.rb +59 -0
  125. data/app/helpers/rails_den/application_helper.rb +39 -0
  126. data/app/helpers/rails_den/boards_helper.rb +4 -0
  127. data/app/helpers/rails_den/moderation/reports_helper.rb +42 -0
  128. data/app/helpers/rails_den/notifications_helper.rb +4 -0
  129. data/app/helpers/rails_den/posts_helper.rb +4 -0
  130. data/app/helpers/rails_den/topics_helper.rb +4 -0
  131. data/app/jobs/rails_den/application_job.rb +4 -0
  132. data/app/jobs/rails_den/expire_user_restriction_job.rb +9 -0
  133. data/app/jobs/rails_den/member_profile_stats_refresh_job.rb +48 -0
  134. data/app/jobs/rails_den/reconcile_user_restrictions_job.rb +9 -0
  135. data/app/jobs/rails_den/resolve_onebox_entry_job.rb +74 -0
  136. data/app/mailers/rails_den/application_mailer.rb +6 -0
  137. data/app/models/rails_den/administrator.rb +18 -0
  138. data/app/models/rails_den/advertising_configuration.rb +14 -0
  139. data/app/models/rails_den/application_record.rb +5 -0
  140. data/app/models/rails_den/badge.rb +142 -0
  141. data/app/models/rails_den/badge_award.rb +87 -0
  142. data/app/models/rails_den/board.rb +129 -0
  143. data/app/models/rails_den/board_follow.rb +18 -0
  144. data/app/models/rails_den/board_read_state.rb +60 -0
  145. data/app/models/rails_den/board_role_assignment.rb +45 -0
  146. data/app/models/rails_den/board_role_permission.rb +31 -0
  147. data/app/models/rails_den/board_role_requirement.rb +16 -0
  148. data/app/models/rails_den/board_sponsorship.rb +21 -0
  149. data/app/models/rails_den/bookmark.rb +31 -0
  150. data/app/models/rails_den/category.rb +81 -0
  151. data/app/models/rails_den/category_role_requirement.rb +16 -0
  152. data/app/models/rails_den/category_sponsorship.rb +21 -0
  153. data/app/models/rails_den/chat_channel.rb +44 -0
  154. data/app/models/rails_den/chat_channel_membership.rb +21 -0
  155. data/app/models/rails_den/chat_channel_read_state.rb +100 -0
  156. data/app/models/rails_den/chat_message.rb +37 -0
  157. data/app/models/rails_den/community_read_state.rb +52 -0
  158. data/app/models/rails_den/community_sponsorship.rb +15 -0
  159. data/app/models/rails_den/member_profile.rb +113 -0
  160. data/app/models/rails_den/mention.rb +20 -0
  161. data/app/models/rails_den/moderation_event.rb +16 -0
  162. data/app/models/rails_den/moderation_note.rb +11 -0
  163. data/app/models/rails_den/notification.rb +33 -0
  164. data/app/models/rails_den/notification_event.rb +40 -0
  165. data/app/models/rails_den/notification_mute.rb +9 -0
  166. data/app/models/rails_den/onebox_entry.rb +214 -0
  167. data/app/models/rails_den/post.rb +396 -0
  168. data/app/models/rails_den/post_draft.rb +63 -0
  169. data/app/models/rails_den/post_revision.rb +10 -0
  170. data/app/models/rails_den/private_conversation.rb +25 -0
  171. data/app/models/rails_den/private_conversation_participant.rb +16 -0
  172. data/app/models/rails_den/private_message.rb +35 -0
  173. data/app/models/rails_den/private_message_recipient.rb +44 -0
  174. data/app/models/rails_den/profile_field.rb +150 -0
  175. data/app/models/rails_den/profile_field_value.rb +136 -0
  176. data/app/models/rails_den/reaction.rb +56 -0
  177. data/app/models/rails_den/reaction_type.rb +23 -0
  178. data/app/models/rails_den/reader_visit.rb +61 -0
  179. data/app/models/rails_den/report.rb +127 -0
  180. data/app/models/rails_den/report_reason.rb +52 -0
  181. data/app/models/rails_den/reputation_event.rb +92 -0
  182. data/app/models/rails_den/role.rb +87 -0
  183. data/app/models/rails_den/role_assignment.rb +18 -0
  184. data/app/models/rails_den/role_permission.rb +41 -0
  185. data/app/models/rails_den/sluggable.rb +102 -0
  186. data/app/models/rails_den/sponsor.rb +20 -0
  187. data/app/models/rails_den/sponsorship.rb +87 -0
  188. data/app/models/rails_den/tag.rb +61 -0
  189. data/app/models/rails_den/theme_selection.rb +4 -0
  190. data/app/models/rails_den/topic.rb +307 -0
  191. data/app/models/rails_den/topic_follow.rb +18 -0
  192. data/app/models/rails_den/topic_read_state.rb +76 -0
  193. data/app/models/rails_den/topic_role_requirement.rb +16 -0
  194. data/app/models/rails_den/topic_tag.rb +16 -0
  195. data/app/models/rails_den/trust_level.rb +62 -0
  196. data/app/models/rails_den/trust_level_achievement.rb +21 -0
  197. data/app/models/rails_den/user_restriction.rb +54 -0
  198. data/app/models/rails_den/user_warning.rb +10 -0
  199. data/app/presenters/rails_den/member_profile_presenter.rb +285 -0
  200. data/app/queries/rails_den/topic_new_post_counts.rb +153 -0
  201. data/app/queries/rails_den/topic_unread_counts.rb +137 -0
  202. data/app/services/rails_den/board_following.rb +91 -0
  203. data/app/services/rails_den/bookmark_list.rb +109 -0
  204. data/app/services/rails_den/bookmark_state.rb +17 -0
  205. data/app/services/rails_den/built_in_role_provisioner.rb +98 -0
  206. data/app/services/rails_den/chat/broadcaster.rb +81 -0
  207. data/app/services/rails_den/chat/message_payload.rb +26 -0
  208. data/app/services/rails_den/chat/presence_snapshot.rb +269 -0
  209. data/app/services/rails_den/chat/spatial_broadcaster.rb +135 -0
  210. data/app/services/rails_den/chat/spatial_occupancy_snapshot.rb +35 -0
  211. data/app/services/rails_den/chat/spatial_registry.rb +682 -0
  212. data/app/services/rails_den/chat/spatial_room.rb +81 -0
  213. data/app/services/rails_den/chat/spatial_snapshot.rb +261 -0
  214. data/app/services/rails_den/chat/spatial_update.rb +243 -0
  215. data/app/services/rails_den/chat/subscription_token.rb +28 -0
  216. data/app/services/rails_den/chat/unread_counts.rb +79 -0
  217. data/app/services/rails_den/chat/whisper_delivery.rb +287 -0
  218. data/app/services/rails_den/chat_channel_access.rb +97 -0
  219. data/app/services/rails_den/default_report_reason_provisioner.rb +30 -0
  220. data/app/services/rails_den/emoji_catalog.rb +101 -0
  221. data/app/services/rails_den/gamification/activity_recorder.rb +69 -0
  222. data/app/services/rails_den/gamification/badge_evaluator.rb +55 -0
  223. data/app/services/rails_den/gamification/current_trust_level.rb +21 -0
  224. data/app/services/rails_den/gamification/metrics.rb +93 -0
  225. data/app/services/rails_den/gamification/reputation_ledger.rb +261 -0
  226. data/app/services/rails_den/gamification/trust_level_evaluator.rb +78 -0
  227. data/app/services/rails_den/global_moderation_policy.rb +32 -0
  228. data/app/services/rails_den/member_profile_bio_renderer.rb +28 -0
  229. data/app/services/rails_den/mentions/autocomplete.rb +69 -0
  230. data/app/services/rails_den/mentions/candidate.rb +19 -0
  231. data/app/services/rails_den/mentions/parser.rb +185 -0
  232. data/app/services/rails_den/mentions/reconciler.rb +46 -0
  233. data/app/services/rails_den/mentions/renderer.rb +165 -0
  234. data/app/services/rails_den/moderation_access.rb +42 -0
  235. data/app/services/rails_den/moderation_audit.rb +38 -0
  236. data/app/services/rails_den/moderation_event_scope.rb +12 -0
  237. data/app/services/rails_den/moderation_notification_delivery.rb +23 -0
  238. data/app/services/rails_den/notification_events/emitter.rb +226 -0
  239. data/app/services/rails_den/notification_preferences.rb +169 -0
  240. data/app/services/rails_den/notifications/broadcaster.rb +72 -0
  241. data/app/services/rails_den/notifications/materializer.rb +284 -0
  242. data/app/services/rails_den/notifications/subscription_token.rb +28 -0
  243. data/app/services/rails_den/permission_resolver.rb +252 -0
  244. data/app/services/rails_den/presence/board_summary.rb +131 -0
  245. data/app/services/rails_den/presence/broadcaster.rb +193 -0
  246. data/app/services/rails_den/presence/chat_room_registry.rb +263 -0
  247. data/app/services/rails_den/presence/community_summary.rb +166 -0
  248. data/app/services/rails_den/presence/directory.rb +499 -0
  249. data/app/services/rails_den/presence/last_seen.rb +23 -0
  250. data/app/services/rails_den/presence/page_map.rb +202 -0
  251. data/app/services/rails_den/presence/registry.rb +805 -0
  252. data/app/services/rails_den/presence/subscription_token.rb +28 -0
  253. data/app/services/rails_den/presence/visibility.rb +95 -0
  254. data/app/services/rails_den/private_messages/mailbox.rb +108 -0
  255. data/app/services/rails_den/private_messages/read_marker.rb +25 -0
  256. data/app/services/rails_den/private_messages/sender.rb +113 -0
  257. data/app/services/rails_den/private_messages/unread_count.rb +22 -0
  258. data/app/services/rails_den/reaction_summary.rb +54 -0
  259. data/app/services/rails_den/reaction_type_importer.rb +91 -0
  260. data/app/services/rails_den/reaction_type_search.rb +34 -0
  261. data/app/services/rails_den/readable_community_content.rb +156 -0
  262. data/app/services/rails_den/report_assignment.rb +31 -0
  263. data/app/services/rails_den/report_creator.rb +96 -0
  264. data/app/services/rails_den/report_delivery.rb +39 -0
  265. data/app/services/rails_den/report_disposition.rb +25 -0
  266. data/app/services/rails_den/report_recipients.rb +89 -0
  267. data/app/services/rails_den/report_review_policy.rb +66 -0
  268. data/app/services/rails_den/report_review_scope.rb +49 -0
  269. data/app/services/rails_den/restriction_resolver.rb +28 -0
  270. data/app/services/rails_den/role_resolver.rb +66 -0
  271. data/app/services/rails_den/search/adapters/basic.rb +35 -0
  272. data/app/services/rails_den/search/adapters/postgresql.rb +73 -0
  273. data/app/services/rails_den/search/adapters.rb +21 -0
  274. data/app/services/rails_den/search/query.rb +358 -0
  275. data/app/services/rails_den/topic_following.rb +91 -0
  276. data/app/services/rails_den/topic_merger.rb +27 -0
  277. data/app/services/rails_den/topic_moderation.rb +57 -0
  278. data/app/services/rails_den/topic_splitter.rb +36 -0
  279. data/app/services/rails_den/user_restriction_manager.rb +84 -0
  280. data/app/services/rails_den/user_warning_issuer.rb +19 -0
  281. data/app/views/admin/rails_den/advertising_management/_assignment_form.html.erb +340 -0
  282. data/app/views/admin/rails_den/advertising_management/_errors.html.erb +10 -0
  283. data/app/views/admin/rails_den/advertising_management/show.html.erb +324 -0
  284. data/app/views/admin/rails_den/badges/_form.html.erb +191 -0
  285. data/app/views/admin/rails_den/badges/edit.html.erb +14 -0
  286. data/app/views/admin/rails_den/badges/index.html.erb +98 -0
  287. data/app/views/admin/rails_den/badges/new.html.erb +14 -0
  288. data/app/views/admin/rails_den/board_access/show.html.erb +51 -0
  289. data/app/views/admin/rails_den/boards/_form.html.erb +5 -0
  290. data/app/views/admin/rails_den/categories/_form.html.erb +4 -0
  291. data/app/views/admin/rails_den/members/index.html.erb +121 -0
  292. data/app/views/admin/rails_den/members/show.html.erb +398 -0
  293. data/app/views/admin/rails_den/plugins/index.html.erb +49 -0
  294. data/app/views/admin/rails_den/profile_fields/_form.html.erb +169 -0
  295. data/app/views/admin/rails_den/reaction_types/_catalog_search.html.erb +22 -0
  296. data/app/views/admin/rails_den/reaction_types/_errors.html.erb +3 -0
  297. data/app/views/admin/rails_den/reaction_types/index.html.erb +66 -0
  298. data/app/views/admin/rails_den/reaction_types/new.html.erb +23 -0
  299. data/app/views/admin/rails_den/reaction_types/selected.html.erb +15 -0
  300. data/app/views/admin/rails_den/roles/_form.html.erb +64 -0
  301. data/app/views/admin/rails_den/roles/edit.html.erb +18 -0
  302. data/app/views/admin/rails_den/roles/index.html.erb +49 -0
  303. data/app/views/admin/rails_den/roles/new.html.erb +6 -0
  304. data/app/views/admin/rails_den/shared/_access_form.html.erb +59 -0
  305. data/app/views/admin/rails_den/themes/index.html.erb +129 -0
  306. data/app/views/admin/rails_den/trust_levels/_form.html.erb +80 -0
  307. data/app/views/admin/rails_den/trust_levels/edit.html.erb +14 -0
  308. data/app/views/admin/rails_den/trust_levels/index.html.erb +86 -0
  309. data/app/views/admin/rails_den/trust_levels/new.html.erb +14 -0
  310. data/app/views/administrate/application/_index_header.html.erb +68 -0
  311. data/app/views/administrate/application/new.html.erb +42 -0
  312. data/app/views/administrate/application/show.html.erb +89 -0
  313. data/app/views/layouts/administrate/application/_navigation.html.erb +61 -0
  314. data/app/views/layouts/administrate/application.html.erb +40 -0
  315. data/app/views/layouts/rails_den/_navbar.html.erb +293 -0
  316. data/app/views/layouts/rails_den/application.html.erb +198 -0
  317. data/app/views/rails_den/advertising/show.html.erb +13 -0
  318. data/app/views/rails_den/boards/_follow_button.html.erb +45 -0
  319. data/app/views/rails_den/boards/show.html.erb +150 -0
  320. data/app/views/rails_den/bookmarks/_post_control.html.erb +12 -0
  321. data/app/views/rails_den/bookmarks/_topic_control.html.erb +12 -0
  322. data/app/views/rails_den/bookmarks/index.html.erb +78 -0
  323. data/app/views/rails_den/chat_channels/_form.html.erb +174 -0
  324. data/app/views/rails_den/chat_channels/edit.html.erb +51 -0
  325. data/app/views/rails_den/chat_channels/index.html.erb +402 -0
  326. data/app/views/rails_den/chat_channels/new.html.erb +31 -0
  327. data/app/views/rails_den/chat_channels/show.html.erb +476 -0
  328. data/app/views/rails_den/home/index.html.erb +142 -0
  329. data/app/views/rails_den/member_profiles/_avatar.html.erb +18 -0
  330. data/app/views/rails_den/member_profiles/_custom_fields.html.erb +39 -0
  331. data/app/views/rails_den/member_profiles/_followed_boards.html.erb +15 -0
  332. data/app/views/rails_den/member_profiles/_followed_topics.html.erb +15 -0
  333. data/app/views/rails_den/member_profiles/_header.html.erb +103 -0
  334. data/app/views/rails_den/member_profiles/_recent_posts.html.erb +19 -0
  335. data/app/views/rails_den/member_profiles/_recent_topics.html.erb +15 -0
  336. data/app/views/rails_den/member_profiles/_stats.html.erb +11 -0
  337. data/app/views/rails_den/member_profiles/edit.html.erb +265 -0
  338. data/app/views/rails_den/member_profiles/show.html.erb +97 -0
  339. data/app/views/rails_den/member_reports/new.html.erb +1 -0
  340. data/app/views/rails_den/moderation/audit_events/index.html.erb +11 -0
  341. data/app/views/rails_den/moderation/member_histories/show.html.erb +314 -0
  342. data/app/views/rails_den/moderation/reports/index.html.erb +47 -0
  343. data/app/views/rails_den/moderation/reports/show.html.erb +344 -0
  344. data/app/views/rails_den/moderation/restrictions/new.html.erb +14 -0
  345. data/app/views/rails_den/moderation/topics/show.html.erb +14 -0
  346. data/app/views/rails_den/moderation/warnings/new.html.erb +10 -0
  347. data/app/views/rails_den/notifications/_empty_state.html.erb +13 -0
  348. data/app/views/rails_den/notifications/index.html.erb +308 -0
  349. data/app/views/rails_den/passwords/edit.html.erb +55 -0
  350. data/app/views/rails_den/passwords/new.html.erb +49 -0
  351. data/app/views/rails_den/passwords_mailer/reset.html.erb +22 -0
  352. data/app/views/rails_den/passwords_mailer/reset.text.erb +14 -0
  353. data/app/views/rails_den/post_reports/new.html.erb +1 -0
  354. data/app/views/rails_den/posts/_attachments.html.erb +94 -0
  355. data/app/views/rails_den/posts/edit.html.erb +95 -0
  356. data/app/views/rails_den/posts/history.html.erb +123 -0
  357. data/app/views/rails_den/presence/_directory_body.html.erb +155 -0
  358. data/app/views/rails_den/presence/_summary.html.erb +26 -0
  359. data/app/views/rails_den/presence/index.html.erb +29 -0
  360. data/app/views/rails_den/private_conversations/_composer.html.erb +28 -0
  361. data/app/views/rails_den/private_conversations/_conversation_row.html.erb +19 -0
  362. data/app/views/rails_den/private_conversations/_mailbox_nav.html.erb +7 -0
  363. data/app/views/rails_den/private_conversations/_message.html.erb +4 -0
  364. data/app/views/rails_den/private_conversations/_pagination.html.erb +6 -0
  365. data/app/views/rails_den/private_conversations/index.html.erb +11 -0
  366. data/app/views/rails_den/private_conversations/new.html.erb +5 -0
  367. data/app/views/rails_den/private_conversations/sent.html.erb +11 -0
  368. data/app/views/rails_den/private_conversations/show.html.erb +23 -0
  369. data/app/views/rails_den/reactions/_picker_options.html.erb +14 -0
  370. data/app/views/rails_den/reactions/_post_reactions.html.erb +87 -0
  371. data/app/views/rails_den/reactions/_reactor_list.html.erb +16 -0
  372. data/app/views/rails_den/reactions/index.html.erb +34 -0
  373. data/app/views/rails_den/reactions/picker.html.erb +14 -0
  374. data/app/views/rails_den/registrations/edit.html.erb +95 -0
  375. data/app/views/rails_den/registrations/new.html.erb +77 -0
  376. data/app/views/rails_den/reports/_form.html.erb +54 -0
  377. data/app/views/rails_den/search/index.html.erb +235 -0
  378. data/app/views/rails_den/sessions/new.html.erb +64 -0
  379. data/app/views/rails_den/shared/_ad_network_placement.html.erb +5 -0
  380. data/app/views/rails_den/shared/_composer.html.erb +266 -0
  381. data/app/views/rails_den/shared/_sponsor_placement.html.erb +44 -0
  382. data/app/views/rails_den/tags/show.html.erb +91 -0
  383. data/app/views/rails_den/topic_reports/new.html.erb +1 -0
  384. data/app/views/rails_den/topics/_author_badges.html.erb +15 -0
  385. data/app/views/rails_den/topics/_follow_button.html.erb +45 -0
  386. data/app/views/rails_den/topics/_summary.html.erb +121 -0
  387. data/app/views/rails_den/topics/_tags.html.erb +47 -0
  388. data/app/views/rails_den/topics/new.html.erb +181 -0
  389. data/app/views/rails_den/topics/show.html.erb +430 -0
  390. data/config/locales/rails_den.en.yml +65 -0
  391. data/config/routes.rb +442 -0
  392. data/db/migrate/20260820181527_create_rails_den_administrators.rb +12 -0
  393. data/db/migrate/20260820205806_create_rails_den_categories.rb +16 -0
  394. data/db/migrate/20260820212200_create_rails_den_boards.rb +23 -0
  395. data/db/migrate/20260820234758_create_rails_den_topics.rb +24 -0
  396. data/db/migrate/20260821001937_create_rails_den_posts.rb +11 -0
  397. data/db/migrate/20260822004306_add_soft_deletion_to_rails_den_posts.rb +9 -0
  398. data/db/migrate/20260823183944_create_rails_den_onebox_entries.rb +65 -0
  399. data/db/migrate/20260824025007_add_reply_to_to_rails_den_posts.rb +8 -0
  400. data/db/migrate/20260824092300_create_rails_den_post_revisions.rb +22 -0
  401. data/db/migrate/20260824103358_create_rails_den_post_drafts.rb +36 -0
  402. data/db/migrate/20260824142522_create_rails_den_topic_read_states.rb +32 -0
  403. data/db/migrate/20260824214941_create_rails_den_reader_visits.rb +16 -0
  404. data/db/migrate/20260824225733_create_rails_den_board_read_states.rb +34 -0
  405. data/db/migrate/20260824232113_create_rails_den_community_read_states.rb +26 -0
  406. data/db/migrate/20260825121109_create_rails_den_topic_follows.rb +36 -0
  407. data/db/migrate/20260825232623_create_rails_den_board_follows.rb +36 -0
  408. data/db/migrate/20260826003155_create_rails_den_mentions.rb +27 -0
  409. data/db/migrate/20260826080109_create_rails_den_member_profiles.rb +32 -0
  410. data/db/migrate/20260826092936_add_quoted_post_to_rails_den_posts_and_post_drafts.rb +17 -0
  411. data/db/migrate/20260826101755_create_rails_den_notification_events.rb +19 -0
  412. data/db/migrate/20260826121710_create_rails_den_notifications.rb +28 -0
  413. data/db/migrate/20260826140846_create_rails_den_notification_mutes.rb +25 -0
  414. data/db/migrate/20260826175426_create_rails_den_tags.rb +31 -0
  415. data/db/migrate/20260826175428_create_rails_den_topic_tags.rb +26 -0
  416. data/db/migrate/20260827021133_create_rails_den_roles.rb +16 -0
  417. data/db/migrate/20260827021135_create_rails_den_role_assignments.rb +22 -0
  418. data/db/migrate/20260827031134_create_rails_den_role_permissions.rb +28 -0
  419. data/db/migrate/20260827031136_create_rails_den_board_role_permissions.rb +35 -0
  420. data/db/migrate/20260827033116_provision_rails_den_built_in_roles_and_permissions.rb +108 -0
  421. data/db/migrate/20260827040515_create_rails_den_board_role_assignments.rb +33 -0
  422. data/db/migrate/20260827041710_create_rails_den_board_role_requirements.rb +27 -0
  423. data/db/migrate/20260827063901_create_rails_den_category_role_requirements.rb +23 -0
  424. data/db/migrate/20260827063909_create_rails_den_topic_role_requirements.rb +23 -0
  425. data/db/migrate/20260827203747_create_rails_den_report_reasons.rb +19 -0
  426. data/db/migrate/20260827203752_create_rails_den_reports.rb +24 -0
  427. data/db/migrate/20260827203807_provision_rails_den_default_report_reasons.rb +32 -0
  428. data/db/migrate/20260828030352_create_rails_den_moderation_events.rb +26 -0
  429. data/db/migrate/20260828030354_create_rails_den_moderation_notes.rb +13 -0
  430. data/db/migrate/20260828030357_create_rails_den_user_warnings.rb +17 -0
  431. data/db/migrate/20260828030359_create_rails_den_user_restrictions.rb +30 -0
  432. data/db/migrate/20260828030404_add_moderation_fields_to_rails_den_reports.rb +55 -0
  433. data/db/migrate/20260828030407_add_moderation_fields_to_rails_den_topics.rb +14 -0
  434. data/db/migrate/20260828031955_add_opening_post_to_rails_den_topics.rb +25 -0
  435. data/db/migrate/20260828083552_create_rails_den_reaction_types.rb +15 -0
  436. data/db/migrate/20260828083554_create_rails_den_reactions.rb +20 -0
  437. data/db/migrate/20260828083556_provision_rails_den_default_reaction_type.rb +18 -0
  438. data/db/migrate/20260828151420_create_rails_den_bookmarks.rb +20 -0
  439. data/db/migrate/20260828165545_create_rails_den_profile_fields.rb +37 -0
  440. data/db/migrate/20260828165547_create_rails_den_profile_field_values.rb +31 -0
  441. data/db/migrate/20260828191644_add_presence_fields_to_rails_den_member_profiles.rb +22 -0
  442. data/db/migrate/20260829003137_create_rails_den_private_conversations.rb +13 -0
  443. data/db/migrate/20260829003139_create_rails_den_private_conversation_participants.rb +35 -0
  444. data/db/migrate/20260829003141_create_rails_den_private_messages.rb +19 -0
  445. data/db/migrate/20260829003143_create_rails_den_private_message_recipients.rb +26 -0
  446. data/db/migrate/20260829003435_provision_rails_den_message_capability_defaults.rb +39 -0
  447. data/db/migrate/20260829013557_create_rails_den_chat_channels.rb +17 -0
  448. data/db/migrate/20260829014413_create_rails_den_chat_channel_memberships.rb +26 -0
  449. data/db/migrate/20260829014523_create_rails_den_chat_messages.rb +27 -0
  450. data/db/migrate/20260830155021_create_rails_den_chat_channel_read_states.rb +37 -0
  451. data/db/migrate/20260830155023_add_pinned_to_rails_den_chat_messages.rb +16 -0
  452. data/db/migrate/20260830185149_create_rails_den_badges.rb +44 -0
  453. data/db/migrate/20260830185151_create_rails_den_badge_awards.rb +43 -0
  454. data/db/migrate/20260830190053_create_rails_den_reputation_events.rb +52 -0
  455. data/db/migrate/20260830190055_create_rails_den_trust_levels.rb +52 -0
  456. data/db/migrate/20260830190057_create_rails_den_trust_level_achievements.rb +39 -0
  457. data/db/migrate/20260830190059_add_reputation_points_to_rails_den_member_profiles.rb +17 -0
  458. data/db/migrate/20260831120000_create_rails_den_advertising_and_sponsorships.rb +55 -0
  459. data/db/migrate/20260831120001_add_description_to_rails_den_sponsors.rb +5 -0
  460. data/db/migrate/20260831120002_add_advertising_page_to_rails_den_advertising_configurations.rb +7 -0
  461. data/db/migrate/20260831120003_add_destination_url_to_rails_den_sponsors.rb +5 -0
  462. data/db/migrate/20260831120004_move_destination_url_to_rails_den_sponsorships.rb +138 -0
  463. data/db/migrate/20260831204539_create_rails_den_theme_selections.rb +9 -0
  464. data/exe/rails_den +5 -0
  465. data/lib/generators/rails_den/install/install_generator.rb +42 -0
  466. data/lib/generators/rails_den/install/templates/rails_den.rb +75 -0
  467. data/lib/generators/rails_den/install/views/views_generator.rb +56 -0
  468. data/lib/rails/commands/rails_den/import/discourse/discourse_command.rb +48 -0
  469. data/lib/rails_den/cli.rb +174 -0
  470. data/lib/rails_den/configuration.rb +173 -0
  471. data/lib/rails_den/engine.rb +10 -0
  472. data/lib/rails_den/extensions/descriptor.rb +138 -0
  473. data/lib/rails_den/extensions/registry.rb +65 -0
  474. data/lib/rails_den/extensions.rb +49 -0
  475. data/lib/rails_den/formatters/markdown.rb +30 -0
  476. data/lib/rails_den/formatters/plain_text.rb +18 -0
  477. data/lib/rails_den/formatting.rb +130 -0
  478. data/lib/rails_den/gamification.rb +77 -0
  479. data/lib/rails_den/import/discourse/backup.rb +169 -0
  480. data/lib/rails_den/import/discourse/finalizer.rb +617 -0
  481. data/lib/rails_den/import/discourse/importer.rb +266 -0
  482. data/lib/rails_den/import/discourse/source_database.rb +320 -0
  483. data/lib/rails_den/import/discourse/staff_roles.rb +173 -0
  484. data/lib/rails_den/import/discourse/transformer.rb +940 -0
  485. data/lib/rails_den/import/discourse.rb +9 -0
  486. data/lib/rails_den/licensing/client.rb +128 -0
  487. data/lib/rails_den/licensing/result.rb +57 -0
  488. data/lib/rails_den/licensing.rb +28 -0
  489. data/lib/rails_den/metadata.rb +343 -0
  490. data/lib/rails_den/onebox/address_guard.rb +108 -0
  491. data/lib/rails_den/onebox/body_renderer.rb +135 -0
  492. data/lib/rails_den/onebox/embed_policy.rb +179 -0
  493. data/lib/rails_den/onebox/errors.rb +24 -0
  494. data/lib/rails_den/onebox/extractor.rb +130 -0
  495. data/lib/rails_den/onebox/fetcher.rb +199 -0
  496. data/lib/rails_den/onebox/http_transport.rb +164 -0
  497. data/lib/rails_den/onebox/metadata.rb +343 -0
  498. data/lib/rails_den/onebox/oembed/client.rb +46 -0
  499. data/lib/rails_den/onebox/oembed/discovery.rb +296 -0
  500. data/lib/rails_den/onebox/oembed/response.rb +375 -0
  501. data/lib/rails_den/onebox/oembed.rb +18 -0
  502. data/lib/rails_den/onebox/providers/base.rb +23 -0
  503. data/lib/rails_den/onebox/providers/bluesky.rb +402 -0
  504. data/lib/rails_den/onebox/providers/generic.rb +310 -0
  505. data/lib/rails_den/onebox/providers/giphy.rb +281 -0
  506. data/lib/rails_den/onebox/providers/github.rb +300 -0
  507. data/lib/rails_den/onebox/providers/mastodon.rb +505 -0
  508. data/lib/rails_den/onebox/providers/soundcloud.rb +199 -0
  509. data/lib/rails_den/onebox/providers/spotify.rb +196 -0
  510. data/lib/rails_den/onebox/providers/tenor.rb +296 -0
  511. data/lib/rails_den/onebox/providers/tiktok.rb +292 -0
  512. data/lib/rails_den/onebox/providers/twitch.rb +414 -0
  513. data/lib/rails_den/onebox/providers/vimeo.rb +295 -0
  514. data/lib/rails_den/onebox/providers/youtube.rb +201 -0
  515. data/lib/rails_den/onebox/registry.rb +41 -0
  516. data/lib/rails_den/onebox/renderer.rb +403 -0
  517. data/lib/rails_den/onebox/result.rb +86 -0
  518. data/lib/rails_den/onebox/synchronizer.rb +161 -0
  519. data/lib/rails_den/onebox/url.rb +35 -0
  520. data/lib/rails_den/onebox.rb +176 -0
  521. data/lib/rails_den/presence.rb +162 -0
  522. data/lib/rails_den/standalone_template.rb +700 -0
  523. data/lib/rails_den/themes.rb +80 -0
  524. data/lib/rails_den/version.rb +3 -0
  525. data/lib/rails_den/view_installer.rb +129 -0
  526. data/lib/rails_den.rb +113 -0
  527. data/lib/tasks/rails_den_tasks.rake +4 -0
  528. metadata +735 -0
@@ -0,0 +1,56 @@
1
+ require "rails/generators"
2
+ require "rails_den"
3
+
4
+ module RailsDen
5
+ module Generators
6
+ module Install
7
+ class ViewsGenerator < Rails::Generators::Base
8
+ source_root RailsDen::Engine.root.join("app/views").to_s
9
+
10
+ desc "Copies RailsDen's default views into the host application."
11
+
12
+ def copy_views
13
+ copy_file(
14
+ "layouts/rails_den/application.html.erb",
15
+ "app/views/layouts/rails_den/application.html.erb"
16
+ )
17
+
18
+ copy_file(
19
+ "rails_den/sessions/new.html.erb",
20
+ "app/views/rails_den/sessions/new.html.erb"
21
+ )
22
+
23
+ copy_file(
24
+ "rails_den/registrations/new.html.erb",
25
+ "app/views/rails_den/registrations/new.html.erb"
26
+ )
27
+
28
+ copy_file(
29
+ "rails_den/registrations/edit.html.erb",
30
+ "app/views/rails_den/registrations/edit.html.erb"
31
+ )
32
+
33
+ copy_file(
34
+ "rails_den/passwords/new.html.erb",
35
+ "app/views/rails_den/passwords/new.html.erb"
36
+ )
37
+
38
+ copy_file(
39
+ "rails_den/passwords/edit.html.erb",
40
+ "app/views/rails_den/passwords/edit.html.erb"
41
+ )
42
+
43
+ copy_file(
44
+ "rails_den/passwords_mailer/reset.html.erb",
45
+ "app/views/rails_den/passwords_mailer/reset.html.erb"
46
+ )
47
+
48
+ copy_file(
49
+ "rails_den/passwords_mailer/reset.text.erb",
50
+ "app/views/rails_den/passwords_mailer/reset.text.erb"
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_den/import/discourse"
4
+
5
+ module Rails
6
+ module Command
7
+ module RailsDen
8
+ module Import
9
+ class DiscourseCommand < Base
10
+ desc "rails_den:import:discourse BACKUP_PATH",
11
+ "Import an official Discourse backup into RailsDen"
12
+
13
+ def perform(backup_path = nil)
14
+ unless backup_path.present?
15
+ print_usage
16
+ exit 1
17
+ end
18
+
19
+ boot_application!
20
+
21
+ require "rails_den/import/discourse/importer"
22
+
23
+ ::RailsDen::Import::Discourse::Importer.new(
24
+ backup_path: backup_path,
25
+ out: $stdout
26
+ ).call
27
+ rescue ::RailsDen::Import::Discourse::ImportError => import_error
28
+ error "RailsDen Discourse import failed: #{import_error.message}"
29
+ exit 1
30
+ end
31
+
32
+ private
33
+
34
+ def print_usage
35
+ error "RailsDen Discourse Import"
36
+ error ""
37
+ error "Create and download an official Discourse backup, then run:"
38
+ error ""
39
+ error " bin/rails rails_den:import:discourse /path/to/discourse-backup.tar.gz"
40
+ error ""
41
+ error "The importer requires PostgreSQL."
42
+ error "Imported users must reset their password before first sign-in."
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,174 @@
1
+ require "bundler"
2
+ require "rails_den/version"
3
+ require "rails_den/view_installer"
4
+ require "rails/generators"
5
+ require "rails/generators/rails/app/app_generator"
6
+
7
+ module RailsDen
8
+ class CLI
9
+ DEFAULT_TEMPLATE_PATH = File.expand_path(
10
+ "standalone_template.rb",
11
+ __dir__
12
+ )
13
+
14
+ def self.start(
15
+ argv,
16
+ out: $stdout,
17
+ err: $stderr,
18
+ app_generator: Rails::Generators::AppGenerator,
19
+ view_installer_class: RailsDen::ViewInstaller,
20
+ template_path: DEFAULT_TEMPLATE_PATH
21
+ )
22
+ new(
23
+ argv,
24
+ out: out,
25
+ err: err,
26
+ app_generator: app_generator,
27
+ view_installer_class: view_installer_class,
28
+ template_path: template_path
29
+ ).start
30
+ end
31
+
32
+ def initialize(
33
+ argv,
34
+ out:,
35
+ err:,
36
+ app_generator:,
37
+ view_installer_class:,
38
+ template_path:
39
+ )
40
+ @argv = argv.dup
41
+ @out = out
42
+ @err = err
43
+ @app_generator = app_generator
44
+ @view_installer_class = view_installer_class
45
+ @template_path = template_path
46
+ end
47
+
48
+ def start
49
+ command = @argv.shift
50
+
51
+ case command
52
+ when nil, "-h", "--help", "help"
53
+ print_help
54
+ 0
55
+ when "-v", "--version", "version"
56
+ @out.puts RailsDen::VERSION
57
+ 0
58
+ when "new"
59
+ create_application
60
+ when "install:views"
61
+ install_views
62
+ else
63
+ @err.puts "Unknown command: #{command}"
64
+ @err.puts
65
+ print_help(@err)
66
+ 1
67
+ end
68
+ rescue ArgumentError => error
69
+ @err.puts error.message
70
+ 1
71
+ end
72
+
73
+ private
74
+
75
+ def create_application
76
+ name = @argv.shift
77
+
78
+ if name.nil? || name.strip.empty?
79
+ @err.puts "Usage: rails_den new NAME [rails options]"
80
+ return 1
81
+ end
82
+
83
+ rails_options = @argv.dup
84
+
85
+ unless database_option_present?(rails_options)
86
+ rails_options << "--database=postgresql"
87
+ end
88
+
89
+ Bundler.with_unbundled_env do
90
+ @app_generator.start(
91
+ [
92
+ name,
93
+ *rails_options,
94
+ "--template=#{@template_path}"
95
+ ]
96
+ )
97
+ end
98
+
99
+ 0
100
+ end
101
+
102
+ def database_option_present?(arguments)
103
+ arguments.any? do |argument|
104
+ argument == "-d" ||
105
+ argument.start_with?("-d=") ||
106
+ argument == "--database" ||
107
+ argument.start_with?("--database=")
108
+ end
109
+ end
110
+
111
+ def install_views
112
+ force = false
113
+
114
+ @argv.each do |argument|
115
+ case argument
116
+ when "--force"
117
+ force = true
118
+ else
119
+ @err.puts "Unknown option for install:views: #{argument}"
120
+ @err.puts
121
+ @err.puts "Usage: rails_den install:views [--force]"
122
+ return 1
123
+ end
124
+ end
125
+
126
+ installer = @view_installer_class.new(
127
+ destination_root: Dir.pwd,
128
+ out: @out
129
+ )
130
+
131
+ installer.install(force: force)
132
+
133
+ @out.puts
134
+ @out.puts "RailsDen views are now available under app/views."
135
+ @out.puts "Your local copies override RailsDen's packaged defaults."
136
+
137
+ 0
138
+ end
139
+
140
+ def print_help(io = @out)
141
+ io.puts <<~HELP
142
+ RailsDen #{RailsDen::VERSION}
143
+
144
+ Usage:
145
+ rails_den new NAME [rails options]
146
+ rails_den install:views [--force]
147
+ rails_den --version
148
+ rails_den --help
149
+
150
+ Commands:
151
+ new NAME
152
+ Create a new standalone RailsDen application.
153
+
154
+ PostgreSQL is used by default. Pass a Rails database option
155
+ to choose a different database.
156
+
157
+ install:views
158
+ Copy RailsDen's packaged views into the current Rails app
159
+ so they can be customized.
160
+
161
+ Existing files are preserved by default.
162
+ Use --force to replace them with RailsDen's defaults.
163
+
164
+ Examples:
165
+ rails_den new community
166
+ rails_den new community --database=sqlite3
167
+
168
+ cd community
169
+ rails_den install:views
170
+ rails_den install:views --force
171
+ HELP
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,173 @@
1
+ module RailsDen
2
+ class Configuration
3
+ DEFAULT_ATTACHMENT_ALLOWED_TYPES = {
4
+ "jpg" => [
5
+ "image/jpeg"
6
+ ],
7
+ "jpeg" => [
8
+ "image/jpeg"
9
+ ],
10
+ "png" => [
11
+ "image/png"
12
+ ],
13
+ "gif" => [
14
+ "image/gif"
15
+ ],
16
+ "webp" => [
17
+ "image/webp"
18
+ ],
19
+ "pdf" => [
20
+ "application/pdf"
21
+ ],
22
+ "txt" => [
23
+ "text/plain"
24
+ ],
25
+ "md" => [
26
+ "text/plain",
27
+ "text/markdown"
28
+ ],
29
+ "csv" => [
30
+ "text/plain",
31
+ "text/csv"
32
+ ]
33
+ }.freeze
34
+
35
+ attr_accessor :community_name,
36
+ :user_class,
37
+ :current_user_method,
38
+ :current_user_resolver,
39
+ :authentication_method,
40
+ :authentication_handler,
41
+ :parent_controller,
42
+ :registration_enabled,
43
+ :public_revision_history,
44
+ :user_display_name_method,
45
+ :user_mention_name_method,
46
+ :user_mention_resolver,
47
+ :user_mention_candidates_resolver,
48
+ :user_search_resolver,
49
+ :user_mention_path_resolver,
50
+ :formatting_adapter,
51
+ :onebox_enabled,
52
+ :onebox_allowed_ports,
53
+ :onebox_open_timeout,
54
+ :onebox_read_timeout,
55
+ :onebox_max_response_bytes,
56
+ :onebox_max_redirects,
57
+ :onebox_user_agent,
58
+ :onebox_cache_ttl,
59
+ :onebox_twitch_parent_hosts,
60
+ :visit_inactivity_window,
61
+ :attachment_allowed_types,
62
+ :attachment_max_size,
63
+ :allow_member_created_tags,
64
+ :max_tags_per_topic,
65
+ :search_adapter,
66
+ :can_access_board,
67
+ :presence_enabled,
68
+ :presence_visibility,
69
+ :presence_redis_url,
70
+ :presence_heartbeat_interval,
71
+ :presence_expiration,
72
+ :presence_away_after,
73
+ :presence_recently_active_window,
74
+ :gamification_enabled,
75
+ :leaderboard_enabled,
76
+ :gamification_topic_points,
77
+ :gamification_reply_points,
78
+ :licensing_api_url,
79
+ :licensing_open_timeout,
80
+ :licensing_read_timeout,
81
+ :licensing_verification_interval,
82
+ :licensing_retry_interval
83
+
84
+ def initialize
85
+ @community_name = "RailsDen"
86
+ @user_class = "User"
87
+ @current_user_method = :current_user
88
+ @current_user_resolver = nil
89
+ @authentication_method = :authenticate_user!
90
+ @authentication_handler = nil
91
+ @parent_controller = "ApplicationController"
92
+ @registration_enabled = true
93
+ @public_revision_history = false
94
+ @user_display_name_method = :username
95
+ @user_mention_name_method = :username
96
+ @user_mention_resolver = nil
97
+
98
+ # Receives a normalized prefix and bounded limit, and returns host identities.
99
+ @user_mention_candidates_resolver = nil
100
+
101
+ # Receives a normalized search query and bounded limit, and returns host identities.
102
+ @user_search_resolver = nil
103
+
104
+ @user_mention_path_resolver = nil
105
+ @formatting_adapter = :markdown
106
+ @onebox_enabled = true
107
+ @onebox_allowed_ports = [80, 443]
108
+ @onebox_open_timeout = 3
109
+ @onebox_read_timeout = 5
110
+ @onebox_max_response_bytes = 2 * 1024 * 1024
111
+ @onebox_max_redirects = 5
112
+ @onebox_user_agent = "RailsDen Onebox"
113
+ @onebox_cache_ttl = 86_400
114
+ @onebox_twitch_parent_hosts = []
115
+ @visit_inactivity_window = 30.minutes
116
+ @attachment_allowed_types =
117
+ DEFAULT_ATTACHMENT_ALLOWED_TYPES
118
+ .transform_values(&:dup)
119
+ @attachment_max_size = 10.megabytes
120
+ @allow_member_created_tags = false
121
+ @max_tags_per_topic = 5
122
+
123
+ # Portable by default. PostgreSQL hosts may opt into :postgresql.
124
+ @search_adapter = :basic
125
+
126
+ # Optional host-defined board eligibility gate.
127
+ #
128
+ # Receives:
129
+ # user, board
130
+ #
131
+ # Returns:
132
+ # false - deny access to the board
133
+ # true - eligible; continue through RailsDen permissions
134
+ # nil - no host decision; continue through RailsDen permissions
135
+ @can_access_board = nil
136
+
137
+ @presence_enabled = true
138
+ @presence_visibility = :members_only
139
+
140
+ @presence_redis_url =
141
+ ENV["RAILS_DEN_REDIS_URL"]
142
+ .to_s
143
+ .strip
144
+
145
+ if @presence_redis_url.empty?
146
+ @presence_redis_url =
147
+ ENV["REDIS_URL"]
148
+ .to_s
149
+ .strip
150
+ end
151
+
152
+ if @presence_redis_url.empty?
153
+ @presence_redis_url =
154
+ "redis://127.0.0.1:6379/0"
155
+ end
156
+
157
+ @presence_heartbeat_interval = 30.seconds
158
+ @presence_expiration = 90.seconds
159
+ @presence_away_after = 5.minutes
160
+ @presence_recently_active_window = 24.hours
161
+
162
+ @gamification_enabled = true
163
+ @leaderboard_enabled = false
164
+ @gamification_topic_points = 5
165
+ @gamification_reply_points = 2
166
+ @licensing_api_url = nil
167
+ @licensing_open_timeout = 3
168
+ @licensing_read_timeout = 5
169
+ @licensing_verification_interval = 24.hours
170
+ @licensing_retry_interval = 1.hour
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,10 @@
1
+ module RailsDen
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace RailsDen
4
+
5
+ initializer "rails_den.configure_react_rails",
6
+ before: "react_rails.setup_engine" do |app|
7
+ app.config.react.sprockets_strategy = false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,138 @@
1
+ require "pathname"
2
+ require "rubygems/requirement"
3
+ require "rubygems/version"
4
+
5
+ module RailsDen
6
+ module Extensions
7
+ class Descriptor
8
+ TYPES = %i[plugin theme].freeze
9
+ KEY_PATTERN = /\A[a-z0-9][a-z0-9_]*\z/
10
+
11
+ attr_reader :type,
12
+ :key,
13
+ :name,
14
+ :version,
15
+ :rails_den_requirement,
16
+ :license_product,
17
+ :license_key,
18
+ :view_path,
19
+ :stylesheet,
20
+ :javascript
21
+
22
+ def initialize(
23
+ type:,
24
+ key:,
25
+ name:,
26
+ version:,
27
+ rails_den_requirement:,
28
+ license_product: nil,
29
+ license_key: nil,
30
+ view_path: nil,
31
+ stylesheet: nil,
32
+ javascript: nil
33
+ )
34
+ @type = normalize_type(type)
35
+ @key = normalize_key(key).freeze
36
+ @name = normalize_required_string(name, "name").freeze
37
+ @parsed_version = Gem::Version.new(version.to_s.strip).freeze
38
+ @version = @parsed_version.to_s.freeze
39
+ @parsed_requirement = Gem::Requirement.new(rails_den_requirement.to_s.strip).freeze
40
+ @rails_den_requirement = @parsed_requirement.to_s.freeze
41
+ @license_product = normalize_optional_string(license_product)&.freeze
42
+ @license_key = normalize_optional_string(license_key)&.freeze
43
+ validate_license_metadata!
44
+ @view_path = normalize_view_path(view_path)&.freeze
45
+ @stylesheet = normalize_optional_string(stylesheet)&.freeze
46
+ @javascript = normalize_optional_string(javascript)&.freeze
47
+ @attributes = build_attributes.freeze
48
+
49
+ freeze
50
+ rescue ArgumentError => error
51
+ raise InvalidDescriptorError, error.message
52
+ end
53
+
54
+ def licensed?
55
+ !license_product.nil?
56
+ end
57
+
58
+ def compatible?
59
+ @parsed_requirement.satisfied_by?(
60
+ Gem::Version.new(RailsDen::VERSION)
61
+ )
62
+ end
63
+
64
+ def theme?
65
+ type == :theme
66
+ end
67
+
68
+ def plugin?
69
+ type == :plugin
70
+ end
71
+
72
+ def to_h
73
+ @attributes
74
+ end
75
+
76
+ private
77
+
78
+ def normalize_type(value)
79
+ normalized = value.to_sym
80
+ return normalized if TYPES.include?(normalized)
81
+
82
+ raise InvalidDescriptorError,
83
+ "type must be plugin or theme"
84
+ rescue NoMethodError
85
+ raise InvalidDescriptorError,
86
+ "type must be plugin or theme"
87
+ end
88
+
89
+ def normalize_key(value)
90
+ normalized = normalize_required_string(value, "key")
91
+ return normalized if KEY_PATTERN.match?(normalized)
92
+
93
+ raise InvalidDescriptorError,
94
+ "key must contain only lowercase letters, numbers, and underscores"
95
+ end
96
+
97
+ def normalize_required_string(value, attribute)
98
+ normalized = value.to_s.strip
99
+ return normalized unless normalized.empty?
100
+
101
+ raise InvalidDescriptorError,
102
+ "#{attribute} must be present"
103
+ end
104
+
105
+ def normalize_optional_string(value)
106
+ normalized = value.to_s.strip
107
+ normalized unless normalized.empty?
108
+ end
109
+
110
+ def normalize_view_path(value)
111
+ normalized = normalize_optional_string(value)
112
+ Pathname.new(normalized) if normalized
113
+ end
114
+
115
+ def validate_license_metadata!
116
+ return if license_product.nil? == license_key.nil?
117
+
118
+ raise InvalidDescriptorError,
119
+ "license_product and license_key must be supplied together"
120
+ end
121
+
122
+ def build_attributes
123
+ {
124
+ type: type,
125
+ key: key,
126
+ name: name,
127
+ version: version,
128
+ rails_den_requirement: rails_den_requirement,
129
+ license_product: license_product,
130
+ license_key: license_key,
131
+ view_path: view_path,
132
+ stylesheet: stylesheet,
133
+ javascript: javascript
134
+ }
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,65 @@
1
+ require "thread"
2
+
3
+ module RailsDen
4
+ module Extensions
5
+ class Registry
6
+ def initialize
7
+ @descriptors = {}
8
+ @mutex = Mutex.new
9
+ end
10
+
11
+ def register(descriptor)
12
+ unless descriptor.compatible?
13
+ raise IncompatibleVersionError,
14
+ "#{descriptor.name} requires RailsDen #{descriptor.rails_den_requirement}"
15
+ end
16
+
17
+ @mutex.synchronize do
18
+ existing = @descriptors[descriptor.key]
19
+
20
+ if existing
21
+ return existing if existing.to_h == descriptor.to_h
22
+
23
+ raise DuplicateRegistrationError,
24
+ "extension key #{descriptor.key.inspect} is already registered"
25
+ end
26
+
27
+ @descriptors[descriptor.key] = descriptor
28
+ end
29
+
30
+ descriptor
31
+ end
32
+
33
+ def all
34
+ query
35
+ end
36
+
37
+ def plugins
38
+ query(&:plugin?)
39
+ end
40
+
41
+ def themes
42
+ query(&:theme?)
43
+ end
44
+
45
+ def find(key)
46
+ @mutex.synchronize do
47
+ @descriptors[key.to_s.strip]
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def query(&filter)
54
+ @mutex.synchronize do
55
+ descriptors = @descriptors.values
56
+ descriptors = descriptors.select(&filter) if filter
57
+
58
+ descriptors
59
+ .sort_by { |descriptor| [descriptor.name.downcase, descriptor.key] }
60
+ .freeze
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end