helios-press 0.2 → 0.4
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 +27 -4
- data/app/controllers/helios/press/api/posts_controller.rb +19 -13
- data/app/models/helios/press/block_image.rb +5 -1
- data/app/services/helios/press/image_ingestor.rb +167 -0
- data/db/migrate/20250510000001_create_helios_press_posts.rb +13 -1
- data/db/migrate/20250510000002_create_helios_press_blocks.rb +14 -2
- data/db/migrate/20250510000003_create_helios_press_block_images.rb +14 -2
- data/db/migrate/20250526000001_add_image_ingestion_to_helios_press.rb +6 -0
- data/lib/helios/press/version.rb +1 -1
- metadata +22 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3ea59768263242ec8f88e1bd68e8d33f67f4b5a313d32626ac735632be159672
|
|
4
|
+
data.tar.gz: f2aa7c604191d1e340f18c1c9cf980d6f988407deff6127953a023572bcd1ef6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa4299b094dca0fc56ef35d1c930146cabbf6020bc4561f7482c140a1d9fac88a995f56a18a7aa53da51331f03e1b75e9d4d88f3c26c66b52968594673567752
|
|
7
|
+
data.tar.gz: 6e804a7772de4fe2f6b29ed41b1f111bede76ef00b86e39e3215bf07f311ac30344e28cafde50df2e11e5878dc843cd585272536bfc4bd9bb43634a1168c6352
|
data/README.md
CHANGED
|
@@ -89,9 +89,12 @@ mount Helios::Press::Admin::Engine, at: "/admin/press"
|
|
|
89
89
|
|
|
90
90
|
## JavaScript Setup
|
|
91
91
|
|
|
92
|
-
Register the Stimulus controllers in your host app:
|
|
92
|
+
Register the Stimulus controllers in your host app. You **must** also import `trix` and `@rails/actiontext` — without these imports, the rich text editor will not render in text blocks:
|
|
93
93
|
|
|
94
94
|
```javascript
|
|
95
|
+
import 'trix'
|
|
96
|
+
import '@rails/actiontext'
|
|
97
|
+
|
|
95
98
|
import {
|
|
96
99
|
HeliosPressBlocksController,
|
|
97
100
|
HeliosPressTextBlockController,
|
|
@@ -107,7 +110,7 @@ application.register("helios-press-image-block", HeliosPressImageBlockController
|
|
|
107
110
|
- `sortablejs`
|
|
108
111
|
- `@hotwired/stimulus`
|
|
109
112
|
- `@rails/activestorage`
|
|
110
|
-
- `trix` and `@rails/actiontext`
|
|
113
|
+
- `trix` and `@rails/actiontext` — **required** for text block editing
|
|
111
114
|
|
|
112
115
|
### Vite
|
|
113
116
|
|
|
@@ -157,11 +160,31 @@ POST to your mounted API path with `X-API-Key` header:
|
|
|
157
160
|
"slug": "my-post-title",
|
|
158
161
|
"description": "Meta description",
|
|
159
162
|
"keywords": "keyword1, keyword2",
|
|
160
|
-
"body_html": "<p>Post content...</p>",
|
|
161
|
-
"published": true
|
|
163
|
+
"body_html": "<p>Post content with <img src=\"https://example.com/photo.jpg\"> tags...</p>",
|
|
164
|
+
"published": true,
|
|
165
|
+
"images": [
|
|
166
|
+
{
|
|
167
|
+
"reference_key": "hero1",
|
|
168
|
+
"url": "https://example.com/hero.jpg",
|
|
169
|
+
"alt": "Hero image",
|
|
170
|
+
"caption": "Photo credit: Example"
|
|
171
|
+
}
|
|
172
|
+
]
|
|
162
173
|
}
|
|
163
174
|
```
|
|
164
175
|
|
|
176
|
+
### Image Ingestion
|
|
177
|
+
|
|
178
|
+
When a post is ingested via the API, all images in `body_html` are automatically downloaded, stored via ActiveStorage (e.g., to S3), and the `<img>` src attributes are rewritten to local proxy URLs. This ensures no external image hotlinking in published posts.
|
|
179
|
+
|
|
180
|
+
Two modes are supported:
|
|
181
|
+
|
|
182
|
+
1. **Explicit references**: Use `src="helios://image/<reference_key>"` in your `body_html` and provide the actual download URL in the `images` array. The ingestor matches them by `reference_key`.
|
|
183
|
+
|
|
184
|
+
2. **Auto-import**: Any `src="https://..."` URL in `body_html` is automatically downloaded. Images are deduplicated by a SHA256 hash of the URL path (ignoring query strings/signatures), so re-ingesting the same image with different signed URLs won't create duplicates.
|
|
185
|
+
|
|
186
|
+
Images are stored as `BlockImage` records with ActiveStorage attachments and served via `rails_storage_proxy_path`. Failed downloads are logged and skipped (soft failure — the original src is preserved).
|
|
187
|
+
|
|
165
188
|
## License
|
|
166
189
|
|
|
167
190
|
Proprietary. All rights reserved.
|
|
@@ -2,7 +2,7 @@ module Helios
|
|
|
2
2
|
module Press
|
|
3
3
|
module Api
|
|
4
4
|
class PostsController < Helios::Press::Api::BaseController
|
|
5
|
-
# POST /api/
|
|
5
|
+
# POST /api/press/posts
|
|
6
6
|
# Upsert a post by external_id. Payload shape:
|
|
7
7
|
# {
|
|
8
8
|
# "external_id": "helios-blog-post-draft-4821",
|
|
@@ -10,9 +10,18 @@ module Helios
|
|
|
10
10
|
# "slug": "...",
|
|
11
11
|
# "keywords": "...",
|
|
12
12
|
# "description": "...",
|
|
13
|
-
# "body_html": "
|
|
14
|
-
# "published": true
|
|
13
|
+
# "body_html": "<p>Content with <img src=\"https://...\"> tags...</p>",
|
|
14
|
+
# "published": true,
|
|
15
|
+
# "images": [
|
|
16
|
+
# { "reference_key": "hero1", "url": "https://...", "alt": "...", "caption": "..." }
|
|
17
|
+
# ]
|
|
15
18
|
# }
|
|
19
|
+
#
|
|
20
|
+
# Images in body_html are automatically downloaded, stored via ActiveStorage,
|
|
21
|
+
# and their src attributes rewritten to local proxy URLs. Two modes:
|
|
22
|
+
# 1. Explicit: use src="helios://image/<reference_key>" in body_html and
|
|
23
|
+
# provide the download URL in the images array.
|
|
24
|
+
# 2. Auto: any src="https://..." in body_html is downloaded automatically.
|
|
16
25
|
def create
|
|
17
26
|
external_id = params[:external_id].to_s
|
|
18
27
|
return render json: { error: "external_id is required" }, status: :bad_request if external_id.blank?
|
|
@@ -27,19 +36,16 @@ module Helios
|
|
|
27
36
|
published: ActiveModel::Type::Boolean.new.cast(params[:published])
|
|
28
37
|
)
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
post.save!
|
|
40
|
+
|
|
31
41
|
if params[:body_html].present?
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
post.blocks.build(block_type: "text", position: 0, content: params[:body_html])
|
|
38
|
-
end
|
|
42
|
+
ingestor = ImageIngestor.new(post)
|
|
43
|
+
ingestor.call(
|
|
44
|
+
body_html: params[:body_html],
|
|
45
|
+
images_payload: params[:images] || []
|
|
46
|
+
)
|
|
39
47
|
end
|
|
40
48
|
|
|
41
|
-
post.save!
|
|
42
|
-
|
|
43
49
|
render json: {
|
|
44
50
|
ok: true,
|
|
45
51
|
id: post.id,
|
|
@@ -8,7 +8,11 @@ module Helios
|
|
|
8
8
|
has_one_attached :file
|
|
9
9
|
|
|
10
10
|
validates :position, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
|
11
|
-
validates :file, presence: true
|
|
11
|
+
validates :file, presence: true, unless: :reference_key?
|
|
12
|
+
|
|
13
|
+
def reference_key?
|
|
14
|
+
reference_key.present?
|
|
15
|
+
end
|
|
12
16
|
|
|
13
17
|
acts_as_list scope: :block
|
|
14
18
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "nokogiri"
|
|
5
|
+
require "uri"
|
|
6
|
+
require "digest"
|
|
7
|
+
|
|
8
|
+
module Helios
|
|
9
|
+
module Press
|
|
10
|
+
# Downloads remote images referenced in ingested post HTML, stores them via
|
|
11
|
+
# ActiveStorage, and rewrites the body HTML so <img> src attributes point at
|
|
12
|
+
# locally-hosted ActiveStorage proxy URLs.
|
|
13
|
+
#
|
|
14
|
+
# Supports two modes:
|
|
15
|
+
# 1. Explicit references: src="helios://image/<reference_key>" paired with
|
|
16
|
+
# an images_payload array containing download URLs.
|
|
17
|
+
# 2. Auto-import: any remaining src="https://..." URLs are downloaded,
|
|
18
|
+
# deduplicated by a SHA256 of the URL path.
|
|
19
|
+
class ImageIngestor
|
|
20
|
+
class FetchError < StandardError; end
|
|
21
|
+
|
|
22
|
+
MAX_BYTES = 15.megabytes
|
|
23
|
+
|
|
24
|
+
def initialize(post)
|
|
25
|
+
@post = post
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# images_payload: Array of Hashes
|
|
29
|
+
# [{ "reference_key" => "abc123", "url" => "https://...", "alt" => "...", "caption" => "..." }]
|
|
30
|
+
def call(body_html:, images_payload: [])
|
|
31
|
+
ensure_text_block!
|
|
32
|
+
upsert_inline_images(images_payload)
|
|
33
|
+
rewritten = rewrite_body_html(body_html)
|
|
34
|
+
text_block.content = rewritten
|
|
35
|
+
text_block.save!
|
|
36
|
+
rewritten
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
attr_reader :post
|
|
42
|
+
|
|
43
|
+
def text_block
|
|
44
|
+
@text_block ||= post.blocks.find_by(block_type: "text") ||
|
|
45
|
+
post.blocks.build(block_type: "text", position: 0)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def ensure_text_block!
|
|
49
|
+
text_block # trigger lazy init
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def image_block
|
|
53
|
+
@image_block ||= post.blocks.find_by(block_type: "image_container") ||
|
|
54
|
+
post.blocks.create!(block_type: "image_container", position: 1)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def upsert_inline_images(payload)
|
|
58
|
+
return if payload.blank?
|
|
59
|
+
|
|
60
|
+
payload.each do |entry|
|
|
61
|
+
key = entry["reference_key"].presence
|
|
62
|
+
next unless key
|
|
63
|
+
|
|
64
|
+
bi = image_block.block_images.find_or_initialize_by(reference_key: key)
|
|
65
|
+
bi.caption = entry["caption"].to_s if entry["caption"].present?
|
|
66
|
+
bi.position ||= (image_block.block_images.maximum(:position) || 0) + 1
|
|
67
|
+
|
|
68
|
+
if bi.file.attached?
|
|
69
|
+
bi.save! if bi.changed?
|
|
70
|
+
next
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
blob = fetch_as_blob(entry["url"])
|
|
74
|
+
unless blob
|
|
75
|
+
Rails.logger.warn("Helios::Press::ImageIngestor: skipping #{key} — blob fetch failed")
|
|
76
|
+
next
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
bi.file.attach(blob)
|
|
80
|
+
bi.save!
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def rewrite_body_html(html)
|
|
85
|
+
return html if html.blank?
|
|
86
|
+
|
|
87
|
+
doc = Nokogiri::HTML.fragment(html)
|
|
88
|
+
doc.css("img").each do |img|
|
|
89
|
+
src = img["src"].to_s
|
|
90
|
+
|
|
91
|
+
if src.start_with?("helios://image/")
|
|
92
|
+
key = src.delete_prefix("helios://image/")
|
|
93
|
+
bi = image_block.block_images.find_by(reference_key: key)
|
|
94
|
+
next unless bi&.file&.attached?
|
|
95
|
+
|
|
96
|
+
img["src"] = proxy_path(bi.file)
|
|
97
|
+
img["alt"] = bi.caption if bi.caption.present? && img["alt"].blank?
|
|
98
|
+
elsif src.match?(%r{\Ahttps?://}i)
|
|
99
|
+
bi = import_remote_image(src, alt: img["alt"].to_s)
|
|
100
|
+
next unless bi&.file&.attached?
|
|
101
|
+
|
|
102
|
+
img["src"] = proxy_path(bi.file)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
doc.to_html
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def import_remote_image(url, alt: "")
|
|
110
|
+
uri = URI.parse(url)
|
|
111
|
+
key = "auto_#{Digest::SHA256.hexdigest(uri.path.to_s)[0, 16]}"
|
|
112
|
+
|
|
113
|
+
bi = image_block.block_images.find_or_initialize_by(reference_key: key)
|
|
114
|
+
bi.caption = alt if alt.present? && bi.caption.blank?
|
|
115
|
+
bi.position ||= (image_block.block_images.maximum(:position) || 0) + 1
|
|
116
|
+
|
|
117
|
+
if bi.file.attached?
|
|
118
|
+
bi.save! if bi.changed?
|
|
119
|
+
return bi
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
blob = fetch_as_blob(url)
|
|
123
|
+
unless blob
|
|
124
|
+
Rails.logger.warn("Helios::Press::ImageIngestor: skipping remote image #{url} — blob fetch failed")
|
|
125
|
+
return nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
bi.file.attach(blob)
|
|
129
|
+
bi.save!
|
|
130
|
+
bi
|
|
131
|
+
rescue StandardError => e
|
|
132
|
+
Rails.logger.error("Helios::Press::ImageIngestor: failed to import #{url} — #{e.class}: #{e.message}")
|
|
133
|
+
nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def proxy_path(attachment)
|
|
137
|
+
Rails.application.routes.url_helpers.rails_storage_proxy_path(attachment, only_path: true)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def fetch_as_blob(url)
|
|
141
|
+
uri = URI.parse(url)
|
|
142
|
+
return nil unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
|
|
143
|
+
|
|
144
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
|
|
145
|
+
http.open_timeout = 10
|
|
146
|
+
http.read_timeout = 30
|
|
147
|
+
http.request(Net::HTTP::Get.new(uri))
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
raise FetchError, "HTTP #{response.code} fetching #{url}" unless response.is_a?(Net::HTTPSuccess)
|
|
151
|
+
raise FetchError, "Image too large: #{response.body.bytesize}" if response.body.bytesize > MAX_BYTES
|
|
152
|
+
|
|
153
|
+
filename = File.basename(uri.path.presence || "image")
|
|
154
|
+
filename = "image.jpg" if filename.blank? || filename == "/"
|
|
155
|
+
|
|
156
|
+
ActiveStorage::Blob.create_and_upload!(
|
|
157
|
+
io: StringIO.new(response.body),
|
|
158
|
+
filename: filename,
|
|
159
|
+
content_type: response["content-type"] || "application/octet-stream"
|
|
160
|
+
)
|
|
161
|
+
rescue StandardError => e
|
|
162
|
+
Rails.logger.error("Helios::Press::ImageIngestor: failed to fetch #{url} — #{e.class}: #{e.message}")
|
|
163
|
+
nil
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
class CreateHeliosPressPosts < ActiveRecord::Migration[8.0]
|
|
2
2
|
def change
|
|
3
|
-
|
|
3
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
|
4
|
+
|
|
5
|
+
create_table :helios_press_posts, id: primary_key_type do |t|
|
|
4
6
|
t.string :name, null: false
|
|
5
7
|
t.string :slug, null: false
|
|
6
8
|
t.text :description
|
|
@@ -15,4 +17,14 @@ class CreateHeliosPressPosts < ActiveRecord::Migration[8.0]
|
|
|
15
17
|
add_index :helios_press_posts, :external_id, unique: true
|
|
16
18
|
add_index :helios_press_posts, :published
|
|
17
19
|
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def primary_and_foreign_key_types
|
|
24
|
+
config = Rails.configuration.generators
|
|
25
|
+
setting = config.options[config.orm][:primary_key_type]
|
|
26
|
+
primary_key_type = setting || :primary_key
|
|
27
|
+
foreign_key_type = setting || :bigint
|
|
28
|
+
[primary_key_type, foreign_key_type]
|
|
29
|
+
end
|
|
18
30
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
class CreateHeliosPressBlocks < ActiveRecord::Migration[8.0]
|
|
2
2
|
def change
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
|
4
|
+
|
|
5
|
+
create_table :helios_press_blocks, id: primary_key_type do |t|
|
|
6
|
+
t.references :post, null: false, foreign_key: { to_table: :helios_press_posts }, type: foreign_key_type
|
|
5
7
|
t.string :block_type, null: false
|
|
6
8
|
t.integer :position, null: false
|
|
7
9
|
t.integer :columns, default: 3
|
|
@@ -11,4 +13,14 @@ class CreateHeliosPressBlocks < ActiveRecord::Migration[8.0]
|
|
|
11
13
|
|
|
12
14
|
add_index :helios_press_blocks, [:post_id, :position]
|
|
13
15
|
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def primary_and_foreign_key_types
|
|
20
|
+
config = Rails.configuration.generators
|
|
21
|
+
setting = config.options[config.orm][:primary_key_type]
|
|
22
|
+
primary_key_type = setting || :primary_key
|
|
23
|
+
foreign_key_type = setting || :bigint
|
|
24
|
+
[primary_key_type, foreign_key_type]
|
|
25
|
+
end
|
|
14
26
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
class CreateHeliosPressBlockImages < ActiveRecord::Migration[8.0]
|
|
2
2
|
def change
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
|
4
|
+
|
|
5
|
+
create_table :helios_press_block_images, id: primary_key_type do |t|
|
|
6
|
+
t.references :block, null: false, foreign_key: { to_table: :helios_press_blocks }, type: foreign_key_type
|
|
5
7
|
t.integer :position, null: false
|
|
6
8
|
t.text :caption
|
|
7
9
|
|
|
@@ -10,4 +12,14 @@ class CreateHeliosPressBlockImages < ActiveRecord::Migration[8.0]
|
|
|
10
12
|
|
|
11
13
|
add_index :helios_press_block_images, [:block_id, :position]
|
|
12
14
|
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def primary_and_foreign_key_types
|
|
19
|
+
config = Rails.configuration.generators
|
|
20
|
+
setting = config.options[config.orm][:primary_key_type]
|
|
21
|
+
primary_key_type = setting || :primary_key
|
|
22
|
+
foreign_key_type = setting || :bigint
|
|
23
|
+
[primary_key_type, foreign_key_type]
|
|
24
|
+
end
|
|
13
25
|
end
|
data/lib/helios/press/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: helios-press
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.4'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jason Fleetwood-Boldt
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-05-28 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: rails
|
|
@@ -37,6 +38,20 @@ dependencies:
|
|
|
37
38
|
- - ">="
|
|
38
39
|
- !ruby/object:Gem::Version
|
|
39
40
|
version: '1.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: nokogiri
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.13'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.13'
|
|
40
55
|
- !ruby/object:Gem::Dependency
|
|
41
56
|
name: helios-videos
|
|
42
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -97,6 +112,7 @@ files:
|
|
|
97
112
|
- app/models/helios/press/block.rb
|
|
98
113
|
- app/models/helios/press/block_image.rb
|
|
99
114
|
- app/models/helios/press/post.rb
|
|
115
|
+
- app/services/helios/press/image_ingestor.rb
|
|
100
116
|
- app/views/helios/press/admin/blocks/_block.html.erb
|
|
101
117
|
- app/views/helios/press/admin/blocks/_image_block.html.erb
|
|
102
118
|
- app/views/helios/press/admin/blocks/_image_item.html.erb
|
|
@@ -121,6 +137,7 @@ files:
|
|
|
121
137
|
- db/migrate/20250510000001_create_helios_press_posts.rb
|
|
122
138
|
- db/migrate/20250510000002_create_helios_press_blocks.rb
|
|
123
139
|
- db/migrate/20250510000003_create_helios_press_block_images.rb
|
|
140
|
+
- db/migrate/20250526000001_add_image_ingestion_to_helios_press.rb
|
|
124
141
|
- lib/helios-press.rb
|
|
125
142
|
- lib/helios/press.rb
|
|
126
143
|
- lib/helios/press/configuration.rb
|
|
@@ -133,6 +150,7 @@ licenses:
|
|
|
133
150
|
metadata:
|
|
134
151
|
homepage_uri: https://github.com/heliosdev-shop/helios-press
|
|
135
152
|
source_code_uri: https://github.com/heliosdev-shop/helios-press
|
|
153
|
+
post_install_message:
|
|
136
154
|
rdoc_options: []
|
|
137
155
|
require_paths:
|
|
138
156
|
- lib
|
|
@@ -147,7 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
147
165
|
- !ruby/object:Gem::Version
|
|
148
166
|
version: '0'
|
|
149
167
|
requirements: []
|
|
150
|
-
rubygems_version: 3.
|
|
168
|
+
rubygems_version: 3.4.19
|
|
169
|
+
signing_key:
|
|
151
170
|
specification_version: 4
|
|
152
171
|
summary: Multi-block blog post editor for Rails with drag-to-reorder
|
|
153
172
|
test_files: []
|