thredded 1.0.1 → 1.1.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.
- checksums.yaml +4 -4
- data/README.md +12 -4
- data/app/helpers/thredded/urls_helper.rb +2 -0
- data/app/view_models/thredded/topics_page_view.rb +1 -0
- data/bin/run_specs_repeatedly +9 -0
- data/lib/thredded/collection_to_strings_with_cache_renderer.rb +29 -39
- data/lib/thredded/compat.rb +0 -6
- data/lib/thredded/content_formatter.rb +11 -18
- data/lib/thredded/db_tools.rb +1 -5
- data/lib/thredded/version.rb +1 -1
- metadata +8 -14
- data/lib/thredded/rails_lt_5_2_arel_case_node.rb +0 -119
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19cde941264a9f9b9427694c27cc5f2a668fd18debbfe459d3fc58087e5636bf
|
4
|
+
data.tar.gz: 0d4eec1e395f2265783f9283ad958ec2a7f486a017bb961af87b26c2fd711c20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7d6aa4fd6d1eaecda06e839b757d6fa2bbf7fd24ae6ef4ba3c238a5d8880baeff1be6b9ee2aae21b34c8f844d0aa5eb5c41a1f70e7841cbe867a900e29b980a
|
7
|
+
data.tar.gz: 04af99833299683e35b13468e957bd75880a1627db1ff6c9ab53e1678f99842b273cc50ed529c9cddeedb7600c0d54b404550fd8858a7901346d6c72df77bdb2
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Thredded [](https://codeclimate.com/github/thredded/thredded) [](https://travis-ci.org/thredded/thredded/) [](https://codeclimate.com/github/thredded/thredded/coverage) [](http://inch-ci.org/github/thredded/thredded) [](https://gitter.im/thredded/thredded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
2
2
|
|
3
|
-
_Thredded_ is a Rails
|
3
|
+
_Thredded_ is a Rails 6.0+ forum/messageboard engine. Its goal is to be as simple and feature rich as possible.
|
4
4
|
|
5
5
|
Some of the features currently in Thredded:
|
6
6
|
|
@@ -38,6 +38,7 @@ Table of Contents
|
|
38
38
|
* [Adding Thredded to an existing Rails app](#adding-thredded-to-an-existing-rails-app)
|
39
39
|
* [Upgrading an existing install](#upgrading-an-existing-install)
|
40
40
|
* [Migrating from Forem](#migrating-from-forem)
|
41
|
+
* [Rails compatibility](#rails-compatibility)
|
41
42
|
* [Views and other assets](#views-and-other-assets)
|
42
43
|
* [Standalone layout](#standalone-layout)
|
43
44
|
* [Application layout](#application-layout)
|
@@ -96,7 +97,7 @@ Then, see the rest of this Readme for more information about using and customizi
|
|
96
97
|
Add the gem to your Gemfile:
|
97
98
|
|
98
99
|
```ruby
|
99
|
-
gem 'thredded', '~> 1.
|
100
|
+
gem 'thredded', '~> 1.1'
|
100
101
|
```
|
101
102
|
|
102
103
|
Add the Thredded [initializer] to your parent app by running the install generator.
|
@@ -155,6 +156,15 @@ to Thredded.
|
|
155
156
|
[forem-to-thredded]: https://github.com/thredded/thredded/wiki/Migrate-from-Forem
|
156
157
|
[Forem]: https://github.com/rubysherpas/forem
|
157
158
|
|
159
|
+
## Rails compatibility
|
160
|
+
|
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 |
|
166
|
+
|
167
|
+
|
158
168
|
## Views and other assets
|
159
169
|
|
160
170
|
### Standalone layout
|
@@ -596,8 +606,6 @@ Rails.application.config.to_prepare do
|
|
596
606
|
Thredded::ApplicationController.module_eval do
|
597
607
|
# Require authentication to access the forums:
|
598
608
|
before_action :thredded_require_login!
|
599
|
-
# NB: in rails 4.2 you will need to change this to:
|
600
|
-
# before_action { thredded_require_login! }
|
601
609
|
|
602
610
|
# You may also want to render a login form after the
|
603
611
|
# "Please sign in first" message:
|
@@ -47,7 +47,8 @@ module Thredded
|
|
47
47
|
|
48
48
|
ordered_keys.map do |cache_key|
|
49
49
|
[keyed_collection[cache_key], cached_partials[cache_key] || rendered_partials.next.tap do |rendered|
|
50
|
-
|
50
|
+
cache.write(cache_key, rendered, expires_in: expires_in)
|
51
|
+
cached_partials[cache_key] = rendered
|
51
52
|
end]
|
52
53
|
end
|
53
54
|
end
|
@@ -82,18 +83,29 @@ module Thredded
|
|
82
83
|
else
|
83
84
|
collection.each_slice(collection.size / num_threads).map do |slice|
|
84
85
|
Thread.start do
|
85
|
-
# `ActionView::PartialRenderer` mutates the contents of `opts[:locals]`, `opts[:locals][:as]` in particular:
|
86
|
-
# https://github.com/rails/rails/blob/v6.0.2.1/actionview/lib/action_view/renderer/partial_renderer.rb#L379
|
87
|
-
# https://github.com/rails/rails/blob/v6.0.2.1/actionview/lib/action_view/renderer/partial_renderer.rb#L348-L356
|
88
|
-
opts[:locals] = opts[:locals].dup if opts[:locals]
|
89
86
|
ActiveRecord::Base.connection_pool.with_connection do
|
90
|
-
render_partials_serial(view_context.dup, slice, opts)
|
87
|
+
render_partials_serial(view_context.dup, slice, dup_opts(opts))
|
91
88
|
end
|
92
89
|
end
|
93
90
|
end.flat_map(&:value)
|
94
91
|
end
|
95
92
|
end
|
96
93
|
|
94
|
+
# `ActionView::PartialRenderer` mutates the contents of `opts[:locals]`, `opts[:locals][:as]` in particular:
|
95
|
+
# https://github.com/rails/rails/blob/v6.0.2.1/actionview/lib/action_view/renderer/partial_renderer.rb#L379
|
96
|
+
# https://github.com/rails/rails/blob/v6.0.2.1/actionview/lib/action_view/renderer/partial_renderer.rb#L348-L356
|
97
|
+
def dup_opts(opts)
|
98
|
+
if opts[:locals]
|
99
|
+
opts = opts.dup
|
100
|
+
# sometimes have a thread safe :users_provider, preserve that for performance reasons
|
101
|
+
# hence not doing a deep_dup
|
102
|
+
opts[:locals] = opts[:locals].dup
|
103
|
+
opts
|
104
|
+
else
|
105
|
+
opts.dup
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
97
109
|
if Thredded::Compat.rails_gte_61?
|
98
110
|
# @param [Array<Object>] collection
|
99
111
|
# @param [Hash] opts
|
@@ -121,42 +133,20 @@ module Thredded
|
|
121
133
|
view.combined_fragment_cache_key(key)
|
122
134
|
end
|
123
135
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
view.cache_fragment_name(key, virtual_path: virtual_path, digest_path: digest_path)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def digest_path_from_template(view, template)
|
134
|
-
view.digest_path_from_template(template)
|
135
|
-
end
|
136
|
-
|
137
|
-
def render_partial(partial_renderer, view_context, opts)
|
138
|
-
partial_renderer.render(view_context, opts, nil).body
|
139
|
-
end
|
140
|
-
else
|
141
|
-
def cache_fragment_name(_view, key, virtual_path:, digest_path:)
|
142
|
-
if digest_path
|
143
|
-
["#{virtual_path}:#{digest_path}", key]
|
144
|
-
else
|
145
|
-
[virtual_path, key]
|
146
|
-
end
|
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)
|
147
141
|
end
|
142
|
+
end
|
148
143
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
finder: @lookup_context,
|
153
|
-
dependencies: view.view_cache_dependencies
|
154
|
-
).presence
|
155
|
-
end
|
144
|
+
def digest_path_from_template(view, template)
|
145
|
+
view.digest_path_from_template(template)
|
146
|
+
end
|
156
147
|
|
157
|
-
|
158
|
-
|
159
|
-
end
|
148
|
+
def render_partial(partial_renderer, view_context, opts)
|
149
|
+
partial_renderer.render(view_context, opts, nil).body
|
160
150
|
end
|
161
151
|
end
|
162
152
|
end
|
data/lib/thredded/compat.rb
CHANGED
@@ -3,12 +3,6 @@
|
|
3
3
|
module Thredded
|
4
4
|
module Compat
|
5
5
|
class << self
|
6
|
-
# @api private
|
7
|
-
def rails_gte_60?
|
8
|
-
@rails_gte_60 = (Rails.gem_version >= Gem::Version.new('6.0.0')) if @rails_gte_60.nil?
|
9
|
-
@rails_gte_60
|
10
|
-
end
|
11
|
-
|
12
6
|
# @api private
|
13
7
|
def rails_gte_61?
|
14
8
|
@rails_gte_61 = (Rails.gem_version >= Gem::Version.new('6.1.0')) if @rails_gte_61.nil?
|
@@ -8,7 +8,15 @@ module Thredded
|
|
8
8
|
attr_accessor :allowlist
|
9
9
|
|
10
10
|
# TODO: v2.0: drop alias and just use allowlist
|
11
|
-
|
11
|
+
# @deprecated use allowlist
|
12
|
+
def whitelist
|
13
|
+
ActiveSupport::Deprecation.warn(<<~MESSAGE.squish)
|
14
|
+
ContentFormatter.whitelist is deprecated and will be removed in Thredded 2.0.
|
15
|
+
Use ContentFormatter.allowlist instead
|
16
|
+
MESSAGE
|
17
|
+
|
18
|
+
allowlist
|
19
|
+
end
|
12
20
|
|
13
21
|
# Filters that run before processing the markup.
|
14
22
|
# input: markup, output: markup.
|
@@ -30,17 +38,8 @@ module Thredded
|
|
30
38
|
# input: sanitized html, output: html
|
31
39
|
attr_accessor :after_sanitization_filters
|
32
40
|
|
33
|
-
# TODO: v1.1: only allow html-pipeline >= 2.14.1 and drop this
|
34
|
-
def sanitization_filter_uses_allowlist?
|
35
|
-
defined?(HTML::Pipeline::SanitizationFilter::ALLOWLIST)
|
36
|
-
end
|
37
|
-
|
38
41
|
def sanitization_filter_allowlist_config
|
39
|
-
|
40
|
-
HTML::Pipeline::SanitizationFilter::ALLOWLIST
|
41
|
-
else
|
42
|
-
HTML::Pipeline::SanitizationFilter::WHITELIST
|
43
|
-
end
|
42
|
+
HTML::Pipeline::SanitizationFilter::ALLOWLIST
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -150,15 +149,9 @@ module Thredded
|
|
150
149
|
|
151
150
|
# @return [Hash] options for HTML::Pipeline.new
|
152
151
|
def content_pipeline_options
|
153
|
-
option = if self.class.sanitization_filter_uses_allowlist?
|
154
|
-
:allowlist
|
155
|
-
else
|
156
|
-
# TODO: v1.1: only allow html-pipeline >= 2.14.1 and drop this
|
157
|
-
:whitelist
|
158
|
-
end
|
159
152
|
{
|
160
153
|
asset_root: Rails.application.config.action_controller.asset_host || '',
|
161
|
-
|
154
|
+
allowlist: ContentFormatter.allowlist
|
162
155
|
}
|
163
156
|
end
|
164
157
|
end
|
data/lib/thredded/db_tools.rb
CHANGED
@@ -10,11 +10,7 @@ module Thredded
|
|
10
10
|
verbose_was = ActiveRecord::Migration.verbose
|
11
11
|
ActiveRecord::Migration.verbose = !quiet
|
12
12
|
migrate =
|
13
|
-
|
14
|
-
-> { ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration).migrate(nil, &filter) }
|
15
|
-
else # Rails 5.2
|
16
|
-
-> { ActiveRecord::MigrationContext.new(paths).migrate(nil, &filter) }
|
17
|
-
end
|
13
|
+
-> { ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration).migrate(nil, &filter) }
|
18
14
|
if quiet
|
19
15
|
silence_active_record(&migrate)
|
20
16
|
else
|
data/lib/thredded/version.rb
CHANGED
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.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Oliveira
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-02-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: active_record_union
|
@@ -127,20 +127,14 @@ dependencies:
|
|
127
127
|
name: rails
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
129
129
|
requirements:
|
130
|
-
- - "
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: 5.2.0
|
133
|
-
- - "!="
|
130
|
+
- - ">"
|
134
131
|
- !ruby/object:Gem::Version
|
135
132
|
version: 6.0.0.rc2
|
136
133
|
type: :runtime
|
137
134
|
prerelease: false
|
138
135
|
version_requirements: !ruby/object:Gem::Requirement
|
139
136
|
requirements:
|
140
|
-
- - "
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
version: 5.2.0
|
143
|
-
- - "!="
|
137
|
+
- - ">"
|
144
138
|
- !ruby/object:Gem::Version
|
145
139
|
version: 6.0.0.rc2
|
146
140
|
- !ruby/object:Gem::Dependency
|
@@ -163,14 +157,14 @@ dependencies:
|
|
163
157
|
requirements:
|
164
158
|
- - ">="
|
165
159
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
160
|
+
version: 2.14.1
|
167
161
|
type: :runtime
|
168
162
|
prerelease: false
|
169
163
|
version_requirements: !ruby/object:Gem::Requirement
|
170
164
|
requirements:
|
171
165
|
- - ">="
|
172
166
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
167
|
+
version: 2.14.1
|
174
168
|
- !ruby/object:Gem::Dependency
|
175
169
|
name: kramdown
|
176
170
|
requirement: !ruby/object:Gem::Requirement
|
@@ -634,7 +628,7 @@ dependencies:
|
|
634
628
|
- !ruby/object:Gem::Version
|
635
629
|
version: '0'
|
636
630
|
description: |-
|
637
|
-
The best Rails
|
631
|
+
The best Rails 6.0+ forums engine ever. Its goal is to be as simple and feature rich as possible.
|
638
632
|
Thredded works with SQLite, MySQL (v5.6.4+), and PostgreSQL. See the demo at https://thredded.org/.
|
639
633
|
email:
|
640
634
|
- joel@thredded.com
|
@@ -985,6 +979,7 @@ files:
|
|
985
979
|
- bin/create_migration_fixture
|
986
980
|
- bin/rails
|
987
981
|
- bin/rubocop
|
982
|
+
- bin/run_specs_repeatedly
|
988
983
|
- config/i18n-tasks.yml
|
989
984
|
- config/locales/de.yml
|
990
985
|
- config/locales/en.yml
|
@@ -1034,7 +1029,6 @@ files:
|
|
1034
1029
|
- lib/thredded/html_pipeline/spoiler_tag_filter.rb
|
1035
1030
|
- lib/thredded/html_pipeline/utils.rb
|
1036
1031
|
- lib/thredded/html_pipeline/wrap_iframes_filter.rb
|
1037
|
-
- lib/thredded/rails_lt_5_2_arel_case_node.rb
|
1038
1032
|
- lib/thredded/users_provider.rb
|
1039
1033
|
- lib/thredded/version.rb
|
1040
1034
|
- lib/thredded/view_hooks/config.rb
|
@@ -1,119 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Arel
|
4
|
-
module Nodes
|
5
|
-
class Case < Arel::Nodes::Node
|
6
|
-
include Arel::OrderPredications
|
7
|
-
include Arel::Predications
|
8
|
-
include Arel::AliasPredication
|
9
|
-
|
10
|
-
attr_accessor :case, :conditions, :default
|
11
|
-
|
12
|
-
def initialize(expression = nil, default = nil)
|
13
|
-
@case = expression
|
14
|
-
@conditions = []
|
15
|
-
@default = default
|
16
|
-
end
|
17
|
-
|
18
|
-
def when(condition, expression = nil)
|
19
|
-
@conditions << When.new(Nodes.build_quoted(condition), expression)
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def then(expression)
|
24
|
-
@conditions.last.right = Nodes.build_quoted(expression)
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
def else(expression)
|
29
|
-
@default = Else.new Nodes.build_quoted(expression)
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def initialize_copy(other)
|
34
|
-
super
|
35
|
-
@case = @case.clone if @case
|
36
|
-
@conditions = @conditions.map(&:clone)
|
37
|
-
@default = @default.clone if @default
|
38
|
-
end
|
39
|
-
|
40
|
-
def hash
|
41
|
-
[@case, @conditions, @default].hash
|
42
|
-
end
|
43
|
-
|
44
|
-
def eql?(other)
|
45
|
-
self.class == other.class &&
|
46
|
-
self.case == other.case &&
|
47
|
-
conditions == other.conditions &&
|
48
|
-
default == other.default
|
49
|
-
end
|
50
|
-
|
51
|
-
alias == eql?
|
52
|
-
end
|
53
|
-
|
54
|
-
class When < Binary
|
55
|
-
end
|
56
|
-
|
57
|
-
class Else < Unary
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
module Arel
|
63
|
-
module Visitors
|
64
|
-
class DepthFirst < Arel::Visitors::Visitor
|
65
|
-
alias visit_Arel_Nodes_Else unary
|
66
|
-
|
67
|
-
def visit_Arel_Nodes_Case(o) # rubocop:disable Naming/MethodName
|
68
|
-
visit o.case
|
69
|
-
visit o.conditions
|
70
|
-
visit o.default
|
71
|
-
end
|
72
|
-
|
73
|
-
alias visit_Arel_Nodes_When binary
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
module Arel
|
79
|
-
module Predications
|
80
|
-
def when(right)
|
81
|
-
Nodes::Case.new(self).when quoted_node(right)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
module Arel
|
87
|
-
module Visitors
|
88
|
-
class ToSql < Arel::Visitors::Reduce
|
89
|
-
def visit_Arel_Nodes_Case(o, collector) # rubocop:disable Naming/MethodName
|
90
|
-
collector << 'CASE '
|
91
|
-
if o.case
|
92
|
-
visit o.case, collector
|
93
|
-
collector << ' '
|
94
|
-
end
|
95
|
-
o.conditions.each do |condition|
|
96
|
-
visit condition, collector
|
97
|
-
collector << ' '
|
98
|
-
end
|
99
|
-
if o.default
|
100
|
-
visit o.default, collector
|
101
|
-
collector << ' '
|
102
|
-
end
|
103
|
-
collector << 'END'
|
104
|
-
end
|
105
|
-
|
106
|
-
def visit_Arel_Nodes_When(o, collector) # rubocop:disable Naming/MethodName
|
107
|
-
collector << 'WHEN '
|
108
|
-
visit o.left, collector
|
109
|
-
collector << ' THEN '
|
110
|
-
visit o.right, collector
|
111
|
-
end
|
112
|
-
|
113
|
-
def visit_Arel_Nodes_Else(o, collector) # rubocop:disable Naming/MethodName
|
114
|
-
collector << 'ELSE '
|
115
|
-
visit o.expr, collector
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|