bridgetown_directus 0.1.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b86e165473c96ffa32fc96cf04ec0b5564169bcdd53866489c6f806f16235dfe
4
- data.tar.gz: c7ea854a2e0263589a31d467b164f061fe15399126a90de273b4c1b8a6366226
3
+ metadata.gz: dd3625cab0b39f5374ad7a3647e5b6e369bed783f05412cb38e15e8f10208908
4
+ data.tar.gz: a99f097216b2c9239188563a288b0df5752709782c29bfe15673edd73fd6c80d
5
5
  SHA512:
6
- metadata.gz: 80a9bfad8a419d19159a2f0a6f7538afc142837a3baff3737bd9c1c5f127f039d7990432ace15dffea1cf3b474129a23335919e1c9e6fa975e4df653ecf83e67
7
- data.tar.gz: '098a9aeb10f146c6a30ee1a60d428390d52998e3bf438735b95f5de0b7fbd0afdfbb61f3982f816c1c12b43224b71afcda6f1783aaf8cb4a52a9b9b1ad545aab'
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
@@ -2,16 +2,19 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/bridgetown_directus.svg)](https://badge.fury.io/rb/bridgetown_directus)
4
4
 
5
- This Bridgetown plugin integrates with [Directus](https://directus.io/), which is among other things a [headless CMS](https://en.wikipedia.org/wiki/Headless_content_management_system). 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.
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.
6
6
 
7
7
  ## Features
8
8
 
9
- - Fetch **published posts** from Directus during the build process
10
- - Support for **multilingual content** through Directus translations
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)
11
14
 
12
15
  ## Installation
13
16
 
14
- 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.
15
18
 
16
19
  ### Recommended Installation (Bridgetown Automation)
17
20
 
@@ -21,11 +24,10 @@ Before installing the plugin make sure you have an [Auth Token](https://docs.dir
21
24
  bin/bridgetown apply https://github.com/munkun-estudio/bridgetown_directus
22
25
  ```
23
26
 
24
- 2. The setup will guide you through:
25
- - Providing the Directus API URL and Auth Token
26
- - Specifying your content collection name
27
- - Enabling/disabling translations support
28
- - Configuring translatable fields (if translations enabled)
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
29
31
 
30
32
  ### Manual Installation
31
33
 
@@ -35,140 +37,82 @@ Before installing the plugin make sure you have an [Auth Token](https://docs.dir
35
37
  bundle add "bridgetown_directus"
36
38
  ```
37
39
 
38
- 2. Run bundle install to install the gem.
39
- 3. Add the plugin configuration to your config/initializers.rb file:
40
-
41
- ```ruby
42
- init :"bridgetown_directus" do
43
- api_url "https://your-directus-instance.com"
44
- token ENV['DIRECTUS_AUTH_TOKEN'] || "your_token"
45
- collection config.directus["collection"]
46
- mappings config.directus["mappings"]
47
- end
48
- ```
49
-
50
- 4. Configure your bridgetown.config.yml:
51
-
52
- ```yaml
53
- directus:
54
- collection: "posts"
55
- mappings:
56
- title: "title" # Required field
57
- content: "body" # Required field
58
- slug: "slug" # Optional, will be auto-generated if not provided
59
- date: "date" # Optional, defaults to current date/time if not provided
60
- category: "category" # Optional
61
- excerpt: "excerpt" # Optional, defaults to content excerpt if not provided
62
- image: "image" # Optional, URL for the image associated with the post
63
- translations:
64
- enabled: false # Set to true for multilingual support
65
- fields: # Only required if translations are enabled
66
- - title
67
- - excerpt
68
- - body
69
- ```
40
+ 2. Run `bundle install` to install the gem.
41
+ 3. Create `config/initializers/bridgetown_directus.rb` (see below for configuration).
70
42
 
71
43
  ## Configuration
72
44
 
73
- ### Basic Configuration
74
-
75
- You can configure the plugin either through environment variables or direct configuration:
76
-
77
- 1. Using environment variables:
78
-
79
- ```bash
80
- export DIRECTUS_API_URL="https://your-directus-instance.com"
81
- export DIRECTUS_AUTH_TOKEN="your-token"
82
- ```
83
-
84
- 2. Or through bridgetown.config.yml as shown in the installation section.
85
-
86
- ### Translations Configuration
87
-
88
- To enable multilingual support:
89
-
90
- 1. In your bridgetown.config.yml, set translations.enabled to true:
91
-
92
- ```yaml
93
- directus:
94
- # ... other config ...
95
- translations:
96
- enabled: true
97
- fields:
98
- - title
99
- - excerpt
100
- - body
101
- ```
102
-
103
- 2. Ensure your Directus collection has translations enabled and configured for the specified fields.
104
-
105
- 3. The plugin will automatically:
106
-
107
- - Generate posts for each available language
108
- - Create appropriate URLs based on locale
109
- - Handle fallback content if translations are missing
110
-
111
- ## Usage
112
-
113
- 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.
45
+ ### Minimal Example
114
46
 
115
- ### Directus Setup
47
+ ```ruby
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"
116
52
 
117
- #### Basic Collection Setup
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])
61
+ end
62
+ end
63
+ ```
118
64
 
119
- Create a collection in your Directus instance with these fields:
65
+ For custom collections, create a layout file at `src/_layouts/[singular].erb` (e.g., `staff_member.erb`) to control the page rendering.
120
66
 
121
- - **title**: The title of the post (Text field)
122
- - **body**: The content of the post (Rich Text or Text field)
123
- - **slug**: Optional. A unique slug for the post (Text field)
124
- - **date**: Optional. The publish date (Datetime field)
125
- - **status**: Optional. The status of the post (Option field with values like "published", "draft", etc.)
126
- - **category**: Optional. The category for the post (Text field)
127
- - **excerpt**: Optional. A short excerpt (Text field)
128
- - **image**: Optional. An image associated with the post (File/Media field)
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
129
72
 
130
- Make sure the **status** field uses `"published"` for posts that you want to be visible on your site.
73
+ #### Example: Customizing a Field
131
74
 
132
- #### Image Permissions
75
+ ```ruby
76
+ c.field :slug, "slug" do |value|
77
+ value || "staff_member-#{SecureRandom.hex(4)}"
78
+ end
79
+ ```
133
80
 
134
- If your posts contain images, and you want to display them in your Bridgetown site, you'll need to ensure that the **directus_files** collection has the appropriate permissions for public access.
81
+ ### Translations
135
82
 
136
- 1. **Public Role Configuration:**
137
- - In Directus, navigate to **Settings** > **Roles & Permissions**.
138
- - Select the **Public** role (or create a custom role if needed).
139
- - Under the **Collections** tab, locate the **directus_files** collection.
140
- - Set the **read** permission to **enabled** so that the images can be accessed publicly.
83
+ To enable translations for specific fields, add this inside your collection block:
141
84
 
142
- 2. **Image Uploads and Management:**
143
- - When users upload images to posts, ensure that the images are associated with the **directus_files** collection.
144
- - 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).
85
+ ```ruby
86
+ c.enable_translations([:title, :content])
87
+ ```
145
88
 
146
- ### Fetching Posts
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.
147
91
 
148
- Posts are fetched from Directus during each build and treated as Bridgetown resources. These resources are available in your site just like regular posts, and you can access them through your templates or layouts.
92
+ ### File Generation & Cleanup
149
93
 
150
- By default, only posts with a status of "published" are fetched from Directus.
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.
151
96
 
152
- ## TODO List
97
+ ### Advanced Configuration
153
98
 
154
- Here are features that are planned for future versions of the plugin:
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
155
104
 
156
- - [ ] Support for Additional Content Types: Extend the plugin to handle other Directus collections and custom content types.
157
- - [ ] Custom Field Mapping via DSL: Implement a DSL for more advanced field mapping.
158
- - [ ] Asset Handling: Add functionality to download and manage images and other assets.
159
- - [ ] Caching & Incremental Builds: Implement caching to improve build performance when fetching content.
160
- - [ ] 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!
161
106
 
162
- ## Testing
107
+ ### Migrating from 0.1.x
163
108
 
164
- Testing isn't fully set up yet, but contributions and improvements are welcome.
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.
165
113
 
166
- ## Contributing
114
+ ---
167
115
 
168
- We welcome contributions! To contribute:
116
+ For more details and advanced usage, see the [plugin README](https://github.com/Munkun-Estudio/bridgetown_directus).
169
117
 
170
- 1. Fork the repository
171
- 2. Create a new branch (git checkout -b feature-branch)
172
- 3. Make your changes
173
- 4. Push to the branch (git push origin feature-branch)
174
- 5. Open a Pull Request
118
+ See [CHANGELOG.md](CHANGELOG.md) for upgrade notes and detailed changes.
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require "rake/testtask"
4
4
  Rake::TestTask.new(:test) do |t|
5
5
  t.libs << "test"
6
6
  t.libs << "lib"
7
- t.test_files = FileList["test/**/test_*.rb"]
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
8
  t.warning = false
9
9
  end
10
10
 
@@ -2,61 +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['DIRECTUS_AUTH_TOKEN'])")
6
- collection = ask("What's the name of the collection (Directus Model)? (Example: posts)")
7
-
8
- # Ask if translations should be enabled with a default of 'n'
9
- translations_enabled_input = ask("Do you want to enable translations? (y/n) default:", :yellow, default: "n")
10
- translations_enabled = translations_enabled_input.strip.downcase.start_with?("y")
11
-
12
- # Prepare the translations YAML block based on the user’s response
13
- translations_yaml = if translations_enabled
14
- translatable_fields_input = ask("List the translatable fields separated by commas (e.g., title, excerpt, content)")
15
- translatable_fields = translatable_fields_input.split(',').map(&:strip)
16
-
17
- " translations:\n enabled: true\n fields:\n#{translatable_fields.map { |field| " - #{field}" }.join("\n")}"
18
- else
19
- " translations:\n enabled: false"
20
- end
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)")
21
8
 
