dato 0.1.31 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -1
- data/.ruby-version +1 -1
- data/docs/dato-cli.md +4 -7
- data/exe/dato +1 -1
- data/lib/dato.rb +1 -1
- data/lib/dato/api_error.rb +5 -1
- data/lib/dato/cli.rb +42 -0
- data/lib/dato/dump/format/toml.rb +4 -4
- data/lib/dato/dump/runner.rb +1 -1
- data/lib/dato/dump/ssg_detector.rb +2 -2
- data/lib/dato/local/field_type/file.rb +3 -4
- data/lib/dato/local/field_type/slug.rb +12 -0
- data/lib/dato/local/item.rb +31 -23
- data/lib/dato/local/loader.rb +3 -1
- data/lib/dato/migrate_slugs/runner.rb +155 -0
- data/lib/dato/version.rb +1 -1
- metadata +6 -5
- data/dato.config.rb +0 -1
- data/lib/dato/dump/cli.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b54b098b276ed1157ddb3a025a7ed159f4de08ce
|
4
|
+
data.tar.gz: 51dabe629a57a274820cf257173b06cf0e3f48fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c175e119234ebb14bdbd534b68a76300cffd7fa893255d95afe2f785020c925b8afce747c94141da9984fafddfbc0cd054fc221fc4f3568847709fc32c65b237
|
7
|
+
data.tar.gz: 63acf4d92d062a34301091d45402a254b08eadd1eee5ed4b6b91aaa852ec72dcab93edabdd28f3528a67736a1e90219f8616e3aeb76ae15fb3691002724657da
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.2.2
|
data/docs/dato-cli.md
CHANGED
@@ -103,12 +103,14 @@ Our job is to generate the Markdown files in the `content` directory from the da
|
|
103
103
|
Using the DatoCMS web interface, we first create the following Item types:
|
104
104
|
|
105
105
|
* post
|
106
|
-
- title (string, required
|
106
|
+
- title (string, required)
|
107
|
+
- slug (slug, required)
|
107
108
|
- publication_date (date, required)
|
108
109
|
- body (text, required)
|
109
110
|
|
110
111
|
* author
|
111
112
|
- name (string, required, title)
|
113
|
+
- slug (slug, required)
|
112
114
|
- bio (text, required)
|
113
115
|
|
114
116
|
* quote
|
@@ -217,7 +219,7 @@ end
|
|
217
219
|
|
218
220
|
directory "data/authors" do
|
219
221
|
dato.authors.each do |item|
|
220
|
-
create_data_file "#{item.
|
222
|
+
create_data_file "#{item.slug}.toml", :toml, {
|
221
223
|
name: item.name,
|
222
224
|
bio: item.bio
|
223
225
|
}
|
@@ -233,11 +235,6 @@ If a Item Type is marked as "single instance" (ie. `about_page`) you don't need
|
|
233
235
|
|
234
236
|
You can query an item's field value with a method called like the field API identifier.
|
235
237
|
|
236
|
-
An item also features a `.slug` method:
|
237
|
-
|
238
|
-
* if an item type has a field of type `string` with a "Title" Presentation mode, than the method returns the slugified version of the title itself;
|
239
|
-
* otherwise, it just returns the unique identifier of the item;
|
240
|
-
|
241
238
|
Complex field types (ie. `image`, `file`, `video`, `seo`) implement specific methods you can use as well within the config file:
|
242
239
|
|
243
240
|
```
|
data/exe/dato
CHANGED
data/lib/dato.rb
CHANGED
data/lib/dato/api_error.rb
CHANGED
@@ -12,8 +12,12 @@ module Dato
|
|
12
12
|
'DatoCMS API Error',
|
13
13
|
"Status: #{faraday_error.response[:status]}",
|
14
14
|
'Response:',
|
15
|
-
JSON.pretty_generate(
|
15
|
+
JSON.pretty_generate(body)
|
16
16
|
].join("\n")
|
17
17
|
end
|
18
|
+
|
19
|
+
def body
|
20
|
+
JSON.parse(faraday_error.response[:body])
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
data/lib/dato/cli.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'thor'
|
3
|
+
require 'dato/dump/runner'
|
4
|
+
require 'dato/dump/ssg_detector'
|
5
|
+
require 'dato/migrate_slugs/runner'
|
6
|
+
|
7
|
+
module Dato
|
8
|
+
class Cli < Thor
|
9
|
+
package_name 'DatoCMS'
|
10
|
+
|
11
|
+
desc 'dump', 'dumps DatoCMS contents into local files'
|
12
|
+
option :config, default: 'dato.config.rb'
|
13
|
+
option :token, default: ENV['DATO_API_TOKEN'], required: true
|
14
|
+
def dump
|
15
|
+
config_file = File.expand_path(options[:config])
|
16
|
+
|
17
|
+
client = Dato::Site::Client.new(
|
18
|
+
options[:token],
|
19
|
+
extra_headers: {
|
20
|
+
'X-Reason' => 'dump',
|
21
|
+
'X-SSG' => Dump::SsgDetector.new(Dir.pwd).detect
|
22
|
+
}
|
23
|
+
)
|
24
|
+
|
25
|
+
Dump::Runner.new(config_file, client).run
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'migrate-slugs', 'migrates a Site so that it uses slug fields'
|
29
|
+
option :token, default: ENV['DATO_API_TOKEN'], required: true
|
30
|
+
option :skip_id_prefix, type: :boolean
|
31
|
+
def migrate_slugs
|
32
|
+
client = Dato::Site::Client.new(
|
33
|
+
options[:token],
|
34
|
+
extra_headers: {
|
35
|
+
'X-Reason' => 'migrate-slugs'
|
36
|
+
}
|
37
|
+
)
|
38
|
+
|
39
|
+
MigrateSlugs::Runner.new(client, options[:skip_id_prefix]).run
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -3,14 +3,14 @@ require 'active_support/core_ext/hash/keys'
|
|
3
3
|
require 'toml'
|
4
4
|
|
5
5
|
class Time
|
6
|
-
def to_toml(
|
7
|
-
utc.strftime(
|
6
|
+
def to_toml(_path = '')
|
7
|
+
utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
class Date
|
12
|
-
def to_toml(
|
13
|
-
strftime(
|
12
|
+
def to_toml(_path = '')
|
13
|
+
strftime('%Y-%m-%d')
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
data/lib/dato/dump/runner.rb
CHANGED
@@ -26,7 +26,7 @@ module Dato
|
|
26
26
|
},
|
27
27
|
{
|
28
28
|
file: 'config.json',
|
29
|
-
loader: ->(content) { JSON.
|
29
|
+
loader: ->(content) { JSON.parse(content) }
|
30
30
|
}
|
31
31
|
].freeze
|
32
32
|
|
@@ -59,7 +59,7 @@ module Dato
|
|
59
59
|
package_path = File.join(path, 'package.json')
|
60
60
|
return unless File.exist?(package_path)
|
61
61
|
|
62
|
-
package = JSON.
|
62
|
+
package = JSON.parse(File.read(package_path))
|
63
63
|
|
64
64
|
deps = package.fetch('dependencies', {})
|
65
65
|
dev_deps = package.fetch('devDependencies', {})
|
data/lib/dato/local/item.rb
CHANGED
@@ -24,14 +24,25 @@ module Dato
|
|
24
24
|
other.is_a?(Item) && other.id == id
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
|
27
|
+
def autogenerated_slug(options = {})
|
28
|
+
warning = [
|
29
|
+
'Warning: the method `Item#autogenerated_slug` is deprecated:',
|
30
|
+
'please add an explicit field of type `slug`',
|
31
|
+
"to the `#{item_type.api_key}` item type."
|
32
|
+
]
|
33
|
+
puts warning.join(' ')
|
34
|
+
|
35
|
+
prefix_with_id = options.fetch(:prefix_with_id, true)
|
36
|
+
|
37
|
+
title_field = fields.find do |field|
|
38
|
+
field.field_type == 'string' &&
|
39
|
+
field.appeareance[:type] == 'title'
|
40
|
+
end
|
29
41
|
|
30
|
-
return read_attribute(:slug, slug_field) if slug_field
|
31
42
|
return item_type.api_key.humanize.parameterize if singleton?
|
32
|
-
return id.to_s unless
|
43
|
+
return id.to_s unless title_field
|
33
44
|
|
34
|
-
title = send(
|
45
|
+
title = send(title_field.api_key)
|
35
46
|
if title && prefix_with_id
|
36
47
|
"#{id}-#{title.parameterize[0..50]}"
|
37
48
|
elsif title
|
@@ -41,14 +52,6 @@ module Dato
|
|
41
52
|
end
|
42
53
|
end
|
43
54
|
|
44
|
-
def title_field_api_key
|
45
|
-
title_field = fields.find do |field|
|
46
|
-
field.field_type == 'string' &&
|
47
|
-
field.appeareance[:type] == 'title'
|
48
|
-
end
|
49
|
-
title_field && title_field.api_key
|
50
|
-
end
|
51
|
-
|
52
55
|
def singleton?
|
53
56
|
item_type.singleton
|
54
57
|
end
|
@@ -88,8 +91,6 @@ module Dato
|
|
88
91
|
base = {
|
89
92
|
id: id,
|
90
93
|
item_type: item_type.api_key,
|
91
|
-
slug: slug(prefix_with_id: false),
|
92
|
-
slug_with_prefix: slug,
|
93
94
|
updated_at: updated_at
|
94
95
|
}
|
95
96
|
|
@@ -112,17 +113,24 @@ module Dato
|
|
112
113
|
field_type = field.field_type
|
113
114
|
type_klass_name = "::Dato::Local::FieldType::#{field_type.camelize}"
|
114
115
|
type_klass = type_klass_name.safe_constantize
|
116
|
+
value = if field.localized
|
117
|
+
(entity.send(method) || {})[I18n.locale]
|
118
|
+
else
|
119
|
+
entity.send(method)
|
120
|
+
end
|
115
121
|
|
116
122
|
if type_klass
|
117
|
-
value = if field.localized
|
118
|
-
(entity.send(method) || {})[I18n.locale]
|
119
|
-
else
|
120
|
-
entity.send(method)
|
121
|
-
end
|
122
|
-
|
123
123
|
value && type_klass.parse(value, @items_repo)
|
124
124
|
else
|
125
|
-
|
125
|
+
warning = [
|
126
|
+
"Warning: unrecognized field of type `#{field_type}`",
|
127
|
+
"for item `#{item_type.api_key}` and",
|
128
|
+
"field `#{method}`: returning a simple Hash instead.",
|
129
|
+
'Please upgrade to the latest version of the `dato` gem!'
|
130
|
+
]
|
131
|
+
puts warning.join(' ')
|
132
|
+
|
133
|
+
value
|
126
134
|
end
|
127
135
|
end
|
128
136
|
|
@@ -136,7 +144,7 @@ module Dato
|
|
136
144
|
rescue NoMethodError
|
137
145
|
message = []
|
138
146
|
message << "Undefined method `#{method}`"
|
139
|
-
message <<
|
147
|
+
message << "Available fields for a `#{item_type.api_key}` item:"
|
140
148
|
message += fields.map do |f|
|
141
149
|
"* .#{f.api_key}"
|
142
150
|
end
|
data/lib/dato/local/loader.rb
CHANGED
@@ -34,7 +34,9 @@ module Dato
|
|
34
34
|
items_per_page = 500
|
35
35
|
base_response = client.request(:get, '/items', 'page[limit]' => 500)
|
36
36
|
|
37
|
-
extra_pages = (
|
37
|
+
extra_pages = (
|
38
|
+
base_response[:meta][:total_count] / items_per_page.to_f
|
39
|
+
).ceil - 1
|
38
40
|
|
39
41
|
extra_pages.times do |page|
|
40
42
|
base_response[:data] += client.request(
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'dato/json_api_deserializer'
|
3
|
+
require 'active_support/inflector/transliterate'
|
4
|
+
|
5
|
+
module Dato
|
6
|
+
module MigrateSlugs
|
7
|
+
class Runner
|
8
|
+
attr_reader :client, :skip_id_prefix
|
9
|
+
|
10
|
+
def initialize(client, skip_id_prefix)
|
11
|
+
@client = client
|
12
|
+
@skip_id_prefix = skip_id_prefix
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
print 'Fetching site informations... '
|
17
|
+
title_fields
|
18
|
+
puts "\e[32m✓\e[0m"
|
19
|
+
|
20
|
+
title_fields.each do |title_field|
|
21
|
+
item_type = item_types.find do |i|
|
22
|
+
i['id'] == title_field['item_type']
|
23
|
+
end
|
24
|
+
|
25
|
+
print "Adding slug field to Item type `#{item_type['name']}`... "
|
26
|
+
add_slug_field(title_field)
|
27
|
+
puts "\e[32m✓\e[0m"
|
28
|
+
|
29
|
+
items = items_for(title_field['item_type'])
|
30
|
+
print "Generating slugs for #{items.count} items"
|
31
|
+
|
32
|
+
items.each do |item|
|
33
|
+
update_item(title_field, item)
|
34
|
+
print '.'
|
35
|
+
end
|
36
|
+
puts "\e[32m✓\e[0m"
|
37
|
+
|
38
|
+
puts
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def simple_slugify(item, title, suffix)
|
43
|
+
if title
|
44
|
+
slug = title.parameterize[0..50].gsub(/(^\-|\-$)/, '')
|
45
|
+
skip_id_prefix ? "#{slug}#{suffix}" : "#{item['id']}-#{slug}#{suffix}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def slugify(item, title, suffix)
|
50
|
+
if title.is_a?(Hash)
|
51
|
+
Hash[
|
52
|
+
title.map do |locale, value|
|
53
|
+
[locale, simple_slugify(item, value, suffix)]
|
54
|
+
end
|
55
|
+
]
|
56
|
+
else
|
57
|
+
simple_slugify(item, title, suffix)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_item(title_field, item)
|
62
|
+
title = item[title_field['api_key']]
|
63
|
+
counter = 0
|
64
|
+
|
65
|
+
loop do
|
66
|
+
begin
|
67
|
+
slug = slugify(item, title, counter.zero? ? '' : "-#{counter}")
|
68
|
+
return client.items.update(item['id'], item.merge(slug: slug))
|
69
|
+
rescue ApiError => e
|
70
|
+
error = e.body['data'][0]
|
71
|
+
|
72
|
+
if error['id'] == 'INVALID_FIELD' &&
|
73
|
+
error['attributes']['details']['field'] == 'slug' &&
|
74
|
+
error['attributes']['details']['code'] == 'VALIDATION_UNIQUE'
|
75
|
+
|
76
|
+
counter += 1
|
77
|
+
else
|
78
|
+
raise e
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def items_for(item_type_id)
|
85
|
+
items_per_page = 500
|
86
|
+
base_response = client.request(
|
87
|
+
:get,
|
88
|
+
'/items',
|
89
|
+
'page[limit]' => 500,
|
90
|
+
'filter[type]' => item_type_id
|
91
|
+
)
|
92
|
+
|
93
|
+
extra_pages = (
|
94
|
+
base_response[:meta][:total_count] / items_per_page.to_f
|
95
|
+
).ceil - 1
|
96
|
+
|
97
|
+
extra_pages.times do |page|
|
98
|
+
base_response[:data] += client.request(
|
99
|
+
:get,
|
100
|
+
'/items',
|
101
|
+
'page[offset]' => items_per_page * (page + 1),
|
102
|
+
'page[limit]' => items_per_page
|
103
|
+
)[:data]
|
104
|
+
end
|
105
|
+
|
106
|
+
JsonApiDeserializer.new.deserialize(base_response)
|
107
|
+
end
|
108
|
+
|
109
|
+
def add_slug_field(field)
|
110
|
+
validators = {
|
111
|
+
unique: {}
|
112
|
+
}
|
113
|
+
|
114
|
+
validators[:required] = {} if field['validators']['required']
|
115
|
+
|
116
|
+
slug_field = client.fields.create(
|
117
|
+
field['item_type'],
|
118
|
+
field_type: 'slug',
|
119
|
+
appeareance: { title_field_id: field['id'] },
|
120
|
+
validators: validators,
|
121
|
+
position: 99,
|
122
|
+
api_key: 'slug',
|
123
|
+
label: 'Slug',
|
124
|
+
hint: '',
|
125
|
+
localized: field['localized']
|
126
|
+
)
|
127
|
+
|
128
|
+
client.fields.update(
|
129
|
+
slug_field['id'],
|
130
|
+
position: field['position'] + 1
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
def title_fields
|
135
|
+
@title_fields ||= item_types.map do |item_type|
|
136
|
+
fields = client.fields.all(item_type['id'])
|
137
|
+
|
138
|
+
any_slug_present = fields.any? do |f|
|
139
|
+
f['field_type'] == 'slug' || f['api_key'] == 'slug'
|
140
|
+
end
|
141
|
+
|
142
|
+
next if any_slug_present
|
143
|
+
fields.find do |field|
|
144
|
+
field['field_type'] == 'string' &&
|
145
|
+
field['appeareance']['type'] == 'title'
|
146
|
+
end
|
147
|
+
end.compact
|
148
|
+
end
|
149
|
+
|
150
|
+
def item_types
|
151
|
+
@item_types ||= client.item_types.all
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/lib/dato/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefano Verna
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -338,7 +338,6 @@ files:
|
|
338
338
|
- Rakefile
|
339
339
|
- bin/console
|
340
340
|
- bin/setup
|
341
|
-
- dato.config.rb
|
342
341
|
- dato.gemspec
|
343
342
|
- docs/account-api-client.md
|
344
343
|
- docs/dato-cli.md
|
@@ -350,7 +349,7 @@ files:
|
|
350
349
|
- lib/dato/account/repo/base.rb
|
351
350
|
- lib/dato/account/repo/site.rb
|
352
351
|
- lib/dato/api_error.rb
|
353
|
-
- lib/dato/
|
352
|
+
- lib/dato/cli.rb
|
354
353
|
- lib/dato/dump/dsl/add_to_data_file.rb
|
355
354
|
- lib/dato/dump/dsl/create_data_file.rb
|
356
355
|
- lib/dato/dump/dsl/create_post.rb
|
@@ -381,6 +380,7 @@ files:
|
|
381
380
|
- lib/dato/local/field_type/link.rb
|
382
381
|
- lib/dato/local/field_type/links.rb
|
383
382
|
- lib/dato/local/field_type/seo.rb
|
383
|
+
- lib/dato/local/field_type/slug.rb
|
384
384
|
- lib/dato/local/field_type/string.rb
|
385
385
|
- lib/dato/local/field_type/text.rb
|
386
386
|
- lib/dato/local/field_type/video.rb
|
@@ -389,6 +389,7 @@ files:
|
|
389
389
|
- lib/dato/local/json_api_entity.rb
|
390
390
|
- lib/dato/local/loader.rb
|
391
391
|
- lib/dato/local/site.rb
|
392
|
+
- lib/dato/migrate_slugs/runner.rb
|
392
393
|
- lib/dato/site/client.rb
|
393
394
|
- lib/dato/site/repo/base.rb
|
394
395
|
- lib/dato/site/repo/field.rb
|
@@ -421,7 +422,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
421
422
|
version: '0'
|
422
423
|
requirements: []
|
423
424
|
rubyforge_project:
|
424
|
-
rubygems_version: 2.
|
425
|
+
rubygems_version: 2.4.5
|
425
426
|
signing_key:
|
426
427
|
specification_version: 4
|
427
428
|
summary: Ruby client for DatoCMS API
|
data/dato.config.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
puts dato.blog_posts.first.title
|
data/lib/dato/dump/cli.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'thor'
|
3
|
-
require 'dato/dump/runner'
|
4
|
-
|
5
|
-
module Dato
|
6
|
-
module Dump
|
7
|
-
class Cli < Thor
|
8
|
-
package_name 'DatoCMS'
|
9
|
-
|
10
|
-
desc 'dump', 'dumps DatoCMS contents into local files'
|
11
|
-
option :config, default: 'dato.config.rb'
|
12
|
-
option :token, default: ENV['DATO_API_TOKEN'], required: true
|
13
|
-
def dump
|
14
|
-
config_file = File.expand_path(options[:config])
|
15
|
-
|
16
|
-
client = Dato::Site::Client.new(
|
17
|
-
options[:token],
|
18
|
-
extra_headers: {
|
19
|
-
'X-Reason' => 'dump',
|
20
|
-
'X-SSG' => SsgDetector.new(Dir.pwd).detect
|
21
|
-
}
|
22
|
-
)
|
23
|
-
|
24
|
-
Runner.new(config_file, client).run
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|