bp3-activestorage 0.2.0 → 0.3.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/CHANGELOG.md +10 -0
- data/CLAUDE.md +9 -4
- data/Gemfile.lock +4 -2
- data/lib/bp3/activestorage/railtie.rb +88 -75
- data/lib/bp3/activestorage/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 109755bc5d9c018fc401b343738355f976b96d73e2f34997ac3c19cd3e730afa
|
|
4
|
+
data.tar.gz: 05cab73a42dcfc96d4d3a2b29f4122eb4315ed4c2f11aff389ed65a908af8fd5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0927cc2fd1066da4137fb6eb3d5057d168e33efb90c42e3021e49f7e48157772a4caf9c40186e4798aa50d4c6767ff07fb4dbeb6d80668e42c32b87884dbc240'
|
|
7
|
+
data.tar.gz: 05ee612b2d54d5c3e3d877200565d560862bee6c73b1e6965d7d197657dba593840a3f0dc1b2bbde37d97409871c90a7841bb91c56fb857761ca1ffcabb8c34b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-11-03
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- Require a signed-in user, site admin or root for direct uploads
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Reopen the Active Storage classes in `to_prepare`, so a development reload keeps what this gem adds
|
|
12
|
+
|
|
3
13
|
## [0.2.0] - 2026-10-30
|
|
4
14
|
|
|
5
15
|
### Security
|
data/CLAUDE.md
CHANGED
|
@@ -20,8 +20,10 @@ shell is not already on it; a missing `rspec` means the wrong Ruby, not a missin
|
|
|
20
20
|
|
|
21
21
|
## Architecture
|
|
22
22
|
|
|
23
|
-
`lib/bp3/activestorage/railtie.rb` reopens
|
|
24
|
-
|
|
23
|
+
`lib/bp3/activestorage/railtie.rb` reopens six classes in a `to_prepare` block. Active Storage's models and
|
|
24
|
+
controllers are reloaded with the application's code in development, and `to_prepare` runs again after
|
|
25
|
+
each reload, where `after_initialize` would not. Each class is referenced before it is reopened, so that
|
|
26
|
+
it is autoloaded rather than defined anew. The Railtie is only defined when `Rails.env` is.
|
|
25
27
|
|
|
26
28
|
**Models**: `ActiveStorage::Attachment`, `Blob` and `VariantRecord`
|
|
27
29
|
- include `Bp3::Core::Rqid`, `Sqnr` and `Ransackable` (Blob also `Displayable`), call
|
|
@@ -34,8 +36,11 @@ only defined when `Rails.env` is.
|
|
|
34
36
|
|
|
35
37
|
**Controllers**: `ActiveStorage::BaseController` and `ActiveStorage::Representations::ProxyController`
|
|
36
38
|
include `Bp3::Core::Actions`, `Settings`, `FeatureFlags` and `Cookies`, so file requests get the same site,
|
|
37
|
-
tenant and request tracking as the rest of the application. They do not authenticate
|
|
38
|
-
|
|
39
|
+
tenant and request tracking as the rest of the application. They do not authenticate: the signed URL is
|
|
40
|
+
the permission, and public pages and emails show files to people with no session.
|
|
41
|
+
`ActiveStorage::DirectUploadsController` does: it answers 401 unless `grsc.current_login` names someone. It
|
|
42
|
+
inherits `set_global_request_state` from `Bp3::Core::Actions` through `BaseController`, and its own check
|
|
43
|
+
runs after it, so it asks the request state rather than Devise.
|
|
39
44
|
|
|
40
45
|
## Testing
|
|
41
46
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
bp3-activestorage (0.
|
|
4
|
+
bp3-activestorage (0.3.0)
|
|
5
5
|
activestorage (~> 8.1)
|
|
6
6
|
bp3-core (>= 0.4.0)
|
|
7
7
|
paper_trail (>= 15.1)
|
|
@@ -60,9 +60,10 @@ GEM
|
|
|
60
60
|
actionview (~> 8.1)
|
|
61
61
|
activesupport (~> 8.1)
|
|
62
62
|
bp3-request_state (~> 0.1)
|
|
63
|
-
bp3-request_state (0.1.
|
|
63
|
+
bp3-request_state (0.1.4)
|
|
64
64
|
actionpack (~> 8.1)
|
|
65
65
|
activesupport (~> 8.1)
|
|
66
|
+
ostruct (>= 0.6)
|
|
66
67
|
request_store (>= 1.5.1)
|
|
67
68
|
builder (3.3.0)
|
|
68
69
|
byebug (13.0.0)
|
|
@@ -91,6 +92,7 @@ GEM
|
|
|
91
92
|
prism (~> 1.5)
|
|
92
93
|
nokogiri (1.19.4-x86_64-darwin)
|
|
93
94
|
racc (~> 1.4)
|
|
95
|
+
ostruct (0.6.3)
|
|
94
96
|
paper_trail (17.0.0)
|
|
95
97
|
activerecord (>= 7.1)
|
|
96
98
|
request_store (~> 1.4)
|
|
@@ -7,101 +7,114 @@ module Bp3
|
|
|
7
7
|
module Activestorage
|
|
8
8
|
if defined?(Rails.env)
|
|
9
9
|
class Railtie < Rails::Railtie
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
10
|
+
# to_prepare rather than after_initialize: Active Storage's models and controllers are reloaded
|
|
11
|
+
# with the application's code in development, and what is added to them here goes with them.
|
|
12
|
+
config.to_prepare do
|
|
13
|
+
::ActiveStorage::Attachment # preload
|
|
14
|
+
::ActiveStorage::Blob # preload
|
|
15
|
+
::ActiveStorage::VariantRecord # preload
|
|
16
|
+
::ActiveStorage::BaseController # preload
|
|
17
|
+
::ActiveStorage::Representations::ProxyController # preload
|
|
18
|
+
::ActiveStorage::DirectUploadsController # preload
|
|
19
|
+
module ::ActiveStorage
|
|
20
|
+
# CAUTION: do not include Tenantable, it breaks things (it may set site/tenant behind the scenes,
|
|
21
|
+
# and sets the default scope, and then later the blob can't be found
|
|
22
|
+
class Attachment
|
|
23
|
+
include Bp3::Core::Rqid
|
|
24
|
+
include Bp3::Core::Sqnr
|
|
25
|
+
include Bp3::Core::Ransackable
|
|
26
|
+
|
|
27
|
+
use_sqnr_for_ordering
|
|
28
|
+
has_paper_trail
|
|
29
|
+
|
|
30
|
+
belongs_to :sites_site, class_name: 'Sites::Site', optional: true
|
|
31
|
+
alias site sites_site
|
|
32
|
+
alias site= sites_site=
|
|
33
|
+
belongs_to :tenant, optional: true
|
|
34
|
+
|
|
35
|
+
def self.table_name_basis
|
|
36
|
+
table_name.gsub(/\Apublic\./, '').singularize
|
|
36
37
|
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Blob
|
|
41
|
+
include Bp3::Core::Rqid
|
|
42
|
+
include Bp3::Core::Sqnr
|
|
43
|
+
include Bp3::Core::Displayable
|
|
44
|
+
include Bp3::Core::Ransackable
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
include Bp3::Core::Sqnr
|
|
41
|
-
include Bp3::Core::Displayable
|
|
42
|
-
include Bp3::Core::Ransackable
|
|
46
|
+
# The key locates the file in storage, so it is not to be guessed at one character at a time
|
|
47
|
+
self.unexplorable_columns = %w[key]
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
use_sqnr_for_ordering
|
|
50
|
+
has_paper_trail
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
belongs_to :sites_site, class_name: 'Sites::Site', optional: true
|
|
53
|
+
alias site sites_site
|
|
54
|
+
alias site= sites_site=
|
|
55
|
+
belongs_to :tenant, optional: true
|
|
56
|
+
|
|
57
|
+
def self.table_name_basis
|
|
58
|
+
table_name.gsub(/\Apublic\./, '').singularize
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def version_filter_mask
|
|
64
|
+
'[FILTERED][AB]'
|
|
65
|
+
end
|
|
66
|
+
end
|
|
49
67
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
68
|
+
class VariantRecord
|
|
69
|
+
include Bp3::Core::Rqid
|
|
70
|
+
include Bp3::Core::Sqnr
|
|
71
|
+
include Bp3::Core::Ransackable
|
|
54
72
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
end
|
|
73
|
+
use_sqnr_for_ordering
|
|
74
|
+
has_paper_trail
|
|
58
75
|
|
|
59
|
-
|
|
76
|
+
belongs_to :sites_site, class_name: 'Sites::Site', optional: true
|
|
77
|
+
alias site sites_site
|
|
78
|
+
alias site= sites_site=
|
|
79
|
+
belongs_to :tenant, optional: true
|
|
60
80
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
end
|
|
81
|
+
def self.table_name_basis
|
|
82
|
+
table_name.gsub(/\Apublic\./, '').singularize
|
|
64
83
|
end
|
|
84
|
+
end
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
class BaseController
|
|
87
|
+
include Bp3::Core::Actions
|
|
88
|
+
include Bp3::Core::Settings
|
|
89
|
+
include Bp3::Core::FeatureFlags
|
|
90
|
+
include Bp3::Core::Cookies
|
|
91
|
+
|
|
92
|
+
# No login is asked of anyone fetching a file. The URL is signed, and holding it is the
|
|
93
|
+
# permission: a visitor reading a page and an email client showing a logo have no session.
|
|
94
|
+
end
|
|
70
95
|
|
|
71
|
-
|
|
72
|
-
|
|
96
|
+
# A direct upload creates a blob and hands back a signed URL to store a file at, and Rails asks
|
|
97
|
+
# nothing of the caller. It is for signed-in work, such as a rich text editor, so it asks for a
|
|
98
|
+
# login. BaseController's Bp3::Core::Actions#set_global_request_state runs before this, so the
|
|
99
|
+
# request state knows who is signed in.
|
|
100
|
+
class DirectUploadsController
|
|
101
|
+
before_action :require_login_for_direct_upload
|
|
73
102
|
|
|
74
|
-
|
|
75
|
-
alias site sites_site
|
|
76
|
-
alias site= sites_site=
|
|
77
|
-
belongs_to :tenant, optional: true
|
|
103
|
+
private
|
|
78
104
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
end
|
|
105
|
+
def require_login_for_direct_upload
|
|
106
|
+
head :unauthorized unless grsc.current_login
|
|
82
107
|
end
|
|
108
|
+
end
|
|
83
109
|
|
|
84
|
-
|
|
110
|
+
module Representations
|
|
111
|
+
class ProxyController
|
|
85
112
|
include Bp3::Core::Actions
|
|
86
113
|
include Bp3::Core::Settings
|
|
87
114
|
include Bp3::Core::FeatureFlags
|
|
88
115
|
include Bp3::Core::Cookies
|
|
89
116
|
|
|
90
|
-
#
|
|
91
|
-
# before_action :authenticate_root!
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
module Representations
|
|
95
|
-
class ProxyController
|
|
96
|
-
include Bp3::Core::Actions
|
|
97
|
-
include Bp3::Core::Settings
|
|
98
|
-
include Bp3::Core::FeatureFlags
|
|
99
|
-
include Bp3::Core::Cookies
|
|
100
|
-
|
|
101
|
-
# using authenticate_root! breaks things
|
|
102
|
-
# TODO: is this needed?
|
|
103
|
-
# before_action :authenticate_root!
|
|
104
|
-
end
|
|
117
|
+
# Like ActiveStorage::BaseController, asks no login: the signed URL is the permission.
|
|
105
118
|
end
|
|
106
119
|
end
|
|
107
120
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bp3-activestorage
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wim den Braven
|
|
@@ -180,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
180
180
|
- !ruby/object:Gem::Version
|
|
181
181
|
version: '0'
|
|
182
182
|
requirements: []
|
|
183
|
-
rubygems_version: 4.0.
|
|
183
|
+
rubygems_version: 4.0.23
|
|
184
184
|
specification_version: 4
|
|
185
185
|
summary: bp3-activestorage adapts activestorage for BP3 (persuavis/black_phoebe_3).
|
|
186
186
|
test_files: []
|