dato 0.1.31 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|