22
9
  # Add the bridgetown_directus gem
23
10
  add_gem "bridgetown_directus"
24
11
 
25
- # Add Directus configuration to config/initializers.rb
26
- add_initializer :bridgetown_directus do
12
+ # Add minimal Directus configuration to config/initializers.rb in the idiomatic Bridgetown plugin style
13
+ add_initializer :bridgetown_directus do |directus|
27
14
  <<~RUBY
28
- do
29
- api_url "#{api_url}"
30
- token "#{auth_token.present? ? auth_token : "<%= ENV['DIRECTUS_AUTH_TOKEN'] %>"}"
31
- collection config.directus["collection"]
32
- mappings config.directus["mappings"]
33
- end
34
- RUBY
35
- end
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}"
36
41
 
37
- # Append the configuration to bridgetown.config.yml
38
- append_to_file "bridgetown.config.yml" do
39
- <<~YAML
40
-
41
- directus:
42
- collection: "#{collection}"
43
- mappings:
44
- title: "title" # Required field
45
- content: "body" # Required field
46
- slug: "slug" # Optional, will be auto-generated if not provided
47
- date: "date" # Optional, defaults to the current date/time if not provided
48
- category: "category" # Optional
49
- excerpt: "excerpt" # Optional, defaults to content excerpt if not provided
50
- image: "image" # Optional, URL for the image associated with the post
51
- #{translations_yaml}
52
- YAML
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])
51
+ end
52
+ RUBY
53
53
  end
