bridgetown_directus 0.1.2 → 0.2.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/README.md +74 -94
- data/Rakefile +1 -1
- data/bridgetown.automation.rb +52 -24
- data/bridgetown_directus.gemspec +9 -2
- data/example/bridgetown.config.yml +24 -0
- data/example/config/initializers.rb +34 -0
- data/lib/bridgetown_directus/builder.rb +115 -42
- data/lib/bridgetown_directus/client.rb +71 -0
- data/lib/bridgetown_directus/configuration.rb +82 -0
- data/lib/bridgetown_directus/data_mapper.rb +152 -0
- data/lib/bridgetown_directus/utils.rb +6 -1
- data/lib/bridgetown_directus/version.rb +1 -1
- data/lib/bridgetown_directus.rb +24 -12
- metadata +19 -15
- data/lib/bridgetown_directus/api_client.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd3625cab0b39f5374ad7a3647e5b6e369bed783f05412cb38e15e8f10208908
|
4
|
+
data.tar.gz: a99f097216b2c9239188563a288b0df5752709782c29bfe15673edd73fd6c80d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d70b609eab2f9c4015c4e8898324fe046f8a62673c51d11057ec166372cceb7dfc3cba9793b1a37e3dd175f150d1d2dbc2c7c371427e740b61303630228793f0
|
7
|
+
data.tar.gz: 1dafe4be86342c4196ca93700035ad75f99b0a6a7d0ab78f0592f8ec0a76e51a223b7b63a7f46bf1b0568593b8322b0428f95e5329f38788c55d0a9b07907a9a
|
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
9
9
|
|
10
10
|
- ...
|
11
11
|
|
12
|
+
## [0.2.0] - 2025-04-16
|
13
|
+
|
14
|
+
- BREAKING: Simplified configuration—`resource_type` is no longer required. Use the Bridgetown collection name and layout instead.
|
15
|
+
- Automation now prompts for both Directus and Bridgetown collection names and sets up the initializer accordingly.
|
16
|
+
- Generated files are now flagged with `directus_generated: true` in front matter for safe cleanup.
|
17
|
+
- Only plugin-generated files (with this flag) are deleted during cleanup; user-authored files are preserved.
|
18
|
+
- Layouts for custom collections are now singular (e.g., `staff_member.erb`).
|
19
|
+
- README and example configuration updated for new conventions.
|
20
|
+
- Test suite updated for custom collections and file safety logic.
|
21
|
+
|
12
22
|
## [0.1.0] - 2024-09-27
|
13
23
|
|
14
24
|
- First version
|
data/README.md
CHANGED
@@ -1,138 +1,118 @@
|
|
1
1
|
# Bridgetown Directus Plugin
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/bridgetown_directus)
|
4
|
+
|
5
|
+
This Bridgetown plugin integrates with [Directus](https://directus.io/), a flexible headless CMS. The plugin allows Bridgetown to pull content from a Directus API during the build process and generate static content in your site. It supports both single-language and multilingual content through Directus translations.
|
4
6
|
|
5
7
|
## Features
|
6
8
|
|
7
|
-
- Fetch
|
8
|
-
-
|
9
|
+
- Fetch content from **multiple Directus collections** during the build process
|
10
|
+
- Support for **flexible field mapping** and custom converters
|
11
|
+
- Support for **multilingual content** via Directus translations
|
12
|
+
- **Experimental**: Advanced **filtering, sorting, and pagination** options
|
13
|
+
- Simple configuration for any Bridgetown collection (posts, pages, or custom types)
|
9
14
|
|
10
15
|
## Installation
|
11
16
|
|
12
|
-
Before installing the plugin make sure you have an [Auth Token](https://docs.directus.io/reference/authentication.html#access-tokens) in your Directus instance.
|
17
|
+
Before installing the plugin, make sure you have an [Auth Token](https://docs.directus.io/reference/authentication.html#access-tokens) in your Directus instance.
|
13
18
|
|
14
19
|
### Recommended Installation (Bridgetown Automation)
|
15
20
|
|
16
21
|
1. Run the plugin's automation setup:
|
22
|
+
|
17
23
|
```bash
|
18
24
|
bin/bridgetown apply https://github.com/munkun-estudio/bridgetown_directus
|
19
25
|
```
|
20
|
-
|
26
|
+
|
27
|
+
This will:
|
28
|
+
- Prompt for your Directus API URL, token, Directus collection name, and Bridgetown collection name
|
29
|
+
- Generate a minimal `config/initializers/bridgetown_directus.rb`
|
30
|
+
- All further customization is done in Ruby, not YAML
|
21
31
|
|
22
32
|
### Manual Installation
|
23
33
|
|
24
|
-
1.
|
25
|
-
```ruby
|
26
|
-
bundle add "bridgetown_directus"
|
27
|
-
```
|
28
|
-
2. Run bundle install to install the gem.
|
29
|
-
3. Add the plugin configuration to your config/initializers.rb file:
|
30
|
-
```ruby
|
31
|
-
init :bridgetown_directus do
|
32
|
-
api_url "https://your-directus-instance.com"
|
33
|
-
token ENV['DIRECTUS_AUTH_TOKEN'] || "your_token"
|
34
|
-
|
35
|
-
# Required field mappings
|
36
|
-
mappings do
|
37
|
-
title "title"
|
38
|
-
content "content"
|
39
|
-
slug "slug"
|
40
|
-
date "date"
|
41
|
-
category "category"
|
42
|
-
excerpt "excerpt"
|
43
|
-
image "image"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
```
|
34
|
+
1. Add the gem to your Gemfile:
|
47
35
|
|
48
|
-
|
36
|
+
```ruby
|
37
|
+
bundle add "bridgetown_directus"
|
38
|
+
```
|
49
39
|
|
50
|
-
|
40
|
+
2. Run `bundle install` to install the gem.
|
41
|
+
3. Create `config/initializers/bridgetown_directus.rb` (see below for configuration).
|
51
42
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
export DIRECTUS_AUTH_TOKEN="your-token"
|
56
|
-
```
|
43
|
+
## Configuration
|
44
|
+
|
45
|
+
### Minimal Example
|
57
46
|
|
58
|
-
2. Or hard-code the values directly in your initializer:
|
59
47
|
```ruby
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
48
|
+
# config/initializers/bridgetown_directus.rb
|
49
|
+
init :bridgetown_directus do |directus|
|
50
|
+
directus.api_url = ENV["DIRECTUS_API_URL"] || "https://your-directus-instance.com"
|
51
|
+
directus.token = ENV["DIRECTUS_API_TOKEN"] || "your-token"
|
52
|
+
|
53
|
+
directus.register_collection(:posts) do |c|
|
54
|
+
c.endpoint = "posts"
|
55
|
+
c.layout = "post" # Use the singular layout for individual pages
|
56
|
+
# Minimal mapping (optional):
|
57
|
+
c.field :id, "id"
|
58
|
+
c.field :title, "title"
|
59
|
+
# To enable translations, uncomment and edit:
|
60
|
+
# c.enable_translations([:title, :content])
|
73
61
|
end
|
74
62
|
end
|
75
63
|
```
|
76
|
-
## Usage
|
77
|
-
|
78
|
-
Once the plugin is installed and configured, it will fetch posts from your Directus instance during each build. These posts will be generated as in-memory resources, meaning they are not written to disk but are treated as normal posts by Bridgetown.
|
79
|
-
|
80
|
-
### Directus Setup
|
81
|
-
|
82
|
-
To use the plugin, ensure that you’ve set up a collection in your Directus instance with the following fields (you can name the collection anything you like):
|
83
64
|
|
84
|
-
|
85
|
-
- **content**: The content of the post (Rich Text or Text field)
|
86
|
-
- **slug**: Optional. A unique slug for the post (Text field)
|
87
|
-
- **date**: Optional.The publish date (Datetime field)
|
88
|
-
- **status**: Optional. The status of the post (Option field with values like “published”, “draft”, etc.)
|
89
|
-
- **category**: Optional. The category for the post (Text field)
|
90
|
-
- **excerpt**: Optional. A short excerpt (Text field)
|
91
|
-
- **image**: Optional. An image associated with the post (File/Media field)
|
65
|
+
For custom collections, create a layout file at `src/_layouts/[singular].erb` (e.g., `staff_member.erb`) to control the page rendering.
|
92
66
|
|
93
|
-
|
67
|
+
**By default, all Directus fields will be written to the front matter of generated Markdown files.**
|
68
|
+
You only need to declare fields with `c.field` if you want to:
|
69
|
+
- Rename a field in the output
|
70
|
+
- Transform/convert a field value (e.g., format a date, generate a slug, etc.)
|
71
|
+
- Set a default value if a field is missing
|
94
72
|
|
95
|
-
####
|
73
|
+
#### Example: Customizing a Field
|
96
74
|
|
97
|
-
|
75
|
+
```ruby
|
76
|
+
c.field :slug, "slug" do |value|
|
77
|
+
value || "staff_member-#{SecureRandom.hex(4)}"
|
78
|
+
end
|
79
|
+
```
|
98
80
|
|
99
|
-
|
100
|
-
- In Directus, navigate to **Settings** > **Roles & Permissions**.
|
101
|
-
- Select the **Public** role (or create a custom role if needed).
|
102
|
-
- Under the **Collections** tab, locate the **directus_files** collection.
|
103
|
-
- Set the **read** permission to **enabled** so that the images can be accessed publicly.
|
81
|
+
### Translations
|
104
82
|
|
105
|
-
|
106
|
-
- When users upload images to posts, ensure that the images are associated with the **directus_files** collection.
|
107
|
-
- By default, Directus will store image URLs, which the plugin can reference directly. Ensure that the **image** field or URL is added to the **body** field (or wherever applicable).
|
83
|
+
To enable translations for specific fields, add this inside your collection block:
|
108
84
|
|
85
|
+
```ruby
|
86
|
+
c.enable_translations([:title, :content])
|
87
|
+
```
|
109
88
|
|
110
|
-
|
89
|
+
- You can list any field that exists in your Directus collection, even if it's not declared above with `c.field`.
|
90
|
+
- Only declare a field with `c.field` if you want to rename, transform, or set a default for it.
|
111
91
|
|
112
|
-
|
92
|
+
### File Generation & Cleanup
|
113
93
|
|
114
|
-
|
94
|
+
- **Generated files**: The plugin writes Markdown files to `src/_[bridgetown_collection]/` (e.g., `src/_staff_members/`).
|
95
|
+
- **Safety**: Only files with the `directus_generated: true` flag in their front matter are deleted during cleanup. User-authored files are never removed.
|
115
96
|
|
116
|
-
|
97
|
+
### Advanced Configuration
|
117
98
|
|
118
|
-
|
99
|
+
See the plugin source and inline documentation for advanced features such as:
|
100
|
+
- Multiple collections
|
101
|
+
- Custom layouts per collection
|
102
|
+
- Filtering, sorting, and pagination via `c.default_query` (**experimental**; not fully tested in production—see notes below)
|
103
|
+
- Selective field output
|
119
104
|
|
120
|
-
|
121
|
-
- [ ] Custom Field Mapping via DSL: Implement a DSL for more advanced field mapping.
|
122
|
-
- [ ] Asset Handling: Add functionality to download and manage images and other assets.
|
123
|
-
- [ ] Caching & Incremental Builds: Implement caching to improve build performance when fetching content.
|
124
|
-
- [ ] Draft Previews: Add support for previewing unpublished (draft) posts.
|
105
|
+
**Note:** Filtering, sorting, and pagination via `c.default_query` is experimental and not yet fully tested in real Bridgetown projects. Please report issues or contribute test cases if you use this feature!
|
125
106
|
|
126
|
-
|
107
|
+
### Migrating from 0.1.x
|
127
108
|
|
128
|
-
|
109
|
+
- **YAML config is no longer used.** All configuration is now in Ruby in `config/initializers/bridgetown_directus.rb`.
|
110
|
+
- Field mapping, transformation, and translations are handled in the initializer.
|
111
|
+
- All Directus fields are output by default; use `c.field` for customization.
|
112
|
+
- **Upgrading?** The `resource_type` option is no longer required. Use the Bridgetown collection name and layout instead. See the [CHANGELOG](CHANGELOG.md) for details.
|
129
113
|
|
130
|
-
|
114
|
+
---
|
131
115
|
|
132
|
-
|
116
|
+
For more details and advanced usage, see the [plugin README](https://github.com/Munkun-Estudio/bridgetown_directus).
|
133
117
|
|
134
|
-
|
135
|
-
2. Create a new branch (git checkout -b feature-branch)
|
136
|
-
3. Make your changes
|
137
|
-
4. Push to the branch (git push origin feature-branch)
|
138
|
-
5. Open a Pull Request
|
118
|
+
See [CHANGELOG.md](CHANGELOG.md) for upgrade notes and detailed changes.
|
data/Rakefile
CHANGED
data/bridgetown.automation.rb
CHANGED
@@ -2,35 +2,63 @@ say_status :directus, "Installing the bridgetown_directus plugin..."
|
|
2
2
|
|
3
3
|
# Prompt the user for Directus API URL and Auth Token
|
4
4
|
api_url = ask("What's your Directus instance URL? (Example: https://your-instance.example.com)")
|
5
|
-
auth_token = ask("What's your Directus API auth token? (Leave blank to use ENV['
|
6
|
-
|
5
|
+
auth_token = ask("What's your Directus API auth token? (Leave blank to use ENV['DIRECTUS_API_TOKEN'])")
|
6
|
+
directus_collection = ask("What's the Directus collection name (API endpoint/model)? (Example: posts)")
|
7
|
+
bridgetown_collection = ask("What's the Bridgetown collection name (used for folder and resource)? (Example: posts)")
|
7
8
|
|
8
9
|
# Add the bridgetown_directus gem
|
9
10
|
add_gem "bridgetown_directus"
|
10
11
|
|
11
|
-
# Add Directus configuration to config/initializers.rb
|
12
|
-
add_initializer :
|
12
|
+
# Add minimal Directus configuration to config/initializers.rb in the idiomatic Bridgetown plugin style
|
13
|
+
add_initializer :bridgetown_directus do |directus|
|
13
14
|
<<~RUBY
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
15
|
+
# This block was generated by bridgetown_directus automation.
|
16
|
+
# All Directus configuration is now handled here (not in YAML).
|
17
|
+
# Set DIRECTUS_API_URL and DIRECTUS_API_TOKEN in your .env or shell environment.
|
18
|
+
#
|
19
|
+
# By default, ALL fields from Directus will be written to the front matter of generated Markdown files.
|
20
|
+
# You only need to declare fields here if you want to:
|
21
|
+
# - Rename a field in the output
|
22
|
+
# - Transform/convert a field value (e.g., format a date, generate a slug, etc.)
|
23
|
+
# - Set a default value if a field is missing
|
24
|
+
#
|
25
|
+
# Example: To customize or transform fields, use the c.field declaration:
|
26
|
+
# # require "securerandom" # Uncomment if you use SecureRandom in your mapping
|
27
|
+
# c.field :slug, "slug" do |value|
|
28
|
+
# value || "post-#{SecureRandom.hex(4)}"
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# ---
|
32
|
+
# TRANSLATIONS:
|
33
|
+
# To enable translations for specific fields, add this line inside your collection block:
|
34
|
+
# c.enable_translations([:title, :content])
|
35
|
+
# You can list any field that exists in your Directus collection, even if it's not declared above with c.field.
|
36
|
+
# Declaring a field with c.field is only required if you want to rename, transform, or set a default for it.
|
37
|
+
# ---
|
38
|
+
|
39
|
+
directus.api_url = ENV["DIRECTUS_API_URL"] || "#{api_url}"
|
40
|
+
directus.token = ENV["DIRECTUS_API_TOKEN"] || "#{auth_token}"
|
41
|
+
|
42
|
+
directus.register_collection(:#{bridgetown_collection}) do |c|
|
43
|
+
c.endpoint = "#{directus_collection}"
|
44
|
+
c.layout = "#{bridgetown_collection.to_s.singularize}"
|
45
|
+
# Minimal mapping (optional):
|
46
|
+
c.field :id, "id"
|
47
|
+
c.field :title, "title"
|
48
|
+
# Add more c.field declarations above as needed for custom logic.
|
49
|
+
# To enable translations, uncomment and edit the following line:
|
50
|
+
# c.enable_translations([:title, :content])
|
29
51
|
end
|
30
52
|
RUBY
|
31
53
|
end
|
32
|
-
|
33
|
-
say_status :
|
34
|
-
say_status :directus, "Check config/initializers.rb for your Directus setup
|
35
|
-
say_status :directus, "
|
36
|
-
|
54
|
+
|
55
|
+
say_status :success, "Bridgetown Directus plugin has been installed!", :green
|
56
|
+
say_status :directus, "Check config/initializers.rb for your Directus setup."
|
57
|
+
say_status :directus, "Check bridgetown.config.yml for your collection setup."
|
58
|
+
|
59
|
+
# Only remind the user to create a layout if it's a custom collection (not 'posts' or 'pages')
|
60
|
+
if !%w[posts pages].include?(bridgetown_collection.to_s)
|
61
|
+
say_status :directus, "Don't forget to create a layout file at src/_layouts/#{bridgetown_collection.to_s.singularize}.erb for your custom collection pages!"
|
62
|
+
end
|
63
|
+
|
64
|
+
say_status :directus, "For advanced usage and field customization, see the README: https://github.com/Munkun-Estudio/bridgetown_directus"
|
data/bridgetown_directus.gemspec
CHANGED
@@ -15,9 +15,16 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.test_files = spec.files.grep(%r!^test/!)
|
16
16
|
spec.require_paths = ["lib"]
|
17
17
|
|
18
|
+
spec.metadata = {
|
19
|
+
"source_code_uri" => spec.homepage,
|
20
|
+
"bug_tracker_uri" => "#{spec.homepage}/issues",
|
21
|
+
"changelog_uri" => "#{spec.homepage}/releases",
|
22
|
+
"homepage_uri" => spec.homepage
|
23
|
+
}
|
24
|
+
|
18
25
|
spec.required_ruby_version = ">= 2.7.0"
|
19
26
|
|
20
|
-
spec.add_dependency "bridgetown", ">=
|
27
|
+
spec.add_dependency "bridgetown", ">= 2.0.0.beta4", "< 3.0"
|
21
28
|
spec.add_dependency "faraday", "~> 2.12"
|
22
29
|
|
23
30
|
spec.add_development_dependency "bundler", "~> 2.0"
|
@@ -25,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
25
32
|
spec.add_development_dependency "rubocop-bridgetown", "~> 0.3"
|
26
33
|
spec.add_development_dependency "shoulda", "~> 3.0"
|
27
34
|
spec.add_development_dependency "minitest", "~> 5.0"
|
28
|
-
spec.add_development_dependency "minitest-profile", "~> 0.
|
35
|
+
spec.add_development_dependency "minitest-profile", "~> 0.0.2"
|
29
36
|
spec.add_development_dependency "minitest-reporters", "~> 1.0"
|
30
37
|
spec.add_development_dependency "webmock", "~> 3.0"
|
31
38
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Example Bridgetown configuration file for the enhanced Directus plugin
|
2
|
+
|
3
|
+
# Site settings
|
4
|
+
title: My Bridgetown Site with Directus
|
5
|
+
email: your-email@example.com
|
6
|
+
description: >-
|
7
|
+
A Bridgetown site powered by Directus headless CMS
|
8
|
+
baseurl: ""
|
9
|
+
url: ""
|
10
|
+
|
11
|
+
# Collections
|
12
|
+
collections:
|
13
|
+
posts:
|
14
|
+
output: true
|
15
|
+
permalink: /blog/:slug/
|
16
|
+
source: _posts
|
17
|
+
future: true
|
18
|
+
staff_members:
|
19
|
+
output: true
|
20
|
+
permalink: /staff_members/:slug/
|
21
|
+
source: _staff_members
|
22
|
+
sort_field: 'created_at'
|
23
|
+
sort_reverse: false
|
24
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Example Bridgetown Directus plugin initializer for v2+
|
4
|
+
#
|
5
|
+
# All Directus configuration is now handled here, NOT in bridgetown.config.yml.
|
6
|
+
# Use ENV variables for secrets and API credentials.
|
7
|
+
|
8
|
+
require "securerandom"
|
9
|
+
require "time"
|
10
|
+
|
11
|
+
init :bridgetown_directus do |directus|
|
12
|
+
# Set API credentials from environment variables
|
13
|
+
directus.api_url = ENV["DIRECTUS_API_URL"] || "https://your-directus-instance.com"
|
14
|
+
directus.token = ENV["DIRECTUS_API_TOKEN"] || "your-token-here"
|
15
|
+
|
16
|
+
# Example custom collection: staff_members
|
17
|
+
directus.register_collection(:staff_members) do |c|
|
18
|
+
c.endpoint = "staff_members"
|
19
|
+
c.layout = "staff_member"
|
20
|
+
c.field :id, "id"
|
21
|
+
c.field :title, "title"
|
22
|
+
# To enable translations, uncomment and edit:
|
23
|
+
# c.enable_translations([:title, :content])
|
24
|
+
# Add more fields as needed
|
25
|
+
end
|
26
|
+
|
27
|
+
# Example for posts (if needed)
|
28
|
+
directus.register_collection(:posts) do |c|
|
29
|
+
c.endpoint = "articles"
|
30
|
+
c.layout = "post"
|
31
|
+
c.field :title, "title"
|
32
|
+
c.field :content, "body"
|
33
|
+
end
|
34
|
+
end
|
@@ -1,62 +1,135 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "yaml"
|
4
|
+
|
3
5
|
module BridgetownDirectus
|
4
6
|
class Builder < Bridgetown::Builder
|
5
7
|
def build
|
8
|
+
config = site.config.bridgetown_directus
|
6
9
|
return if site.ssr?
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Utils.log_directus "Fetched #{posts_data.size} posts from Directus."
|
11
|
+
config.collections.each_value do |collection_config|
|
12
|
+
next unless [:posts, :pages, :custom_collection].include?(collection_config.resource_type)
|
12
13
|
|
13
|
-
|
14
|
+
process_collection(
|
15
|
+
client: Client.new(
|
16
|
+
api_url: config.api_url,
|
17
|
+
token: config.token
|
18
|
+
),
|
19
|
+
collection_config: collection_config
|
20
|
+
)
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
24
|
private
|
17
25
|
|
18
|
-
|
19
|
-
|
20
|
-
|
26
|
+
# Determine the output directory for the given collection name
|
27
|
+
def collection_directory(collection_name)
|
28
|
+
case collection_name.to_s
|
29
|
+
when "posts"
|
30
|
+
File.join(site.source, "_posts")
|
31
|
+
when "pages"
|
32
|
+
File.join(site.source, "_pages")
|
33
|
+
else
|
34
|
+
File.join(site.source, "_#{collection_name}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Write a Directus item as a Markdown file in the correct Bridgetown collection directory
|
39
|
+
def write_directus_file(item, collection_dir, layout = nil, api_url = nil)
|
40
|
+
require "fileutils"
|
41
|
+
FileUtils.mkdir_p(collection_dir)
|
42
|
+
slug = item["slug"] || item["id"].to_s
|
43
|
+
filename = build_filename(collection_dir, slug)
|
44
|
+
item = transform_item_fields(item, api_url, layout)
|
45
|
+
item["directus_generated"] = true # Add flag to front matter
|
46
|
+
content = item.delete("body") || ""
|
47
|
+
front_matter = generate_front_matter(item)
|
48
|
+
write_markdown_file(filename, front_matter, content)
|
21
49
|
end
|
22
50
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
def build_filename(collection_dir, slug)
|
52
|
+
File.join(collection_dir, "#{slug}.md")
|
53
|
+
end
|
54
|
+
|
55
|
+
def transform_item_fields(item, api_url, layout)
|
56
|
+
item = item.dup
|
57
|
+
if item["image"] && api_url && !item["image"].to_s.start_with?("http://", "https://")
|
58
|
+
item["image"] = File.join(api_url, "assets", item["image"])
|
59
|
+
end
|
60
|
+
item["layout"] = layout if layout
|
61
|
+
item
|
62
|
+
end
|
63
|
+
|
64
|
+
def generate_front_matter(item)
|
65
|
+
yaml = item.to_yaml
|
66
|
+
yaml.sub(%r{^---\s*\n}, "") # Remove leading --- if present
|
67
|
+
end
|
68
|
+
|
69
|
+
def write_markdown_file(filename, front_matter, content)
|
70
|
+
File.write(filename, "---\n#{front_matter}---\n\n#{content}")
|
71
|
+
end
|
72
|
+
|
73
|
+
# Remove only plugin-generated Markdown files in the target directory before writing new ones
|
74
|
+
def clean_collection_directory(collection_dir)
|
75
|
+
require "yaml"
|
76
|
+
Dir.glob(File.join(collection_dir, "*.md")).each do |file|
|
77
|
+
fm = File.read(file)[%r{\A---.*?---}m]
|
78
|
+
File.delete(file) if fm && YAML.safe_load(fm)["directus_generated"]
|
79
|
+
rescue StandardError => e
|
80
|
+
warn "[BridgetownDirectus] Could not check/delete #{file}: #{e.message}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_collection(client:, collection_config:)
|
85
|
+
endpoint = collection_config.endpoint || collection_config.name.to_s
|
86
|
+
begin
|
87
|
+
response = client.fetch_collection(endpoint, collection_config.default_query)
|
88
|
+
rescue StandardError => e
|
89
|
+
warn "Error fetching collection '#{endpoint}': #{e.message}"
|
90
|
+
return
|
91
|
+
end
|
92
|
+
collection_dir = collection_directory(collection_config.name)
|
93
|
+
clean_collection_directory(collection_dir)
|
94
|
+
api_url = site.config.bridgetown_directus.api_url
|
95
|
+
sanitized_response = sanitize_keys(response)
|
96
|
+
sanitized_response.each do |item|
|
97
|
+
write_directus_file(item, collection_dir, collection_config.layout, api_url)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Recursively sanitize keys to avoid illegal instance variable names (Ruby 3.4+)
|
102
|
+
def sanitize_keys(obj)
|
103
|
+
case obj
|
104
|
+
when Hash
|
105
|
+
obj.each_with_object({}) do |(k, v), h|
|
106
|
+
safe_key = if %r{^\d}.match?(k.to_s)
|
107
|
+
"n_#{k}"
|
108
|
+
else
|
109
|
+
k
|
110
|
+
end
|
111
|
+
h[safe_key] = sanitize_keys(v)
|
56
112
|
end
|
113
|
+
when Array
|
114
|
+
obj.map { |v| sanitize_keys(v) }
|
115
|
+
else
|
116
|
+
obj
|
57
117
|
end
|
118
|
+
end
|
58
119
|
|
59
|
-
|
120
|
+
# Recursively log all keys to find problematic ones
|
121
|
+
def log_all_keys(obj, path = "")
|
122
|
+
case obj
|
123
|
+
when Hash
|
124
|
+
obj.each do |k, v|
|
125
|
+
# puts "[BridgetownDirectus DEBUG] Key at #{path}: #{k.inspect}" if %r{^\d}.match?(k.to_s)
|
126
|
+
log_all_keys(v, "#{path}/#{k}")
|
127
|
+
end
|
128
|
+
when Array
|
129
|
+
obj.each_with_index do |v, idx|
|
130
|
+
log_all_keys(v, "#{path}[#{idx}]")
|
131
|
+
end
|
132
|
+
end
|
60
133
|
end
|
61
134
|
end
|
62
135
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "faraday"
|
5
|
+
|
6
|
+
module BridgetownDirectus
|
7
|
+
# Client for interacting with the Directus API
|
8
|
+
class Client
|
9
|
+
attr_reader :api_url, :token
|
10
|
+
|
11
|
+
def initialize(api_url:, token:)
|
12
|
+
@api_url = api_url
|
13
|
+
@token = token
|
14
|
+
return unless @token.nil? || @api_url.nil?
|
15
|
+
|
16
|
+
raise StandardError, "Invalid Directus configuration: missing API token or URL"
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch_collection(collection, params = {})
|
20
|
+
response = connection.get("/items/#{collection}") do |req|
|
21
|
+
req.params.merge!(prepare_params(params))
|
22
|
+
end
|
23
|
+
handle_response(response)
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch_item(collection, id, params = {})
|
27
|
+
response = connection.get("/items/#{collection}/#{id}") do |req|
|
28
|
+
req.params.merge!(prepare_params(params))
|
29
|
+
end
|
30
|
+
handle_response(response)
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_items_with_filter(collection, filter, params = {})
|
34
|
+
merged_params = params.merge(filter: filter)
|
35
|
+
fetch_collection(collection, merged_params)
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch_related_items(collection, id, relation, params = {})
|
39
|
+
response = connection.get("/items/#{collection}/#{id}/#{relation}") do |req|
|
40
|
+
req.params.merge!(prepare_params(params))
|
41
|
+
end
|
42
|
+
handle_response(response)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def connection
|
48
|
+
@connection ||= Faraday.new(url: @api_url) do |faraday|
|
49
|
+
faraday.headers["Authorization"] = "Bearer #{@token}"
|
50
|
+
faraday.headers["Content-Type"] = "application/json"
|
51
|
+
faraday.adapter Faraday.default_adapter
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def prepare_params(params)
|
56
|
+
params.transform_keys(&:to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_response(response)
|
60
|
+
unless response.success?
|
61
|
+
Utils.log_directus "Directus API error: #{response.status} - #{response.body}"
|
62
|
+
raise "Directus API error: #{response.status}"
|
63
|
+
end
|
64
|
+
json = JSON.parse(response.body)
|
65
|
+
json["data"] || []
|
66
|
+
rescue JSON::ParserError => e
|
67
|
+
Utils.log_directus "Failed to parse Directus response: #{e.message}"
|
68
|
+
raise
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BridgetownDirectus
|
4
|
+
# Configuration module for Bridgetown Directus plugin
|
5
|
+
class Configuration
|
6
|
+
attr_reader :collections
|
7
|
+
attr_accessor :api_url, :token
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@collections = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Register a new collection with the given name
|
14
|
+
# @param name [Symbol] The name of the collection
|
15
|
+
# @param block [Proc] Configuration block for the collection
|
16
|
+
# @return [CollectionConfig] The collection configuration
|
17
|
+
def register_collection(name, &block)
|
18
|
+
collection = CollectionConfig.new(name)
|
19
|
+
collection.instance_eval(&block) if block_given?
|
20
|
+
@collections[name] = collection
|
21
|
+
collection
|
22
|
+
end
|
23
|
+
|
24
|
+
# Find a collection by name
|
25
|
+
# @param name [Symbol] The name of the collection
|
26
|
+
# @return [CollectionConfig, nil] The collection configuration or nil if not found
|
27
|
+
def find_collection(name)
|
28
|
+
@collections[name]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Collection configuration class
|
32
|
+
class CollectionConfig
|
33
|
+
attr_reader :name
|
34
|
+
|
35
|
+
# Initialize a new collection configuration
|
36
|
+
# @param name [Symbol] The name of the collection
|
37
|
+
def initialize(name)
|
38
|
+
@name = name
|
39
|
+
@fields = {}
|
40
|
+
@default_query = {}
|
41
|
+
@resource_type = :posts
|
42
|
+
@layout = "post"
|
43
|
+
@translations_enabled = false
|
44
|
+
@translatable_fields = []
|
45
|
+
@endpoint = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set up accessors for collection configuration properties
|
49
|
+
attr_accessor :endpoint, :fields, :default_query, :resource_type, :layout,
|
50
|
+
:translations_enabled, :translatable_fields
|
51
|
+
|
52
|
+
# Define a field mapping with optional converter
|
53
|
+
# @param bridgetown_field [Symbol] The field name in Bridgetown
|
54
|
+
# @param directus_field [String, Symbol] The field name in Directus
|
55
|
+
# @param converter [Proc, nil] Optional converter to transform the field value
|
56
|
+
# @return [void]
|
57
|
+
def field(bridgetown_field, directus_field, &converter)
|
58
|
+
@fields[bridgetown_field] = {
|
59
|
+
directus_field: directus_field.to_s,
|
60
|
+
converter: converter,
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Enable translations for this collection
|
65
|
+
# @param fields [Array<Symbol>] The fields that should be translated
|
66
|
+
# @return [void]
|
67
|
+
def enable_translations(fields = [])
|
68
|
+
@translations_enabled = true
|
69
|
+
@translatable_fields = fields
|
70
|
+
end
|
71
|
+
|
72
|
+
# Generate the resource path for a given item
|
73
|
+
# @param item [Hash] The data item from Directus
|
74
|
+
# @return [String] The resource path
|
75
|
+
def path(item)
|
76
|
+
# Default: /:resource_type/:slug/index.html
|
77
|
+
slug = item["slug"] || item[:slug] || item["id"] || item[:id]
|
78
|
+
"/#{resource_type}/#{slug}/index.html"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BridgetownDirectus
|
4
|
+
# Data mapper for transforming Directus data into Bridgetown resources
|
5
|
+
class DataMapper
|
6
|
+
class << self
|
7
|
+
# Map Directus data to Bridgetown format based on collection configuration
|
8
|
+
# @param collection_config [CollectionConfig] The collection configuration
|
9
|
+
# @param data [Hash] The Directus data
|
10
|
+
# @return [Hash] The mapped data
|
11
|
+
def map(collection_config, data)
|
12
|
+
mapped_data = {}
|
13
|
+
|
14
|
+
collection_config.fields.each do |bridgetown_field, field_config|
|
15
|
+
if field_config.is_a?(Hash)
|
16
|
+
directus_field = field_config[:directus_field]
|
17
|
+
converter = field_config[:converter]
|
18
|
+
|
19
|
+
value = extract_value(data, directus_field)
|
20
|
+
|
21
|
+
# Apply converter if provided
|
22
|
+
value = converter.call(value) if converter.respond_to?(:call)
|
23
|
+
|
24
|
+
mapped_data[bridgetown_field] = value
|
25
|
+
else
|
26
|
+
# Support for simple string mapping for backward compatibility
|
27
|
+
directus_field = field_config.to_s
|
28
|
+
mapped_data[bridgetown_field] = extract_value(data, directus_field)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
mapped_data
|
33
|
+
end
|
34
|
+
|
35
|
+
# Map translated fields from Directus data
|
36
|
+
# @param collection_config [CollectionConfig] The collection configuration
|
37
|
+
# @param data [Hash] The Directus data
|
38
|
+
# @param locale [Symbol] The locale to map
|
39
|
+
# @return [Hash] The mapped data with translations
|
40
|
+
def map_translations(collection_config, data, locale)
|
41
|
+
# First map the base data
|
42
|
+
mapped_data = map(collection_config, data)
|
43
|
+
|
44
|
+
# If translations are enabled and the data has translations
|
45
|
+
return mapped_data unless collection_config.translations_enabled && data["translations"]
|
46
|
+
|
47
|
+
# Find the translation for the requested locale
|
48
|
+
translation = find_translation_for_locale(data["translations"], locale)
|
49
|
+
|
50
|
+
# Apply translations if found
|
51
|
+
if translation
|
52
|
+
apply_translations(collection_config, translation, mapped_data)
|
53
|
+
mapped_data[:locale] = locale
|
54
|
+
end
|
55
|
+
|
56
|
+
mapped_data
|
57
|
+
end
|
58
|
+
|
59
|
+
# Resolve relationships in the data
|
60
|
+
# @param client [Client] The Directus client
|
61
|
+
# @param collection_config [CollectionConfig] The collection configuration
|
62
|
+
# @param data [Hash] The mapped data
|
63
|
+
# @param relationships [Hash] Relationship configuration
|
64
|
+
# @return [Hash] The data with resolved relationships
|
65
|
+
def resolve_relationships(client, collection_config, data, relationships)
|
66
|
+
return data unless relationships
|
67
|
+
|
68
|
+
resolved_data = data.dup
|
69
|
+
|
70
|
+
relationships.each do |field, relationship_config|
|
71
|
+
relation_id = data[field]
|
72
|
+
next unless relation_id
|
73
|
+
|
74
|
+
related_collection = relationship_config[:collection]
|
75
|
+
related_fields = relationship_config[:fields] || "*"
|
76
|
+
|
77
|
+
# Fetch the related item
|
78
|
+
related_item = client.fetch_item(
|
79
|
+
related_collection,
|
80
|
+
relation_id,
|
81
|
+
{ fields: related_fields }
|
82
|
+
)
|
83
|
+
|
84
|
+
# Add the related data to the resolved data
|
85
|
+
if related_item && related_item["data"]
|
86
|
+
resolved_data["#{field}_data"] = related_item["data"]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
resolved_data
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Find translation for a specific locale
|
96
|
+
# @param translations [Array] Array of translation objects
|
97
|
+
# @param locale [Symbol] The locale to find
|
98
|
+
# @return [Hash, nil] The translation for the locale or nil if not found
|
99
|
+
def find_translation_for_locale(translations, locale)
|
100
|
+
translations.find do |t|
|
101
|
+
lang_code = t["languages_code"].to_s.split("-").first.downcase
|
102
|
+
lang_code == locale.to_s
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Apply translations to mapped data
|
107
|
+
# @param collection_config [CollectionConfig] The collection configuration
|
108
|
+
# @param translation [Hash] The translation data
|
109
|
+
# @param mapped_data [Hash] The mapped data to update
|
110
|
+
# @return [void]
|
111
|
+
def apply_translations(collection_config, translation, mapped_data)
|
112
|
+
collection_config.translatable_fields.each do |field|
|
113
|
+
# Get the Directus field name for this Bridgetown field
|
114
|
+
field_config = collection_config.fields[field]
|
115
|
+
|
116
|
+
directus_field = field_config.is_a?(Hash) ? field_config[:directus_field] : field_config.to_s
|
117
|
+
|
118
|
+
# Check if the translation has this field
|
119
|
+
next unless translation[directus_field]
|
120
|
+
|
121
|
+
value = translation[directus_field]
|
122
|
+
|
123
|
+
# Apply converter if provided
|
124
|
+
if field_config.is_a?(Hash) && field_config[:converter].respond_to?(:call)
|
125
|
+
value = field_config[:converter].call(value)
|
126
|
+
end
|
127
|
+
|
128
|
+
mapped_data[field] = value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Extract a value from nested data using dot notation
|
133
|
+
# @param data [Hash] The data to extract from
|
134
|
+
# @param field [String] The field path (e.g., "user.profile.name")
|
135
|
+
# @return [Object] The extracted value
|
136
|
+
def extract_value(data, field)
|
137
|
+
return nil unless data
|
138
|
+
|
139
|
+
keys = field.to_s.split(".")
|
140
|
+
value = data
|
141
|
+
|
142
|
+
keys.each do |key|
|
143
|
+
return nil unless value.is_a?(Hash) && value.key?(key)
|
144
|
+
|
145
|
+
value = value[key]
|
146
|
+
end
|
147
|
+
|
148
|
+
value
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -3,7 +3,12 @@
|
|
3
3
|
module BridgetownDirectus
|
4
4
|
module Utils
|
5
5
|
def self.log_directus(message)
|
6
|
-
Bridgetown.logger
|
6
|
+
if defined?(Bridgetown) && Bridgetown.respond_to?(:logger)
|
7
|
+
Bridgetown.logger.info("Directus") { message }
|
8
|
+
elsif ENV["BRIDGETOWN_DIRECTUS_DEBUG"]
|
9
|
+
# Fallback for testing or when Bridgetown is not available
|
10
|
+
puts "[Directus] #{message}"
|
11
|
+
end
|
7
12
|
end
|
8
13
|
end
|
9
14
|
end
|
data/lib/bridgetown_directus.rb
CHANGED
@@ -1,27 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bridgetown"
|
4
|
-
require_relative "bridgetown_directus/version"
|
5
4
|
require_relative "bridgetown_directus/utils"
|
6
|
-
require_relative "bridgetown_directus/
|
5
|
+
require_relative "bridgetown_directus/client"
|
6
|
+
require_relative "bridgetown_directus/data_mapper"
|
7
|
+
require_relative "bridgetown_directus/configuration"
|
7
8
|
require_relative "bridgetown_directus/builder"
|
8
9
|
|
9
10
|
module BridgetownDirectus
|
10
11
|
# Bridgetown initializer for the plugin
|
11
|
-
Bridgetown.initializer :bridgetown_directus do |config
|
12
|
-
config.bridgetown_directus
|
13
|
-
config.bridgetown_directus
|
14
|
-
|
15
|
-
|
16
|
-
config.bridgetown_directus.
|
12
|
+
Bridgetown.initializer :bridgetown_directus do |config|
|
13
|
+
# Only assign config.bridgetown_directus if not already set
|
14
|
+
config.bridgetown_directus ||= Configuration.new
|
15
|
+
|
16
|
+
# Set up configuration directly (leave to user initializer if possible)
|
17
|
+
config.bridgetown_directus.api_url ||= ENV["DIRECTUS_API_URL"] || "[https://studio.munkun.com](https://studio.munkun.com)"
|
18
|
+
config.bridgetown_directus.token ||= ENV["DIRECTUS_TOKEN"] || "t1P6YstcUslmf-KJFbc6Kyg0bomMxkXY"
|
17
19
|
|
18
20
|
# Register the builder
|
19
21
|
config.builder BridgetownDirectus::Builder
|
22
|
+
end
|
23
|
+
|
24
|
+
class Configuration
|
25
|
+
attr_accessor :api_url, :token
|
26
|
+
attr_reader :collections
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@collections = {}
|
30
|
+
end
|
20
31
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
32
|
+
def register_collection(name, &block)
|
33
|
+
collection = CollectionConfig.new(name)
|
34
|
+
collection.instance_eval(&block) if block_given?
|
35
|
+
@collections[name] = collection
|
36
|
+
collection
|
25
37
|
end
|
26
38
|
end
|
27
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bridgetown_directus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Munkun
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-04-16 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: bridgetown
|
@@ -16,20 +15,20 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
18
|
+
version: 2.0.0.beta4
|
20
19
|
- - "<"
|
21
20
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
21
|
+
version: '3.0'
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
24
|
version_requirements: !ruby/object:Gem::Requirement
|
26
25
|
requirements:
|
27
26
|
- - ">="
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
28
|
+
version: 2.0.0.beta4
|
30
29
|
- - "<"
|
31
30
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
31
|
+
version: '3.0'
|
33
32
|
- !ruby/object:Gem::Dependency
|
34
33
|
name: faraday
|
35
34
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,14 +119,14 @@ dependencies:
|
|
120
119
|
requirements:
|
121
120
|
- - "~>"
|
122
121
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
122
|
+
version: 0.0.2
|
124
123
|
type: :development
|
125
124
|
prerelease: false
|
126
125
|
version_requirements: !ruby/object:Gem::Requirement
|
127
126
|
requirements:
|
128
127
|
- - "~>"
|
129
128
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
129
|
+
version: 0.0.2
|
131
130
|
- !ruby/object:Gem::Dependency
|
132
131
|
name: minitest-reporters
|
133
132
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,7 +155,6 @@ dependencies:
|
|
156
155
|
- - "~>"
|
157
156
|
- !ruby/object:Gem::Version
|
158
157
|
version: '3.0'
|
159
|
-
description:
|
160
158
|
email: development@munkun.com
|
161
159
|
executables: []
|
162
160
|
extensions: []
|
@@ -171,17 +169,24 @@ files:
|
|
171
169
|
- Rakefile
|
172
170
|
- bridgetown.automation.rb
|
173
171
|
- bridgetown_directus.gemspec
|
172
|
+
- example/bridgetown.config.yml
|
173
|
+
- example/config/initializers.rb
|
174
174
|
- lib/bridgetown_directus.rb
|
175
|
-
- lib/bridgetown_directus/api_client.rb
|
176
175
|
- lib/bridgetown_directus/builder.rb
|
176
|
+
- lib/bridgetown_directus/client.rb
|
177
|
+
- lib/bridgetown_directus/configuration.rb
|
178
|
+
- lib/bridgetown_directus/data_mapper.rb
|
177
179
|
- lib/bridgetown_directus/utils.rb
|
178
180
|
- lib/bridgetown_directus/version.rb
|
179
181
|
- package.json
|
180
182
|
homepage: https://github.com/munkun-estudio/bridgetown_directus
|
181
183
|
licenses:
|
182
184
|
- MIT
|
183
|
-
metadata:
|
184
|
-
|
185
|
+
metadata:
|
186
|
+
source_code_uri: https://github.com/munkun-estudio/bridgetown_directus
|
187
|
+
bug_tracker_uri: https://github.com/munkun-estudio/bridgetown_directus/issues
|
188
|
+
changelog_uri: https://github.com/munkun-estudio/bridgetown_directus/releases
|
189
|
+
homepage_uri: https://github.com/munkun-estudio/bridgetown_directus
|
185
190
|
rdoc_options: []
|
186
191
|
require_paths:
|
187
192
|
- lib
|
@@ -196,8 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
201
|
- !ruby/object:Gem::Version
|
197
202
|
version: '0'
|
198
203
|
requirements: []
|
199
|
-
rubygems_version: 3.
|
200
|
-
signing_key:
|
204
|
+
rubygems_version: 3.6.2
|
201
205
|
specification_version: 4
|
202
206
|
summary: Use Directus as headless CMS for Bridgetown
|
203
207
|
test_files: []
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module BridgetownDirectus
|
4
|
-
class APIClient
|
5
|
-
def initialize(site)
|
6
|
-
@site = site
|
7
|
-
@api_url = site.config.bridgetown_directus.api_url
|
8
|
-
@api_token = site.config.bridgetown_directus.token
|
9
|
-
|
10
|
-
raise StandardError, "Invalid Directus configuration: missing API token or URL" if @api_token.nil? || @api_url.nil?
|
11
|
-
end
|
12
|
-
|
13
|
-
# Main method to fetch posts
|
14
|
-
def fetch_posts
|
15
|
-
Utils.log_directus "Request URL: #{@api_url}/items/#{@site.config.bridgetown_directus.collection}"
|
16
|
-
|
17
|
-
response = connection.get("/items/#{@site.config.bridgetown_directus.collection}") do |req|
|
18
|
-
req.params['filter'] = { status: { _eq: "published" } }.to_json
|
19
|
-
end
|
20
|
-
|
21
|
-
if response.success?
|
22
|
-
JSON.parse(response.body) # Return the parsed posts
|
23
|
-
elsif response.status == 401
|
24
|
-
raise RuntimeError, "Unauthorized access to Directus API"
|
25
|
-
else
|
26
|
-
raise "Error fetching posts: #{response.status} - #{response.body}"
|
27
|
-
end
|
28
|
-
rescue Faraday::TimeoutError
|
29
|
-
raise Faraday::TimeoutError, "The request to fetch posts timed out"
|
30
|
-
rescue JSON::ParserError
|
31
|
-
raise JSON::ParserError, "The response from Directus was not valid JSON"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Setup Faraday connection with authorization headers
|
35
|
-
def connection
|
36
|
-
Faraday.new(url: @api_url) do |faraday|
|
37
|
-
faraday.options.timeout = 5
|
38
|
-
faraday.options.open_timeout = 2
|
39
|
-
faraday.headers['Authorization'] = "Bearer #{@api_token}"
|
40
|
-
faraday.headers['Content-Type'] = 'application/json'
|
41
|
-
faraday.adapter Faraday.default_adapter
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# New method for validating the data structure
|
46
|
-
private def validate_posts_data(posts_data)
|
47
|
-
if posts_data.is_a?(Hash) && posts_data.key?("data") && posts_data["data"].is_a?(Array)
|
48
|
-
posts_data["data"]
|
49
|
-
elsif posts_data.is_a?(Array)
|
50
|
-
posts_data
|
51
|
-
else
|
52
|
-
raise "Unexpected structure of posts_data: #{posts_data.inspect}"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|