thredded 1.1.0 → 1.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19cde941264a9f9b9427694c27cc5f2a668fd18debbfe459d3fc58087e5636bf
4
- data.tar.gz: 0d4eec1e395f2265783f9283ad958ec2a7f486a017bb961af87b26c2fd711c20
3
+ metadata.gz: be8026fdf40f38f7143784b548e10f87d2606358ae302e81f536713feb0c59a6
4
+ data.tar.gz: abcbc174119805d870fd2c51b6985524b0f9123dccdfcd26b8e206417b04b333
5
5
  SHA512:
6
- metadata.gz: f7d6aa4fd6d1eaecda06e839b757d6fa2bbf7fd24ae6ef4ba3c238a5d8880baeff1be6b9ee2aae21b34c8f844d0aa5eb5c41a1f70e7841cbe867a900e29b980a
7
- data.tar.gz: 04af99833299683e35b13468e957bd75880a1627db1ff6c9ab53e1678f99842b273cc50ed529c9cddeedb7600c0d54b404550fd8858a7901346d6c72df77bdb2
6
+ metadata.gz: c74687299ccd1435304a97057d7c2430e6c1af13bf3f62ef63a1d6fdcd811d67225782337ccc5018d97cb4cee34bfbb5d9231d0fcd041351eed8a93984ca783e
7
+ data.tar.gz: df93c85e83e7c7be26eeb8ece54167ae279ad5988fd21693a287922e492c0ddcbb25e75bbe3c460dda2cfaa991c2f7801a5eae4bb96083ceacfdada8ccccb7eb
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
- # Thredded [![Code Climate](https://codeclimate.com/github/thredded/thredded/badges/gpa.svg)](https://codeclimate.com/github/thredded/thredded) [![Travis-CI](https://api.travis-ci.org/thredded/thredded.svg?branch=main)](https://travis-ci.org/thredded/thredded/) [![Test Coverage](https://codeclimate.com/github/thredded/thredded/badges/coverage.svg)](https://codeclimate.com/github/thredded/thredded/coverage) [![Inline docs](http://inch-ci.org/github/thredded/thredded.svg?branch=main)](http://inch-ci.org/github/thredded/thredded) [![Gitter](https://badges.gitter.im/thredded/thredded.svg)](https://gitter.im/thredded/thredded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
1
+ # Thredded
2
+ [![Code Climate](https://codeclimate.com/github/thredded/thredded/badges/gpa.svg)](https://codeclimate.com/github/thredded/thredded) [![Test Coverage](https://codeclimate.com/github/thredded/thredded/badges/coverage.svg)](https://codeclimate.com/github/thredded/thredded/coverage) [![Inline docs](http://inch-ci.org/github/thredded/thredded.svg?branch=main)](http://inch-ci.org/github/thredded/thredded) [![Gitter](https://badges.gitter.im/thredded/thredded.svg)](https://gitter.im/thredded/thredded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
3
+ [![CI](https://github.com/thredded/thredded/actions/workflows/build.yml/badge.svg)](https://github.com/thredded/thredded/actions/workflows/build.yml)
2
4
 
3
- _Thredded_ is a Rails 6.0+ forum/messageboard engine. Its goal is to be as simple and feature rich as possible.
5
+ _Thredded_ is a Rails 7.0+ forum/messageboard engine. Its goal is to be as simple and feature rich as possible.
4
6
 
5
7
  Some of the features currently in Thredded:
6
8
 
@@ -21,10 +23,10 @@ Some of the features currently in Thredded:
21
23
 
22
24
  Thredded works with SQLite, MySQL (v5.6.4+), and PostgreSQL. Thredded has no infrastructure
23
25
  dependencies other than the database and, if configured in the parent application, the ActiveJob
24
- backend dependency such as Redis. Currently only MRI Ruby 2.2+ is supported. We would love to
26
+ backend dependency such as Redis. Currently only MRI Ruby 3.1+ is supported. We would love to
25
27
  support JRuby and Rubinius as well.
26
28
 
27
- If you're looking for variations on a theme - see [Discourse]. However, It is a full rails
29
+ If you're looking for variations on a theme - see [Discourse]. However, it is a full rails
28
30
  application and not an engine like Thredded.
29
31
 
30
32
  [Discourse]: http://www.discourse.org/
@@ -78,7 +80,15 @@ Table of Contents
78
80
 
79
81
  ### Creating a new Rails app with Thredded
80
82
 
81
- Thredded provides an app generator that will generate a Rails app with Thredded, Devise, SimpleForm, RSpec,
83
+ > [!CAUTION]
84
+ > Please add thredded_create_app is currently out of date and needs contributors to fix it - it won't work with the latest thredded. See https://github.com/thredded/thredded_create_app if you can contribute.
85
+
86
+ <details>
87
+ <summary>
88
+ View the outdated instructions
89
+ </summary>
90
+
91
+ Thredded provides an app generator that will generate a Rails app with Thredded, Devise, SimpleForm, RSpec,
82
92
  PostgreSQL, and a basic theme and navigation that is configured to work out of the box.
83
93
 
84
94
  ```sh
@@ -92,12 +102,14 @@ Then, see the rest of this Readme for more information about using and customizi
92
102
 
93
103
  [thredded_create_app repo]: https://github.com/thredded/thredded_create_app
94
104
 
105
+ </details>
106
+
95
107
  ### Adding Thredded to an existing Rails app
96
108
 
97
109
  Add the gem to your Gemfile:
98
110
 
99
111
  ```ruby
100
- gem 'thredded', '~> 1.1'
112
+ gem 'thredded', '~> 1.2'
101
113
  ```
102
114
 
103
115
  Add the Thredded [initializer] to your parent app by running the install generator.
@@ -158,11 +170,13 @@ to Thredded.
158
170
 
159
171
  ## Rails compatibility
160
172
 
161
- | Rails | Latest Thredded |
162
- | ------------- |------------------|
163
- | Rails 6.0+ | Thredded 1.1+ |
164
- | Rails 5.2 | Thredded 1.0.1 |
165
- | Rails 4.2 | Thredded 0.16.16 |
173
+ | Rails | Latest Thredded |
174
+ |-----------------------|-----------------|
175
+ | Rails 7.0 - Rails 8.0 | Thredded 1.2 |
176
+ | Rails 6.1 | Thredded 1.1 |
177
+ | Rails 6.0 | Thredded 1.1 |
178
+ | Rails 5.2 | Thredded 1.0.1 |
179
+ | Rails 4.2 | Thredded 0.16.16 |
166
180
 
167
181
 
168
182
  ## Views and other assets
@@ -257,8 +271,7 @@ which are placed in the same order as in the source).
257
271
 
258
272
  <details><summary><b>Rails UJS version</b></summary>
259
273
 
260
- By default, thredded loads `rails-ujs`. If you're using Rails before v5.1, you need to add `rails-ujs` to
261
- your Gemfile.
274
+ By default, thredded loads `rails-ujs`.
262
275
 
263
276
  If you'd like it to use `jquery_ujs` instead, run this command from your app directory:
264
277
 
@@ -332,7 +345,7 @@ Whenever possible, use the styles and i18n to customize Thredded to your needs.
332
345
  Thredded provides view hooks to customize the UI before/after/replacing individual components.
333
346
 
334
347
  View hooks allow you to render anything in the thredded view context.
335
- For example, to render a partial after the post content textarea, add the snippet below to
348
+ For example, to render a partial after the post content textarea, add the snippet below to
336
349
  the `config/initializers/thredded.rb` initializer:
337
350
 
338
351
  ```ruby
@@ -393,7 +406,7 @@ You can also turn off the email notifier totally, or add other notifiers (e.g. P
393
406
  the `Thredded.notifiers` configuration in your initializer. See the default initializer for examples.
394
407
 
395
408
  You must configure the address the email appears to be from (`Thredded.email_from`). This address is also used as the "To" address for both email notifcations, as all the recipients are on bcc.
396
-
409
+
397
410
  ### Enabling auto-follow
398
411
 
399
412
  In some cases, you'll want all users to auto-follow new messageboard topics by default. This might be useful
@@ -423,16 +436,16 @@ Here are the steps to ensure the best support for your language if it isn't Engl
423
436
  //= require timeago/locales/de
424
437
  //= require timeago/locales/pt_BR
425
438
  //= require thredded
426
- ```
427
-
439
+ ```
440
+
428
441
  Webpack:
429
-
442
+
430
443
  ```erb
431
444
  <% timeago_root = File.join(Gem.loaded_specs['timeago_js'].full_gem_path, 'assets', 'javascripts') %>
432
445
  import "<%= File.join(timeago_root, 'timeago.js') %>";
433
446
  <%= %w[de pt_BR].map { |locale| %(import "#{File.join(timeago_root, "timeago/locales/#{locale}.js")}";) } * "\n" %>
434
447
  <%= Thredded::WebpackAssets.javascripts %>
435
- ```
448
+ ```
436
449
 
437
450
  Note that it is important that timeago and its locales are required *before* Thredded.
438
451
 
@@ -701,9 +714,9 @@ brew install --cask chromium
701
714
  brew install --cask chromedriver
702
715
  ```
703
716
 
704
- To get better page saves (`page.save_and_open_page`) from local capybara specs ensure you are running the server locally
705
- and set `export CAPYBARA_ASSET_HOST=http://localhost:3000` (or whatever host/port your server is on) before running your
706
- test suite.
717
+ To get better page saves (`page.save_and_open_page`) from local capybara specs ensure you are running the server locally
718
+ and set `export CAPYBARA_ASSET_HOST=http://localhost:3000` (or whatever host/port your server is on) before running your
719
+ test suite.
707
720
 
708
721
  ### Ruby
709
722
 
@@ -796,25 +809,23 @@ To quickly try out _Thredded_ with the included dummy app, clone the source and
796
809
  start the included docker-compose.yml file with:
797
810
 
798
811
  ```console
799
- docker-compose build
800
- docker-compose up
812
+ docker compose build
813
+ docker compose up
801
814
  ```
802
815
 
803
816
  The above will build and run everything, daemonized, resulting in a running
804
- instance on port 9292. Running `docker-compose logs` will let you know when
817
+ instance on port 9292. Running `docker compose logs` will let you know when
805
818
  everything is up and running. Editing the source on your host machine will
806
819
  be reflected in the running docker'ized application.
807
820
 
808
- Note that when using [boot2docker](https://github.com/boot2docker/boot2docker)
809
- on a Mac make sure you visit the boot2docker host ip at
810
- `http://$(boot2docker ip):9292`.
811
-
812
- After booting up the containers you can run the test suite with the following:
821
+ You can run the test suite with the following (assuming you've already done `docker compose up`)
813
822
 
814
823
  ```console
815
- docker-compose run web bundle exec rake
824
+ docker compose exec web bundle exec rake
816
825
  ```
817
826
 
818
- The docker container uses PostgreSQL.
827
+ Alternatively you run a one-off dyno `docker compose run web bundle exec rake`
828
+
829
+ The docker container uses PostgreSQL
819
830
 
820
831
  [initializer]: https://github.com/thredded/thredded/blob/main/lib/generators/thredded/install/templates/initializer.rb
@@ -7,7 +7,7 @@ module Thredded
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- enum moderation_state: %i[pending_moderation approved blocked]
10
+ enum :moderation_state, { pending_moderation: 0, approved: 1, blocked: 2 }
11
11
  validates :moderation_state, presence: true
12
12
  end
13
13
  end
@@ -15,7 +15,7 @@ module Thredded
15
15
  @scope = @scope.joins(:topic_categories).merge(Thredded::TopicCategory.where(category_id: categories))
16
16
  end
17
17
  if text.present? || users.present?
18
- [search_topics, search_posts].compact.reduce(:union)
18
+ Thredded::Topic.union_scope(search_topics, search_posts)
19
19
  else
20
20
  @scope
21
21
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # simplified version of active_record_union https://github.com/brianhempel/active_record_union/blob/master/lib/active_record_union/active_record/relation/union.rb
4
+
5
+ module Thredded
6
+ module UnionScope
7
+ extend ActiveSupport::Concern
8
+ class_methods do
9
+ # @param left_relation [ActiveRecord::Relation]
10
+ # @param right_relation [ActiveRecord::Relation]
11
+ # @return [ActiveRecord::Relation]
12
+ def union_scope(left_relation, right_relation)
13
+ verify_relations!(left_relation, right_relation)
14
+ union_set = ArelCompat.union_new(self, left_relation.arel, right_relation.arel)
15
+ from_table = Arel::Nodes::TableAlias.new(union_set, arel_table.name)
16
+ unscoped.from(from_table)
17
+ end
18
+
19
+ private
20
+
21
+ def verify_relations!(left_relation, right_relation)
22
+ relations = [left_relation, right_relation]
23
+ includes_relations = relations.select { |r| r.includes_values.any? }
24
+
25
+ fail ArgumentError, 'Cannot union relation with includes.' if includes_relations.any?
26
+
27
+ preload_relations = relations.select { |r| r.preload_values.any? }
28
+ fail ArgumentError, 'Cannot union relation with preload.' if preload_relations.any?
29
+
30
+ eager_load_relations = relations.select { |r| r.eager_load_values.any? }
31
+ return unless eager_load_relations.any?
32
+
33
+ fail ArgumentError, 'Cannot union relation with eager load.'
34
+ end
35
+ end
36
+ end
37
+ end
@@ -3,7 +3,9 @@
3
3
  module Thredded
4
4
  class PostModerationRecord < ActiveRecord::Base
5
5
  include Thredded::ModerationState
6
- enum previous_moderation_state: moderation_states, _prefix: :previous
6
+
7
+ enum :previous_moderation_state, moderation_states, prefix: :previous
8
+
7
9
  validates :previous_moderation_state, presence: true
8
10
 
9
11
  scope :order_newest_first, -> { order(created_at: :desc, id: :desc) }
@@ -4,6 +4,7 @@ module Thredded
4
4
  class Topic < ActiveRecord::Base # rubocop:disable Metrics/ClassLength
5
5
  include Thredded::TopicCommon
6
6
  include Thredded::ContentModerationState
7
+ include Thredded::UnionScope
7
8
 
8
9
  scope :for_messageboard, ->(messageboard) { where(messageboard_id: messageboard.id) }
9
10
 
@@ -85,6 +86,8 @@ module Thredded
85
86
 
86
87
  delegate :name, to: :messageboard, prefix: true
87
88
 
89
+ before_create :ensure_last_post_at
90
+
88
91
  after_commit :update_messageboard_last_topic, on: :update, if: -> { previous_changes.include?('moderation_state') }
89
92
  after_commit :update_last_user_and_time_from_last_post!, if: -> { previous_changes.include?('moderation_state') }
90
93
 
@@ -203,5 +206,9 @@ module Thredded
203
206
  Thredded::Messageboard.find(messageboard_id).update_last_topic!
204
207
  end
205
208
  end
209
+
210
+ def ensure_last_post_at
211
+ self.last_post_at ||= Time.zone.now
212
+ end
206
213
  end
207
214
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Thredded
4
4
  class UserTopicFollow < ActiveRecord::Base
5
- enum reason: %i[manual posted mentioned auto]
5
+ enum :reason, { manual: 0, posted: 1, mentioned: 2, auto: 3 }
6
6
 
7
7
  belongs_to :user, inverse_of: :thredded_topic_follows, class_name: Thredded.user_class_name
8
8
  belongs_to :topic, inverse_of: :user_follows
@@ -12,7 +12,8 @@ module Thredded
12
12
 
13
13
  # shim to behave like postable-related (though actually only ever related to topic)
14
14
  alias_attribute :postable_id, :topic_id
15
- alias_attribute :postable, :topic
15
+ alias postable topic
16
+ alias postable= topic=
16
17
 
17
18
  # Creates a follow or finds the existing one.
18
19
  #
@@ -0,0 +1,284 @@
1
+ ---
2
+ uk:
3
+ thredded:
4
+ content_moderation_states:
5
+ content_blocked_notice: Заблоковано
6
+ content_blocked_notice_with_record_html: Заблоковано користувачем %{moderator} %{time_ago}
7
+ email_notifier:
8
+ by_email: електронною поштою
9
+ emails:
10
+ message_notification:
11
+ html:
12
+ email_sent_reason_html: >-
13
+ Цей електронний лист надіслано вам, оскільки %{user} включив вас до приватної теми "<a href="%{post_url}">%{topic_title}</a>".
14
+ post_lead_html: 'Нове повідомлення від %{user} в <a href="%{post_url}">«%{topic_title}»</a>:'
15
+ unsubscribe_instructions_html: :thredded.emails.post_notification.html.unsubscribe_instructions_html
16
+ subject: Нове повідомлення від %{user} в «%{topic_title}»
17
+ text:
18
+ email_sent_reason: |-
19
+ Цей електронний лист надіслано вам, оскільки %{user} включив вас до
20
+ приватної теми «%{topic_title}».
21
+
22
+ Перейдіть сюди, щоб переглянути розмову:
23
+ %{post_url}
24
+ post_lead: 'Нове повідомлення від %{user} в «%{topic_title}»:'
25
+ unsubscribe_instructions: :thredded.emails.post_notification.text.unsubscribe_instructions
26
+ post_notification:
27
+ html:
28
+ email_sent_reason_html: >-
29
+ Цей електронний лист надіслано вам, оскільки ви стежите за цією темою: "<a href="%{post_url}">%{topic_title}</a>".
30
+ post_lead_html: '%{user} <a href="%{post_url}">написав у «%{topic_title}»</a>:'
31
+ unsubscribe_instructions_html: Щоб відписатися від цих електронних листів, оновіть свої <a href="%{preferences_url}">налаштування</a>.
32
+ subject: Новий допис у «%{topic_title}»
33
+ text:
34
+ email_sent_reason: |-
35
+ Цей електронний лист надіслано вам, оскільки ви стежите за
36
+ темою «%{topic_title}».
37
+
38
+ Перейдіть сюди, щоб переглянути розмову:
39
+ %{post_url}
40
+ post_lead: "%{user} написав у «%{topic_title}»:"
41
+ unsubscribe_instructions: |-
42
+ Щоб відписатися від цих електронних листів, оновіть свої налаштування тут:
43
+ %{unsubscribe_url}
44
+ errors:
45
+ login_required: Будь ласка, увійдіть спочатку.
46
+ not_authorized: Ви не маєте дозволу на доступ до цієї сторінки.
47
+ post_not_found: Цей допис не існує.
48
+ private_post_not_found: Це приватне повідомлення не існує.
49
+ private_topic_create_denied: Ви не маєте дозволу на створення приватних тем.
50
+ private_topic_not_found: Ця приватна тема не існує.
51
+ topic_not_found: Ця тема не існує.
52
+ form:
53
+ create_btn_submitting: Створення...
54
+ preview: Попередній перегляд
55
+ update: Оновити
56
+ update_btn_submitting: Оновлення...
57
+ messageboard:
58
+ create: Створити нову дошку повідомлень
59
+ deleted_notice: Дошку повідомлень видалено
60
+ form:
61
+ create_btn_submitting: :thredded.form.create_btn_submitting
62
+ delete: Видалити дошку повідомлень
63
+ delete_confirm: >-
64
+ Це видалить дошку повідомлень %{messageboard_name} та всі її дописи. Ви не зможете відновити її. Ви впевнені,
65
+ що хочете це зробити?
66
+ description_label: Опис
67
+ locked_label: Заблоковано
68
+ locked_notice: Ця дошка повідомлень заблокована. Лише модератори можуть створювати нові теми тут.
69
+ messageboard_group_id_label: Група дошки повідомлень
70
+ no_group: Без групи
71
+ title_label: Назва
72
+ update_btn_submitting: :thredded.form.update_btn_submitting
73
+ index:
74
+ page_title: Дошки повідомлень
75
+ last_updated_by_html: Оновлено %{time_ago} <cite>користувачем %{user}</cite>
76
+ topics_and_posts_counts: "%{posts_count} дописів у %{topics_count} темах"
77
+ topics_and_unread_topics_counts: "%{unread_topics_count} непрочитаних з %{topics_count} тем"
78
+ update: :thredded.form.update
79
+ updated_notice: Дошку повідомлень оновлено
80
+ messageboard_first_topic:
81
+ content: |-
82
+ Поки що тут не так багато.
83
+
84
+ Ці форуми працюють на [Thredded](https://github.com/thredded/thredded) v%{thredded_version}.
85
+ Ви можете зв'язатися з командою Thredded через [чат-кімнату Thredded](https://gitter.im/thredded/thredded).
86
+ Будь ласка, повідомте нам, що ви використовуєте Thredded, твітнувши [@thredded](https://twitter.com/thredded)!
87
+ title: Ласкаво просимо до першої теми вашої дошки повідомлень
88
+ messageboard_group:
89
+ create: Створити нову групу дошок повідомлень
90
+ form:
91
+ create_btn_submitting: :thredded.form.create_btn_submitting
92
+ saved: Групу дошок повідомлень %{name} створено
93
+ show:
94
+ page_title: 'Група дошок повідомлень: %{name}'
95
+ moderation:
96
+ approve_btn: Схвалити
97
+ block_btn: Заблокувати
98
+ moderation_state:
99
+ name: Стан модерації
100
+ pending:
101
+ empty:
102
+ content: Усі дописи пройшли модерацію.
103
+ title: Гарна робота!
104
+ post_approved_html: Допис схвалено користувачем %{moderator} %{time_ago}.
105
+ post_blocked_html: Допис заблоковано користувачем %{moderator} %{time_ago}.
106
+ post_deleted_notice: Цей допис було видалено.
107
+ posts_content_changed_since_moderation_html: Вміст <a href="%{post_url}">допису</a> змінився після модерації.
108
+ Нижче наведено вміст на момент модерації.
109
+ search_users:
110
+ form_label: Пошук користувачів
111
+ form_placeholder: :thredded.moderation.search_users.form_label
112
+ no_results_message: Немає користувачів, ім'я яких починається з %{query}
113
+ results_message: Користувачі з іменами, що починаються з %{query}
114
+ user:
115
+ name: Користувач
116
+ nav:
117
+ all_messageboards: Усі дошки повідомлень
118
+ edit_messageboard: Редагувати дошку повідомлень
119
+ edit_post: Редагувати допис
120
+ edit_private_topic: :thredded.nav.edit_topic
121
+ edit_topic: Редагувати
122
+ mark_all_read: Позначити все як прочитане
123
+ moderation: Модерація
124
+ moderation_activity: Активність
125
+ moderation_history: Історія
126
+ moderation_pending: Очікує
127
+ moderation_users: Користувачі
128
+ private_topics: Приватні повідомлення
129
+ settings: Налаштування сповіщень
130
+ sign_in: Увійти / Зареєструватися
131
+ sign_out: Вийти
132
+ unread_topics: Непрочитані
133
+ null_user_name: Видалений користувач
134
+ posts:
135
+ delete: Видалити допис
136
+ delete_confirm: Ви впевнені, що хочете видалити цей допис?
137
+ deleted_notice: Ваш допис видалено.
138
+ edit: :thredded.nav.edit_post
139
+ form:
140
+ content_label: Вміст
141
+ create_btn: Надіслати відповідь
142
+ create_btn_submitting: Публікація...
143
+ title_label: Додати допис
144
+ update_btn: Оновити допис
145
+ update_btn_submitting: :thredded.form.update_btn_submitting
146
+ pending_moderation_notice: Ваш допис буде опубліковано після перевірки модератором.
147
+ quote_btn: Цитувати
148
+ spoiler_summary: Спойлер - натисніть, щоб показати.
149
+ spoiler_summary_for_email: 'Спойлер - виділіть вміст нижче, щоб побачити:'
150
+ preferences:
151
+ edit:
152
+ page_title: :thredded.nav.settings
153
+ form:
154
+ auto_follow_topics:
155
+ hint: Автоматично стежити за всіма новими темами. Зміна цього налаштування змінить його для всіх дошок
156
+ повідомлень.
157
+ label: Стежити за всіма новими темами
158
+ follow_topics_on_mention:
159
+ hint: 'Коли хтось згадує вас за вашим ім''ям користувача (наприклад: @sam), ви будете стежити за темою.'
160
+ label: Стежити за темами, в яких вас згадують
161
+ messageboard_auto_follow_topics:
162
+ hint: >-
163
+ Автоматично стежити за всіма новими темами на цій дошці повідомлень. Це перевизначає відповідне налаштування
164
+ вище.
165
+ label: Стежити за всіма новими темами
166
+ messageboard_follow_topics_on_mention:
167
+ hint: >-
168
+ Коли хтось згадує вас за вашим ім'ям користувача (наприклад: @sam) на цій дошці повідомлень, ви будете
169
+ стежити за темою.
170
+ label: :thredded.preferences.form.follow_topics_on_mention.label
171
+ messageboard_notifications_for_followed_topics:
172
+ label: :thredded.preferences.form.notifications_for_followed_topics.label
173
+ notifications_for_followed_topics:
174
+ label: Сповіщення для тем, за якими ви стежите
175
+ notifications_for_private_topics:
176
+ label: Сповіщення для приватних повідомлень
177
+ submit_btn: Оновити налаштування
178
+ update_btn_submitting: :thredded.form.update_btn_submitting
179
+ global_preferences_title: Глобальні налаштування
180
+ messageboard_preferences_nav_title: Налаштування дошки повідомлень
181
+ messageboard_preferences_title_html: Налаштування для <em>%{messageboard}</em>
182
+ updated_notice: Ваші налаштування оновлено.
183
+ private_posts:
184
+ form:
185
+ content_label: Повідомлення
186
+ create_btn: Надіслати повідомлення
187
+ create_btn_submitting: Надсилання...
188
+ update_btn_submitting: :thredded.form.update_btn_submitting
189
+ private_topics:
190
+ create: :thredded.private_topics.form.create_btn
191
+ edit: Редагувати
192
+ errors:
193
+ user_ids_length: Будь ласка, вкажіть принаймні одного іншого користувача.
194
+ form:
195
+ content_label: :thredded.private_posts.form.content_label
196
+ create_btn: :thredded.private_posts.form.create_btn
197
+ create_btn_submitting: :thredded.private_posts.form.create_btn_submitting
198
+ title_label: :thredded.topics.form.title_label
199
+ title_placeholder_new: Напишіть тему цієї розмови
200
+ title_placeholder_start: Почати нову розмову
201
+ update_btn: Оновити
202
+ update_btn_submitting: :thredded.private_posts.form.update_btn_submitting
203
+ users_label: Учасники
204
+ users_placeholder: Виберіть користувачів для участі в цій розмові
205
+ no_private_topics:
206
+ create_btn: Почати першу приватну розмову
207
+ title: У вас немає приватних повідомлень.
208
+ updated_notice: Назву оновлено
209
+ recent_activity: Нещодавня активність
210
+ search:
211
+ form:
212
+ btn_submit: :thredded.search.form.label
213
+ label: Пошук
214
+ placeholder: Пошук тем і дописів
215
+ time_ago: "%{time} тому"
216
+ topics:
217
+ create: :thredded.topics.form.create_btn
218
+ delete_confirm: Ви впевнені, що хочете видалити цю тему? Це НЕ МОЖНА скасувати.
219
+ delete_topic: Видалити тему
220
+ deleted_notice: Тему видалено
221
+ edit: Редагувати тему
222
+ follow: Стежити за цією темою
223
+ followed_by: 'Стежать:'
224
+ followed_by_noone: Ніхто не стежить за цією темою
225
+ followed_notice: Тепер ви стежите за цією темою
226
+ following:
227
+ auto: Ви стежите за цією темою, оскільки увімкнено автоматичне стеження.
228
+ manual: Ви стежите за цією темою.
229
+ mentioned: Ви стежите за цією темою, оскільки вас у ній згадували.
230
+ posted: Ви стежите за цією темою, оскільки ви в ній писали.
231
+ form:
232
+ categories_placeholder: Категорії
233
+ content_label: :thredded.posts.form.content_label
234
+ create_btn: Створити нову тему
235
+ messageboard_label: Дошка повідомлень
236
+ title_label: Назва
237
+ title_placeholder: :thredded.topics.form.title_label
238
+ title_placeholder_start: Почати нову тему
239
+ update_btn: Оновити тему
240
+ in_messageboard_html: в %{messageboard_link}
241
+ locked:
242
+ label: Заблоковано
243
+ message: Цю тему заблоковано модератором.
244
+ mark_as_unread: Позначити як непрочитане звідси
245
+ not_following: Ви не стежите за цією темою.
246
+ search:
247
+ no_results_in_messageboard_message_html: Немає результатів для вашого пошуку <q>%{query}</q> в %{messageboard}
248
+ no_results_message_html: Немає результатів для вашого пошуку <q>%{query}</q>
249
+ page_title: Результати пошуку тем
250
+ results_in_messageboard_message_html: Результати пошуку для <q>%{query}</q> в %{messageboard}
251
+ results_message_html: Результати пошуку для <q>%{query}</q>
252
+ search_in_all_messageboards_btn: Шукати всюди
253
+ started_by_html: Створено %{time_ago} користувачем %{user}
254
+ sticky:
255
+ label: Закріплено
256
+ unfollow: Припинити стеження
257
+ unfollowed_notice: Ви більше не стежите за цією темою
258
+ updated_notice: Тему оновлено
259
+ unread_topics:
260
+ empty:
261
+ content: Ви прочитали все, що є. Поверніться пізніше за новим контентом!
262
+ title: Все прочитано!
263
+ page_title: Непрочитані теми
264
+ page_title_in_messageboard: "%{messageboard}: Непрочитані теми"
265
+ users:
266
+ currently_online: Зараз онлайн
267
+ last_active_html: Остання активність %{time_ago}
268
+ posted_in_topic_html: Написав у %{topic_link}
269
+ posts_count:
270
+ few: Написав %{count} рази
271
+ many: Написав %{count} разів
272
+ one: Написав один раз
273
+ other: Написав %{count} разів
274
+ recent_activity: :thredded.recent_activity
275
+ send_private_message: Надіслати приватне повідомлення
276
+ started_topic_html: Створив %{topic_link}
277
+ started_topics_count:
278
+ few: Створив %{count} теми
279
+ many: Створив %{count} тем
280
+ one: Створив %{count} тему
281
+ other: Створив %{count} тем
282
+ user_posted_in_topic_html: "%{user_link} написав у %{topic_link}"
283
+ user_since_html: Користувач з %{time_ago}
284
+ user_started_topic_html: "%{user_link} створив %{topic_link}"
@@ -15,5 +15,21 @@ module Thredded
15
15
  Arel::Nodes::Division.new(a, b)
16
16
  end
17
17
  end
18
+
19
+ # @param [#connection] engine_or_model_class
20
+ # @param [Arel::Nodes::Node] left
21
+ # @param [Arel::Nodes::Node] right
22
+ # @return [Arel::Nodes::Node] union of left and right
23
+ # extract and simplified from https://github.com/brianhempel/active_record_union/blob/master/lib/active_record_union/active_record/relation/union.rb
24
+ def union_new(engine_or_model_class, left, right)
25
+ if /sqlite/i.match?(engine_or_model_class.connection.adapter_name)
26
+ # Postgres allows ORDER BY in the UNION subqueries if each subquery is surrounded by parenthesis
27
+ # but SQLite does not allow parens around the subqueries
28
+ Arel::Nodes::Union.new(left.ast, right.ast)
29
+ else
30
+ # By default this adds parentheses which sqlite does not allow
31
+ Arel::Nodes::Union.new(left, right)
32
+ end
33
+ end
18
34
  end
19
35
  end
@@ -60,16 +60,16 @@ module Thredded
60
60
  digest_path = digest_path_from_template(view, template)
61
61
 
62
62
  collection.each_with_object([{}, []]) do |item, (hash, ordered_keys)|
63
- key = expanded_cache_key(item, view, template, digest_path)
63
+ key = expanded_cache_key(item, view, digest_path)
64
64
  ordered_keys << key
65
65
  hash[key] = item
66
66
  end
67
67
  end
68
68
 
69
- def expanded_cache_key(key, view, template, digest_path)
69
+ def expanded_cache_key(key, view, digest_path)
70
70
  key = combined_fragment_cache_key(
71
71
  view,
72
- cache_fragment_name(view, key, virtual_path: template.virtual_path, digest_path: digest_path)
72
+ cache_fragment_name(view, key, digest_path: digest_path)
73
73
  )
74
74
  key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
75
75
  end
@@ -106,22 +106,15 @@ module Thredded
106
106
  end
107
107
  end
108
108
 
109
- if Thredded::Compat.rails_gte_61?
110
- # @param [Array<Object>] collection
111
- # @param [Hash] opts
112
- # @param view_context
113
- # @return [Array<String>]
114
- def render_partials_serial(view_context, collection, opts)
115
- # https://github.com/rails/rails/pull/38594
116
- collection.map do |object|
117
- renderer = ActionView::ObjectRenderer.new(@lookup_context, opts)
118
- renderer.render_object_with_partial(object, opts[:partial], view_context, nil).body
119
- end
120
- end
121
- else
122
- def render_partials_serial(view_context, collection, opts)
123
- partial_renderer = ActionView::PartialRenderer.new(@lookup_context)
124
- collection.map { |object| render_partial(partial_renderer, view_context, **opts.merge(object: object)) }
109
+ # @param [Array<Object>] collection
110
+ # @param [Hash] opts
111
+ # @param view_context
112
+ # @return [Array<String>]
113
+ def render_partials_serial(view_context, collection, opts)
114
+ # https://github.com/rails/rails/pull/38594
115
+ collection.map do |object|
116
+ renderer = ActionView::ObjectRenderer.new(@lookup_context, opts)
117
+ renderer.render_object_with_partial(object, opts[:partial], view_context, nil).body
125
118
  end
126
119
  end
127
120
 
@@ -133,12 +126,8 @@ module Thredded
133
126
  view.combined_fragment_cache_key(key)
134
127
  end
135
128
 
136
- def cache_fragment_name(view, key, virtual_path:, digest_path:)
137
- if Thredded::Compat.rails_gte_61?
138
- view.cache_fragment_name(key, digest_path: digest_path)
139
- else
140
- view.cache_fragment_name(key, virtual_path: virtual_path, digest_path: digest_path)
141
- end
129
+ def cache_fragment_name(view, key, digest_path:)
130
+ view.cache_fragment_name(key, digest_path: digest_path)
142
131
  end
143
132
 
144
133
  def digest_path_from_template(view, template)
@@ -4,25 +4,23 @@ module Thredded
4
4
  module Compat
5
5
  class << self
6
6
  # @api private
7
- def rails_gte_61?
8
- @rails_gte_61 = (Rails.gem_version >= Gem::Version.new('6.1.0')) if @rails_gte_61.nil?
9
- @rails_gte_61
7
+ def rails_gte_71?
8
+ @rails_gte_71 = (Rails.gem_version >= Gem::Version.new('7.1.0')) if @rails_gte_71.nil?
9
+ @rails_gte_71
10
10
  end
11
11
 
12
- if Rails.gem_version >= Gem::Version.new('7.0.0')
13
- # @api private
14
- def association_preloader(records:, associations:, scope:)
15
- ActiveRecord::Associations::Preloader.new(
16
- records: records, associations: associations, scope: scope
17
- ).call
18
- end
19
- else
20
- # @api private
21
- def association_preloader(records:, associations:, scope:)
22
- ActiveRecord::Associations::Preloader.new.preload(
23
- records, associations, scope
24
- )
25
- end
12
+ # @api private
13
+ def rails_gte_72?
14
+ @rails_gte_72 = (Rails.gem_version >= Gem::Version.new('7.2.0')) if @rails_gte_72.nil?
15
+ @rails_gte_72
16
+ end
17
+
18
+ # @api private
19
+ # TODO: inline this or put it somewhere else as it's no longer specific to a rails version
20
+ def association_preloader(records:, associations:, scope:)
21
+ ActiveRecord::Associations::Preloader.new(
22
+ records: records, associations: associations, scope: scope
23
+ ).call
26
24
  end
27
25
  end
28
26
  end
@@ -10,6 +10,7 @@ rescue NameError
10
10
  end
11
11
  # rubocop:enable HandleExceptions
12
12
  module Thredded
13
+ # rubocop:disable Metrics/MethodLength
13
14
  class DatabaseSeeder # rubocop:disable Metrics/ClassLength
14
15
  module LogTime
15
16
  def self.included(base)
@@ -60,8 +61,16 @@ module Thredded
60
61
  def self.with_seeder_tweaks
61
62
  # Disable callbacks to avoid creating notifications and performing unnecessary updates
62
63
  DISABLE_COUNTER_CACHE.each do |klass|
63
- klass.send(:alias_method, :original_each_counter_cached_associations, :each_counter_cached_associations)
64
- klass.send(:define_method, :each_counter_cached_associations) {}
64
+ if Thredded::Compat.rails_gte_72?
65
+ klass.class_eval do
66
+ class_attribute :original_counter_cached_association_names
67
+ self.original_counter_cached_association_names = counter_cached_association_names
68
+ self.counter_cached_association_names = []
69
+ end
70
+ else
71
+ klass.send(:alias_method, :original_each_counter_cached_associations, :each_counter_cached_associations)
72
+ klass.send(:define_method, :each_counter_cached_associations) {}
73
+ end
65
74
  end
66
75
  SKIP_CALLBACKS.each { |(klass, *args)| delete_callbacks(klass, *args) }
67
76
  WRITEABLE_READONLY_ATTRIBUTES.each { |(klass, attr)| klass.readonly_attributes.delete(attr) }
@@ -71,9 +80,15 @@ module Thredded
71
80
  ensure
72
81
  # Re-enable callbacks and counter cache
73
82
  DISABLE_COUNTER_CACHE.each do |klass|
74
- klass.send(:remove_method, :each_counter_cached_associations)
75
- klass.send(:alias_method, :each_counter_cached_associations, :original_each_counter_cached_associations)
76
- klass.send(:remove_method, :original_each_counter_cached_associations)
83
+ if Thredded::Compat.rails_gte_72?
84
+ klass.class_eval do
85
+ self.counter_cached_association_names = original_counter_cached_association_names
86
+ end
87
+ else
88
+ klass.send(:remove_method, :each_counter_cached_associations)
89
+ klass.send(:alias_method, :each_counter_cached_associations, :original_each_counter_cached_associations)
90
+ klass.send(:remove_method, :original_each_counter_cached_associations)
91
+ end
77
92
  end
78
93
  SKIP_CALLBACKS.each do |(klass, *args)|
79
94
  args = args.dup
@@ -150,9 +165,7 @@ module Thredded
150
165
  end
151
166
 
152
167
  def user_details
153
- @user_details ||= users.each_with_object({}) do |user, hash|
154
- hash[user] = user.thredded_user_detail
155
- end
168
+ @user_details ||= users.index_with(&:thredded_user_detail)
156
169
  end
157
170
 
158
171
  def first_messageboard
@@ -175,7 +188,7 @@ module Thredded
175
188
  end
176
189
  end
177
190
 
178
- log_method_time def update_messageboards_data(**) # `**` for Ruby < 2.5, see https://bugs.ruby-lang.org/issues/10856
191
+ log_method_time def update_messageboards_data(**)
179
192
  log 'Updating messageboards data...'
180
193
  Messageboard.all.each do |messageboard|
181
194
  messageboard.update_last_topic!
@@ -330,7 +343,7 @@ module Thredded
330
343
  class FirstMessageboard < FirstSeedData
331
344
  MODEL_CLASS = Messageboard
332
345
 
333
- log_method_time def create(**) # `**` for Ruby < 2.5, see https://bugs.ruby-lang.org/issues/10856
346
+ log_method_time def create(**)
334
347
  log 'Creating a messageboard...'
335
348
  @first_messageboard = FactoryBot.create(
336
349
  :messageboard,
@@ -384,7 +397,8 @@ module Thredded
384
397
  class Posts < CollectionSeedData
385
398
  MODEL_CLASS = Post
386
399
 
387
- log_method_time def create(count: (1..1), topics: seeder.topics) # rubocop:disable Metrics/MethodLength
400
+ log_method_time def create(count: (1..1), topics: seeder.topics)
401
+ # rubocop:disable Metrics/MethodLength
388
402
  log "Creating #{count} additional posts in each topic..."
389
403
  topics.flat_map do |topic|
390
404
  last_post_at = random_duration(0..256.hours).ago
@@ -446,4 +460,5 @@ module Thredded
446
460
  end
447
461
  end
448
462
  end
463
+ # rubocop:enable Metrics/MethodLength
449
464
  end
@@ -10,7 +10,7 @@ module Thredded
10
10
  verbose_was = ActiveRecord::Migration.verbose
11
11
  ActiveRecord::Migration.verbose = !quiet
12
12
  migrate =
13
- -> { ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration).migrate(nil, &filter) }
13
+ -> { ActiveRecord::MigrationContext.new(paths).migrate(nil, &filter) }
14
14
  if quiet
15
15
  silence_active_record(&migrate)
16
16
  else
@@ -20,5 +20,17 @@ module Thredded
20
20
  thredded_manifest.js
21
21
  ]
22
22
  end
23
+
24
+ config.after_initialize do |app|
25
+ next unless Rails.env.development? || Rails.env.test?
26
+ next unless app.config.assets.compile && app.assets
27
+
28
+ if app.assets.preprocessors.keys.exclude?('text/scss')
29
+ fail [
30
+ 'Thredded requires a Sass compiler to be registered in Sprockets.',
31
+ %(Please add "sassc-rails" or "dartsass-sprockets" to your application Gemfile.),
32
+ ].join(' ')
33
+ end
34
+ end
23
35
  end
24
36
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Thredded
4
- VERSION = '1.1.0'
4
+ VERSION = '1.2.1'
5
5
  end
data/lib/thredded.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  # Backend
4
4
  require 'pundit'
5
- require 'active_record_union'
6
5
  require 'db_text_search'
7
6
  require 'friendly_id'
8
7
  require 'html/pipeline'
@@ -29,7 +28,6 @@ require 'thredded/users_provider'
29
28
  require 'autoprefixer-rails'
30
29
  require 'timeago_js'
31
30
  require 'sprockets/es6'
32
- require 'sassc-rails'
33
31
 
34
32
  require 'thredded/version'
35
33
  require 'thredded/compat'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thredded
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Oliveira
@@ -9,22 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-02-18 00:00:00.000000000 Z
12
+ date: 2025-05-30 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: active_record_union
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: 1.3.0
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: 1.3.0
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: db_text_search
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -127,16 +113,16 @@ dependencies:
127
113
  name: rails
128
114
  requirement: !ruby/object:Gem::Requirement
129
115
  requirements:
130
- - - ">"
116
+ - - ">="
131
117
  - !ruby/object:Gem::Version
132
- version: 6.0.0.rc2
118
+ version: '7.0'
133
119
  type: :runtime
134
120
  prerelease: false
135
121
  version_requirements: !ruby/object:Gem::Requirement
136
122
  requirements:
137
- - - ">"
123
+ - - ">="
138
124
  - !ruby/object:Gem::Version
139
- version: 6.0.0.rc2
125
+ version: '7.0'
140
126
  - !ruby/object:Gem::Dependency
141
127
  name: rails_gravatar
142
128
  requirement: !ruby/object:Gem::Requirement
@@ -158,6 +144,9 @@ dependencies:
158
144
  - - ">="
159
145
  - !ruby/object:Gem::Version
160
146
  version: 2.14.1
147
+ - - "<"
148
+ - !ruby/object:Gem::Version
149
+ version: '3'
161
150
  type: :runtime
162
151
  prerelease: false
163
152
  version_requirements: !ruby/object:Gem::Requirement
@@ -165,6 +154,9 @@ dependencies:
165
154
  - - ">="
166
155
  - !ruby/object:Gem::Version
167
156
  version: 2.14.1
157
+ - - "<"
158
+ - !ruby/object:Gem::Version
159
+ version: '3'
168
160
  - !ruby/object:Gem::Dependency
169
161
  name: kramdown
170
162
  requirement: !ruby/object:Gem::Requirement
@@ -249,20 +241,6 @@ dependencies:
249
241
  - - ">="
250
242
  - !ruby/object:Gem::Version
251
243
  version: '0'
252
- - !ruby/object:Gem::Dependency
253
- name: sassc-rails
254
- requirement: !ruby/object:Gem::Requirement
255
- requirements:
256
- - - ">="
257
- - !ruby/object:Gem::Version
258
- version: 2.0.0
259
- type: :runtime
260
- prerelease: false
261
- version_requirements: !ruby/object:Gem::Requirement
262
- requirements:
263
- - - ">="
264
- - !ruby/object:Gem::Version
265
- version: 2.0.0
266
244
  - !ruby/object:Gem::Dependency
267
245
  name: sprockets-es6
268
246
  requirement: !ruby/object:Gem::Requirement
@@ -291,342 +269,6 @@ dependencies:
291
269
  - - ">="
292
270
  - !ruby/object:Gem::Version
293
271
  version: 3.0.2.2
294
- - !ruby/object:Gem::Dependency
295
- name: capybara
296
- requirement: !ruby/object:Gem::Requirement
297
- requirements:
298
- - - "~>"
299
- - !ruby/object:Gem::Version
300
- version: '3.0'
301
- type: :development
302
- prerelease: false
303
- version_requirements: !ruby/object:Gem::Requirement
304
- requirements:
305
- - - "~>"
306
- - !ruby/object:Gem::Version
307
- version: '3.0'
308
- - !ruby/object:Gem::Dependency
309
- name: capybara-screenshot
310
- requirement: !ruby/object:Gem::Requirement
311
- requirements:
312
- - - ">="
313
- - !ruby/object:Gem::Version
314
- version: '0'
315
- type: :development
316
- prerelease: false
317
- version_requirements: !ruby/object:Gem::Requirement
318
- requirements:
319
- - - ">="
320
- - !ruby/object:Gem::Version
321
- version: '0'
322
- - !ruby/object:Gem::Dependency
323
- name: cuprite
324
- requirement: !ruby/object:Gem::Requirement
325
- requirements:
326
- - - ">="
327
- - !ruby/object:Gem::Version
328
- version: '0.5'
329
- type: :development
330
- prerelease: false
331
- version_requirements: !ruby/object:Gem::Requirement
332
- requirements:
333
- - - ">="
334
- - !ruby/object:Gem::Version
335
- version: '0.5'
336
- - !ruby/object:Gem::Dependency
337
- name: database_cleaner-active_record
338
- requirement: !ruby/object:Gem::Requirement
339
- requirements:
340
- - - "~>"
341
- - !ruby/object:Gem::Version
342
- version: '2.0'
343
- type: :development
344
- prerelease: false
345
- version_requirements: !ruby/object:Gem::Requirement
346
- requirements:
347
- - - "~>"
348
- - !ruby/object:Gem::Version
349
- version: '2.0'
350
- - !ruby/object:Gem::Dependency
351
- name: factory_bot
352
- requirement: !ruby/object:Gem::Requirement
353
- requirements:
354
- - - ">="
355
- - !ruby/object:Gem::Version
356
- version: 5.0.2
357
- type: :development
358
- prerelease: false
359
- version_requirements: !ruby/object:Gem::Requirement
360
- requirements:
361
- - - ">="
362
- - !ruby/object:Gem::Version
363
- version: 5.0.2
364
- - !ruby/object:Gem::Dependency
365
- name: faker
366
- requirement: !ruby/object:Gem::Requirement
367
- requirements:
368
- - - ">="
369
- - !ruby/object:Gem::Version
370
- version: 1.9.3
371
- type: :development
372
- prerelease: false
373
- version_requirements: !ruby/object:Gem::Requirement
374
- requirements:
375
- - - ">="
376
- - !ruby/object:Gem::Version
377
- version: 1.9.3
378
- - !ruby/object:Gem::Dependency
379
- name: launchy
380
- requirement: !ruby/object:Gem::Requirement
381
- requirements:
382
- - - ">="
383
- - !ruby/object:Gem::Version
384
- version: '0'
385
- type: :development
386
- prerelease: false
387
- version_requirements: !ruby/object:Gem::Requirement
388
- requirements:
389
- - - ">="
390
- - !ruby/object:Gem::Version
391
- version: '0'
392
- - !ruby/object:Gem::Dependency
393
- name: rails-controller-testing
394
- requirement: !ruby/object:Gem::Requirement
395
- requirements:
396
- - - ">="
397
- - !ruby/object:Gem::Version
398
- version: '0'
399
- type: :development
400
- prerelease: false
401
- version_requirements: !ruby/object:Gem::Requirement
402
- requirements:
403
- - - ">="
404
- - !ruby/object:Gem::Version
405
- version: '0'
406
- - !ruby/object:Gem::Dependency
407
- name: rspec-rails
408
- requirement: !ruby/object:Gem::Requirement
409
- requirements:
410
- - - ">="
411
- - !ruby/object:Gem::Version
412
- version: 3.5.0
413
- type: :development
414
- prerelease: false
415
- version_requirements: !ruby/object:Gem::Requirement
416
- requirements:
417
- - - ">="
418
- - !ruby/object:Gem::Version
419
- version: 3.5.0
420
- - !ruby/object:Gem::Dependency
421
- name: simplecov
422
- requirement: !ruby/object:Gem::Requirement
423
- requirements:
424
- - - ">="
425
- - !ruby/object:Gem::Version
426
- version: '0'
427
- type: :development
428
- prerelease: false
429
- version_requirements: !ruby/object:Gem::Requirement
430
- requirements:
431
- - - ">="
432
- - !ruby/object:Gem::Version
433
- version: '0'
434
- - !ruby/object:Gem::Dependency
435
- name: webmock
436
- requirement: !ruby/object:Gem::Requirement
437
- requirements:
438
- - - ">="
439
- - !ruby/object:Gem::Version
440
- version: '0'
441
- type: :development
442
- prerelease: false
443
- version_requirements: !ruby/object:Gem::Requirement
444
- requirements:
445
- - - ">="
446
- - !ruby/object:Gem::Version
447
- version: '0'
448
- - !ruby/object:Gem::Dependency
449
- name: http_accept_language
450
- requirement: !ruby/object:Gem::Requirement
451
- requirements:
452
- - - ">="
453
- - !ruby/object:Gem::Version
454
- version: '0'
455
- type: :development
456
- prerelease: false
457
- version_requirements: !ruby/object:Gem::Requirement
458
- requirements:
459
- - - ">="
460
- - !ruby/object:Gem::Version
461
- version: '0'
462
- - !ruby/object:Gem::Dependency
463
- name: kaminari-i18n
464
- requirement: !ruby/object:Gem::Requirement
465
- requirements:
466
- - - ">="
467
- - !ruby/object:Gem::Version
468
- version: '0'
469
- type: :development
470
- prerelease: false
471
- version_requirements: !ruby/object:Gem::Requirement
472
- requirements:
473
- - - ">="
474
- - !ruby/object:Gem::Version
475
- version: '0'
476
- - !ruby/object:Gem::Dependency
477
- name: mysql2
478
- requirement: !ruby/object:Gem::Requirement
479
- requirements:
480
- - - ">="
481
- - !ruby/object:Gem::Version
482
- version: '0'
483
- type: :development
484
- prerelease: false
485
- version_requirements: !ruby/object:Gem::Requirement
486
- requirements:
487
- - - ">="
488
- - !ruby/object:Gem::Version
489
- version: '0'
490
- - !ruby/object:Gem::Dependency
491
- name: pg
492
- requirement: !ruby/object:Gem::Requirement
493
- requirements:
494
- - - ">="
495
- - !ruby/object:Gem::Version
496
- version: '0'
497
- type: :development
498
- prerelease: false
499
- version_requirements: !ruby/object:Gem::Requirement
500
- requirements:
501
- - - ">="
502
- - !ruby/object:Gem::Version
503
- version: '0'
504
- - !ruby/object:Gem::Dependency
505
- name: puma
506
- requirement: !ruby/object:Gem::Requirement
507
- requirements:
508
- - - ">="
509
- - !ruby/object:Gem::Version
510
- version: '0'
511
- type: :development
512
- prerelease: false
513
- version_requirements: !ruby/object:Gem::Requirement
514
- requirements:
515
- - - ">="
516
- - !ruby/object:Gem::Version
517
- version: '0'
518
- - !ruby/object:Gem::Dependency
519
- name: rails-i18n
520
- requirement: !ruby/object:Gem::Requirement
521
- requirements:
522
- - - ">="
523
- - !ruby/object:Gem::Version
524
- version: '0'
525
- type: :development
526
- prerelease: false
527
- version_requirements: !ruby/object:Gem::Requirement
528
- requirements:
529
- - - ">="
530
- - !ruby/object:Gem::Version
531
- version: '0'
532
- - !ruby/object:Gem::Dependency
533
- name: rails_email_preview
534
- requirement: !ruby/object:Gem::Requirement
535
- requirements:
536
- - - ">="
537
- - !ruby/object:Gem::Version
538
- version: 2.2.1
539
- type: :development
540
- prerelease: false
541
- version_requirements: !ruby/object:Gem::Requirement
542
- requirements:
543
- - - ">="
544
- - !ruby/object:Gem::Version
545
- version: 2.2.1
546
- - !ruby/object:Gem::Dependency
547
- name: sqlite3
548
- requirement: !ruby/object:Gem::Requirement
549
- requirements:
550
- - - ">="
551
- - !ruby/object:Gem::Version
552
- version: '0'
553
- type: :development
554
- prerelease: false
555
- version_requirements: !ruby/object:Gem::Requirement
556
- requirements:
557
- - - ">="
558
- - !ruby/object:Gem::Version
559
- version: '0'
560
- - !ruby/object:Gem::Dependency
561
- name: twemoji
562
- requirement: !ruby/object:Gem::Requirement
563
- requirements:
564
- - - ">="
565
- - !ruby/object:Gem::Version
566
- version: '0'
567
- type: :development
568
- prerelease: false
569
- version_requirements: !ruby/object:Gem::Requirement
570
- requirements:
571
- - - ">="
572
- - !ruby/object:Gem::Version
573
- version: '0'
574
- - !ruby/object:Gem::Dependency
575
- name: web-console
576
- requirement: !ruby/object:Gem::Requirement
577
- requirements:
578
- - - ">="
579
- - !ruby/object:Gem::Version
580
- version: '0'
581
- type: :development
582
- prerelease: false
583
- version_requirements: !ruby/object:Gem::Requirement
584
- requirements:
585
- - - ">="
586
- - !ruby/object:Gem::Version
587
- version: '0'
588
- - !ruby/object:Gem::Dependency
589
- name: thredded-markdown_coderay
590
- requirement: !ruby/object:Gem::Requirement
591
- requirements:
592
- - - ">="
593
- - !ruby/object:Gem::Version
594
- version: '0'
595
- type: :development
596
- prerelease: false
597
- version_requirements: !ruby/object:Gem::Requirement
598
- requirements:
599
- - - ">="
600
- - !ruby/object:Gem::Version
601
- version: '0'
602
- - !ruby/object:Gem::Dependency
603
- name: thredded-markdown_katex
604
- requirement: !ruby/object:Gem::Requirement
605
- requirements:
606
- - - ">="
607
- - !ruby/object:Gem::Version
608
- version: '0'
609
- type: :development
610
- prerelease: false
611
- version_requirements: !ruby/object:Gem::Requirement
612
- requirements:
613
- - - ">="
614
- - !ruby/object:Gem::Version
615
- version: '0'
616
- - !ruby/object:Gem::Dependency
617
- name: turbolinks
618
- requirement: !ruby/object:Gem::Requirement
619
- requirements:
620
- - - ">="
621
- - !ruby/object:Gem::Version
622
- version: '0'
623
- type: :development
624
- prerelease: false
625
- version_requirements: !ruby/object:Gem::Requirement
626
- requirements:
627
- - - ">="
628
- - !ruby/object:Gem::Version
629
- version: '0'
630
272
  description: |-
631
273
  The best Rails 6.0+ forums engine ever. Its goal is to be as simple and feature rich as possible.
632
274
  Thredded works with SQLite, MySQL (v5.6.4+), and PostgreSQL. See the demo at https://thredded.org/.
@@ -795,6 +437,7 @@ files:
795
437
  - app/models/concerns/thredded/search_parser.rb
796
438
  - app/models/concerns/thredded/topic_common.rb
797
439
  - app/models/concerns/thredded/topics_search.rb
440
+ - app/models/concerns/thredded/union_scope.rb
798
441
  - app/models/concerns/thredded/user_topic_read_state_common.rb
799
442
  - app/models/thredded/category.rb
800
443
  - app/models/thredded/messageboard.rb
@@ -989,6 +632,7 @@ files:
989
632
  - config/locales/pl.yml
990
633
  - config/locales/pt-BR.yml
991
634
  - config/locales/ru.yml
635
+ - config/locales/uk.yml
992
636
  - config/locales/zh-CN.yml
993
637
  - config/routes.rb
994
638
  - db/migrate/20160329231848_create_thredded.rb
@@ -1048,7 +692,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
1048
692
  requirements:
1049
693
  - - ">="
1050
694
  - !ruby/object:Gem::Version
1051
- version: '2.1'
695
+ version: '3.1'
1052
696
  - - "<"
1053
697
  - !ruby/object:Gem::Version
1054
698
  version: '4.0'
@@ -1058,7 +702,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1058
702
  - !ruby/object:Gem::Version
1059
703
  version: '0'
1060
704
  requirements: []
1061
- rubygems_version: 3.2.32
705
+ rubygems_version: 3.4.19
1062
706
  signing_key:
1063
707
  specification_version: 4
1064
708
  summary: The best Rails forums engine ever.