54
54
 
55
55
  say_status :success, "Bridgetown Directus plugin has been installed!", :green
56
- say_status :info, "Add your posts to Directus and they will be automatically imported when you build your site.", :yellow
57
- if translations_enabled
58
- say_status :info, "Translations are enabled. Make sure your Directus collection has translations configured.", :yellow
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!"
59
62
  end
60
- say_status :directus, "Check config/initializers.rb for your Directus setup and config.bridgetown.yml to adjust fields mappings if necessary."
61
- say_status :directus, "For usage help visit:"
62
- say_status :directus, "https://github.com/Munkun-Estudio/bridgetown_directus/blob/main/README.md"
63
+
64
+ say_status :directus, "For advanced usage and field customization, see the README: https://github.com/Munkun-Estudio/bridgetown_directus"
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.required_ruby_version = ">= 2.7.0"
26
26
 
27
- spec.add_dependency "bridgetown", ">= 1.2.0", "< 2.0"
27
+ spec.add_dependency "bridgetown", ">= 2.0.0.beta4", "< 3.0"
28
28
  spec.add_dependency "faraday", "~> 2.12"
29
29
 
30
30
  spec.add_development_dependency "bundler", "~> 2.0"
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "rubocop-bridgetown", "~> 0.3"
33
33
  spec.add_development_dependency "shoulda", "~> 3.0"
34
34
  spec.add_development_dependency "minitest", "~> 5.0"
35
- spec.add_development_dependency "minitest-profile", "~> 0.5"
35
+ spec.add_development_dependency "minitest-profile", "~> 0.0.2"
36
36
  spec.add_development_dependency "minitest-reporters", "~> 1.0"
37
37
  spec.add_development_dependency "webmock", "~> 3.0"
38
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,103 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
1
5
  module BridgetownDirectus
2
6
  class Builder < Bridgetown::Builder
3
7
  def build
8
+ config = site.config.bridgetown_directus
4
9
  return if site.ssr?
5
10
 
6
- Utils.log_directus "Connecting to Directus API..."
7
- posts_data = fetch_posts
11
+ config.collections.each_value do |collection_config|
12
+ next unless [:posts, :pages, :custom_collection].include?(collection_config.resource_type)
8
13
 
9
- Utils.log_directus "Fetched #{posts_data.size} posts from Directus."
10
-
11
- create_documents(posts_data)
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
12
22
  end
13
23
 
14
24
  private
15
25
 
16
- def fetch_posts
17
- api_client = BridgetownDirectus::APIClient.new(site)
18
- api_client.fetch_posts
19
- end
20
-
21
- def create_documents(posts_data)
22
- # Ensure posts_data contains a "data" key and it is an array
23
- if posts_data.is_a?(Hash) && posts_data.key?("data") && posts_data["data"].is_a?(Array)
24
- posts_array = posts_data["data"]
25
- elsif posts_data.is_a?(Array)
26
- posts_array = posts_data
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")
27
33
  else
28
- raise "Unexpected structure of posts_data: #{posts_data.inspect}"
34
+ File.join(site.source, "_#{collection_name}")
29
35
  end
30
-
31
- created_posts = 0
32
- posts_array.each do |post|
33
- if translations_enabled?
34
- created_posts += create_translated_posts(post)
35
- else
36
- created_posts += create_single_post(post)
37
- end
38
- end
39
-
40
- Utils.log_directus "Finished generating #{created_posts} posts."
41
36
  end
42
37
 
43
- def translations_enabled?
44
- site.config.dig("directus", "translations", "enabled") == true
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)
45
49
  end
46
50
 
47
- def create_single_post(post)
48
- slug = post["slug"] || Bridgetown::Utils.slugify(post["title"])
49
- api_url = site.config.dig("directus", "api_url")
51
+ def build_filename(collection_dir, slug)
52
+ File.join(collection_dir, "#{slug}.md")
53
+ end
50
54
 
51
- begin
52
- add_resource :posts, "#{slug}.md" do
53
- layout "post"
54
- title post["title"]
55
- content post["body"]
56
- date post["date"] || Time.now.iso8601
57
- category post["category"]
58
- excerpt post["excerpt"]
59
- image post["image"] ? "#{api_url}/assets/#{post['image']}" : nil
60
- end
61
- 1
62
- rescue => e
63
- Utils.log_directus "Error creating post #{slug}: #{e.message}"
64
- 0
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"])
65
59
  end
60
+ item["layout"] = layout if layout
61
+ item
66
62
  end
67
63
 
68
- def create_translated_posts(post)
69
- posts_created = 0
70
- translations = post["translations"] || []
64
+ def generate_front_matter(item)
65
+ yaml = item.to_yaml
66
+ yaml.sub(%r{^---\s*\n}, "") # Remove leading --- if present
67
+ end
71
68
 
72
- translations.each do |translation|
73
- lang_code = translation["languages_code"].split("-").first.downcase
74
- bridgetown_locale = lang_code.to_sym
75
-
76
- next unless site.config["available_locales"].include?(bridgetown_locale)
69
+ def write_markdown_file(filename, front_matter, content)
70
+ File.write(filename, "---\n#{front_matter}---\n\n#{content}")
71
+ end
77
72
 
78
- slug = translation["slug"] || Bridgetown::Utils.slugify(translation["title"])
79
- api_url = site.config.dig("directus", "api_url")
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
80
83
 
81
- begin
82
- add_resource :posts, "#{slug}.md" do
83
- layout "post"
84
- title translation["title"]
85
- content translation["body"]
86
- date post["date"] || Time.now.iso8601
87
- category post["category"]
88
- excerpt translation["excerpt"]
89
- image post["image"] ? "#{api_url}/assets/#{post['image']}" : nil
90
- locale bridgetown_locale
91
- translations translations
92
- end
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
93
100
 
94
- posts_created += 1
95
- rescue => e
96
- Utils.log_directus "Error creating post #{slug} for locale #{bridgetown_locale}: #{e.message}"
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)
97
112
  end
113
+ when Array
114
+ obj.map { |v| sanitize_keys(v) }
115
+ else
116
+ obj
98
117
  end
118
+ end
99
119
 
100
- posts_created
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
101
133
  end
102
134
  end
103
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.info("Directus") { message }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BridgetownDirectus
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -2,36 +2,38 @@
2
2
 
3
3
  require "bridgetown"
4
4
  require_relative "bridgetown_directus/utils"
5
- require_relative "bridgetown_directus/api_client"
5
+ require_relative "bridgetown_directus/client"
6
+ require_relative "bridgetown_directus/data_mapper"
7
+ require_relative "bridgetown_directus/configuration"
6
8
  require_relative "bridgetown_directus/builder"
7
9
 
8
10
  module BridgetownDirectus
9
11
  # Bridgetown initializer for the plugin
10
- Bridgetown.initializer :bridgetown_directus do |config, api_url:, token:, collection:, mappings:|
11
- config.bridgetown_directus ||= {}
12
- config.bridgetown_directus.api_url ||= api_url || ENV.fetch("DIRECTUS_API_URL")
13
- config.bridgetown_directus.token ||= token || ENV.fetch("DIRECTUS_API_TOKEN")
12
+ Bridgetown.initializer :bridgetown_directus do |config|
13
+ # Only assign config.bridgetown_directus if not already set
14
+ config.bridgetown_directus ||= Configuration.new
14
15
 
15
- # Access collection and mappings from the bridgetown.config.yml
16
- config.bridgetown_directus.collection ||= config.directus.collection
17
- config.bridgetown_directus.mappings ||= config.directus.mappings
18
- config.bridgetown_directus.translations ||= config.directus["translations"]
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"
19
19
 
20
20
  # Register the builder
21
21
  config.builder BridgetownDirectus::Builder
22
+ end
23
+
24
+ class Configuration
25
+ attr_accessor :api_url, :token
26
+ attr_reader :collections
22
27
 
23
- # Log translations status
24
- if config.bridgetown_directus.translations["enabled"]
25
- translatable_fields = config.bridgetown_directus.translations["fields"] || []
26
- Bridgetown.logger.info "Directus translations enabled for fields: #{translatable_fields.join(', ')}"
27
- else
28
- Bridgetown.logger.info "Directus translations are disabled"
28
+ def initialize
29
+ @collections = {}
29
30
  end
30
31
 
31
- # Validate Directus config before proceeding
32
- unless config.bridgetown_directus.api_url && config.bridgetown_directus.token
33
- Bridgetown.logger.error "Invalid Directus configuration detected. Please check your API URL and token."
34
- raise "Directus configuration invalid"
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
35
37
  end
36
38
  end
37
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.1.3
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: 2024-11-21 00:00:00.000000000 Z
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: 1.2.0
18
+ version: 2.0.0.beta4
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
- version: '2.0'
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: 1.2.0
28
+ version: 2.0.0.beta4
30
29
  - - "<"
31
30
  - !ruby/object:Gem::Version
32
- version: '2.0'
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: '0.5'
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: '0.5'
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,9 +169,13 @@ 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
@@ -185,7 +187,6 @@ metadata:
185
187
  bug_tracker_uri: https://github.com/munkun-estudio/bridgetown_directus/issues
186
188
  changelog_uri: https://github.com/munkun-estudio/bridgetown_directus/releases
187
189
  homepage_uri: https://github.com/munkun-estudio/bridgetown_directus
188
- post_install_message:
189
190
  rdoc_options: []
190
191
  require_paths:
191
192
  - lib
@@ -200,8 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
201
  - !ruby/object:Gem::Version
201
202
  version: '0'
202
203
  requirements: []
203
- rubygems_version: 3.5.18
204
- signing_key:
204
+ rubygems_version: 3.6.2
205
205
  specification_version: 4
206
206
  summary: Use Directus as headless CMS for Bridgetown
207
207
  test_files: []
@@ -1,57 +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
- req.params['fields'] = '*,translations.*'
20
- end
21
-
22
- if response.success?
23
- JSON.parse(response.body) # Return the parsed posts
24
- elsif response.status == 401
25
- raise RuntimeError, "Unauthorized access to Directus API"
26
- else
27
- raise "Error fetching posts: #{response.status} - #{response.body}"
28
- end
29
- rescue Faraday::TimeoutError
30
- raise Faraday::TimeoutError, "The request to fetch posts timed out"
31
- rescue JSON::ParserError
32
- raise JSON::ParserError, "The response from Directus was not valid JSON"
33
- end
34
-
35
- # Setup Faraday connection with authorization headers
36
- def connection
37
- Faraday.new(url: @api_url) do |faraday|
38
- faraday.options.timeout = 5
39
- faraday.options.open_timeout = 2
40
- faraday.headers['Authorization'] = "Bearer #{@api_token}"
41
- faraday.headers['Content-Type'] = 'application/json'
42
- faraday.adapter Faraday.default_adapter
43
- end
44
- end
45
-
46
- # New method for validating the data structure
47
- private def validate_posts_data(posts_data)
48
- if posts_data.is_a?(Hash) && posts_data.key?("data") && posts_data["data"].is_a?(Array)
49
- posts_data["data"]
50
- elsif posts_data.is_a?(Array)
51
- posts_data
52
- else
53
- raise "Invalid posts data structure: #{posts_data.inspect}"
54
- end
55
- end
56
- end
57
- end