agave-client 0.1.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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +14 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/CONTRIBUTORS.md +34 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +29 -0
- data/README.md +41 -0
- data/Rakefile +7 -0
- data/agave-client.gemspec +63 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/agave +10 -0
- data/lib/agave.rb +11 -0
- data/lib/agave/api_client.rb +97 -0
- data/lib/agave/api_error.rb +23 -0
- data/lib/agave/cli.rb +93 -0
- data/lib/agave/dump/dsl/add_to_data_file.rb +14 -0
- data/lib/agave/dump/dsl/create_data_file.rb +14 -0
- data/lib/agave/dump/dsl/create_post.rb +33 -0
- data/lib/agave/dump/dsl/directory.rb +30 -0
- data/lib/agave/dump/dsl/root.rb +37 -0
- data/lib/agave/dump/format.rb +28 -0
- data/lib/agave/dump/format/json.rb +18 -0
- data/lib/agave/dump/format/toml.rb +31 -0
- data/lib/agave/dump/format/yaml.rb +55 -0
- data/lib/agave/dump/operation/add_to_data_file.rb +41 -0
- data/lib/agave/dump/operation/create_data_file.rb +28 -0
- data/lib/agave/dump/operation/create_post.rb +34 -0
- data/lib/agave/dump/operation/directory.rb +34 -0
- data/lib/agave/dump/operation/root.rb +27 -0
- data/lib/agave/dump/runner.rb +47 -0
- data/lib/agave/dump/ssg_detector.rb +36 -0
- data/lib/agave/json_api_deserializer.rb +38 -0
- data/lib/agave/json_api_serializer.rb +145 -0
- data/lib/agave/local/entities_repo.rb +46 -0
- data/lib/agave/local/field_type/boolean.rb +12 -0
- data/lib/agave/local/field_type/color.rb +63 -0
- data/lib/agave/local/field_type/date.rb +12 -0
- data/lib/agave/local/field_type/date_time.rb +12 -0
- data/lib/agave/local/field_type/file.rb +65 -0
- data/lib/agave/local/field_type/float.rb +12 -0
- data/lib/agave/local/field_type/gallery.rb +23 -0
- data/lib/agave/local/field_type/global_seo.rb +56 -0
- data/lib/agave/local/field_type/image.rb +82 -0
- data/lib/agave/local/field_type/integer.rb +12 -0
- data/lib/agave/local/field_type/json.rb +13 -0
- data/lib/agave/local/field_type/lat_lon.rb +30 -0
- data/lib/agave/local/field_type/link.rb +12 -0
- data/lib/agave/local/field_type/links.rb +21 -0
- data/lib/agave/local/field_type/rich_text.rb +21 -0
- data/lib/agave/local/field_type/seo.rb +33 -0
- data/lib/agave/local/field_type/slug.rb +12 -0
- data/lib/agave/local/field_type/string.rb +12 -0
- data/lib/agave/local/field_type/text.rb +12 -0
- data/lib/agave/local/field_type/theme.rb +43 -0
- data/lib/agave/local/field_type/video.rb +77 -0
- data/lib/agave/local/item.rb +179 -0
- data/lib/agave/local/items_repo.rb +210 -0
- data/lib/agave/local/json_api_entity.rb +78 -0
- data/lib/agave/local/loader.rb +60 -0
- data/lib/agave/local/site.rb +73 -0
- data/lib/agave/paginator.rb +33 -0
- data/lib/agave/repo.rb +93 -0
- data/lib/agave/site/client.rb +24 -0
- data/lib/agave/upload/file.rb +92 -0
- data/lib/agave/upload/image.rb +8 -0
- data/lib/agave/utils/favicon_tags_builder.rb +85 -0
- data/lib/agave/utils/locale_value.rb +15 -0
- data/lib/agave/utils/meta_tags/article_modified_time.rb +15 -0
- data/lib/agave/utils/meta_tags/article_publisher.rb +18 -0
- data/lib/agave/utils/meta_tags/base.rb +55 -0
- data/lib/agave/utils/meta_tags/description.rb +24 -0
- data/lib/agave/utils/meta_tags/image.rb +35 -0
- data/lib/agave/utils/meta_tags/og_locale.rb +15 -0
- data/lib/agave/utils/meta_tags/og_site_name.rb +18 -0
- data/lib/agave/utils/meta_tags/og_type.rb +18 -0
- data/lib/agave/utils/meta_tags/robots.rb +14 -0
- data/lib/agave/utils/meta_tags/title.rb +46 -0
- data/lib/agave/utils/meta_tags/twitter_card.rb +14 -0
- data/lib/agave/utils/meta_tags/twitter_site.rb +18 -0
- data/lib/agave/utils/seo_tags_builder.rb +45 -0
- data/lib/agave/version.rb +4 -0
- data/lib/agave/watch/site_change_watcher.rb +37 -0
- metadata +504 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Agave
|
3
|
+
module Utils
|
4
|
+
class FaviconTagsBuilder
|
5
|
+
attr_reader :theme_color, :site
|
6
|
+
|
7
|
+
APPLE_TOUCH_ICON_SIZES = [57, 60, 72, 76, 114, 120, 144, 152, 180].freeze
|
8
|
+
ICON_SIZES = [16, 32, 96, 192].freeze
|
9
|
+
WINDOWS_SIZES = [[70, 70], [150, 150], [310, 310], [310, 150]].freeze
|
10
|
+
|
11
|
+
def initialize(site, theme_color)
|
12
|
+
@site = site
|
13
|
+
@theme_color = theme_color
|
14
|
+
end
|
15
|
+
|
16
|
+
def meta_tags
|
17
|
+
[
|
18
|
+
build_icon_tags,
|
19
|
+
build_apple_icon_tags,
|
20
|
+
build_windows_tags,
|
21
|
+
build_color_tags,
|
22
|
+
build_app_name_tag
|
23
|
+
].flatten.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_apple_icon_tags
|
27
|
+
return unless site.favicon
|
28
|
+
|
29
|
+
APPLE_TOUCH_ICON_SIZES.map do |size|
|
30
|
+
link_tag(
|
31
|
+
'apple-touch-icon',
|
32
|
+
url(size),
|
33
|
+
sizes: "#{size}x#{size}"
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_icon_tags
|
39
|
+
return unless site.favicon
|
40
|
+
|
41
|
+
ICON_SIZES.map do |size|
|
42
|
+
link_tag(
|
43
|
+
'icon',
|
44
|
+
url(size),
|
45
|
+
sizes: "#{size}x#{size}",
|
46
|
+
type: "image/#{site.favicon.format}"
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_windows_tags
|
52
|
+
return unless site.favicon
|
53
|
+
|
54
|
+
WINDOWS_SIZES.map do |(w, h)|
|
55
|
+
meta_tag("msapplication-square#{w}x#{h}logo", url(w, h))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_app_name_tag
|
60
|
+
meta_tag('application-name', site.name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_color_tags
|
64
|
+
return unless theme_color
|
65
|
+
|
66
|
+
[
|
67
|
+
meta_tag('theme-color', theme_color),
|
68
|
+
meta_tag('msapplication-TileColor', theme_color)
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
def url(width, height = width)
|
73
|
+
site.favicon.url(w: width, h: height)
|
74
|
+
end
|
75
|
+
|
76
|
+
def meta_tag(name, value)
|
77
|
+
{ tag_name: 'meta', attributes: { name: name, content: value } }
|
78
|
+
end
|
79
|
+
|
80
|
+
def link_tag(rel, href, attrs = {})
|
81
|
+
{ tag_name: 'link', attributes: attrs.merge(rel: rel, href: href) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'i18n/backend/fallbacks'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module LocaleValue
|
7
|
+
def self.find(obj)
|
8
|
+
locale_with_value = I18n.fallbacks[I18n.locale]
|
9
|
+
.find { |locale| obj[locale] }
|
10
|
+
|
11
|
+
obj[locale_with_value || I18n.locale]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Agave
|
6
|
+
module Utils
|
7
|
+
module MetaTags
|
8
|
+
class ArticleModifiedTime < Base
|
9
|
+
def build
|
10
|
+
og_tag('article:modified_time', item.updated_at.iso8601) if item
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class ArticlePublisher < Base
|
8
|
+
def build
|
9
|
+
og_tag('article:publisher', facebook_page_url) if facebook_page_url
|
10
|
+
end
|
11
|
+
|
12
|
+
def facebook_page_url
|
13
|
+
site.global_seo && site.global_seo.facebook_page_url
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'forwardable'
|
3
|
+
require 'agave/local/field_type/seo'
|
4
|
+
require 'active_support/core_ext/object/blank'
|
5
|
+
|
6
|
+
module Agave
|
7
|
+
module Utils
|
8
|
+
module MetaTags
|
9
|
+
class Base
|
10
|
+
attr_reader :site, :item
|
11
|
+
|
12
|
+
def initialize(item, site)
|
13
|
+
@item = item
|
14
|
+
@site = site
|
15
|
+
end
|
16
|
+
|
17
|
+
def seo_field_with_fallback(attribute, alternative)
|
18
|
+
fallback_seo = site.global_seo && site.global_seo.fallback_seo
|
19
|
+
|
20
|
+
seo_field = item &&
|
21
|
+
item.fields.detect { |f| f.field_type == 'seo' }
|
22
|
+
|
23
|
+
item_seo_value = seo_field &&
|
24
|
+
item.send(seo_field.api_key) &&
|
25
|
+
item.send(seo_field.api_key).send(attribute)
|
26
|
+
|
27
|
+
fallback_seo_value = fallback_seo &&
|
28
|
+
fallback_seo.send(attribute)
|
29
|
+
|
30
|
+
item_seo_value || alternative || fallback_seo_value
|
31
|
+
end
|
32
|
+
|
33
|
+
def tag(tag_name, attributes)
|
34
|
+
{ tag_name: tag_name, attributes: attributes }
|
35
|
+
end
|
36
|
+
|
37
|
+
def meta_tag(name, content)
|
38
|
+
tag('meta', name: name, content: content)
|
39
|
+
end
|
40
|
+
|
41
|
+
def og_tag(property, content)
|
42
|
+
tag('meta', property: property, content: content)
|
43
|
+
end
|
44
|
+
|
45
|
+
def card_tag(name, content)
|
46
|
+
meta_tag(name, content)
|
47
|
+
end
|
48
|
+
|
49
|
+
def content_tag(tag_name, content)
|
50
|
+
{ tag_name: tag_name, content: content }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class Description < Base
|
8
|
+
def build
|
9
|
+
return unless description.present?
|
10
|
+
|
11
|
+
[
|
12
|
+
meta_tag('description', description),
|
13
|
+
og_tag('og:description', description),
|
14
|
+
card_tag('twitter:description', description)
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def description
|
19
|
+
@description ||= seo_field_with_fallback(:description, nil)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class Image < Base
|
8
|
+
def build
|
9
|
+
return unless image
|
10
|
+
|
11
|
+
[
|
12
|
+
og_tag('og:image', image.url),
|
13
|
+
card_tag('twitter:image', image.url)
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
def image
|
18
|
+
@image ||= seo_field_with_fallback(:image, item_image)
|
19
|
+
end
|
20
|
+
|
21
|
+
def item_image
|
22
|
+
item && item.fields
|
23
|
+
.select { |field| field.field_type == 'image' }
|
24
|
+
.map { |field| item.send(field.api_key) }
|
25
|
+
.compact
|
26
|
+
.find do |image|
|
27
|
+
|
28
|
+
image.width && image.height &&
|
29
|
+
image.width >= 200 && image.height >= 200
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class OgLocale < Base
|
8
|
+
def build
|
9
|
+
locale = I18n.locale
|
10
|
+
og_tag('og:locale', "#{locale}_#{locale.upcase}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class OgSiteName < Base
|
8
|
+
def build
|
9
|
+
og_tag('og:site_name', site_name) if site_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def site_name
|
13
|
+
site.global_seo && site.global_seo.site_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class OgType < Base
|
8
|
+
def build
|
9
|
+
if !item || item.singleton?
|
10
|
+
og_tag('og:type', 'website')
|
11
|
+
else
|
12
|
+
og_tag('og:type', 'article')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class Title < Base
|
8
|
+
def build
|
9
|
+
return unless item_title
|
10
|
+
|
11
|
+
[
|
12
|
+
content_tag('title', item_title_with_suffix),
|
13
|
+
og_tag('og:title', item_title),
|
14
|
+
card_tag('twitter:title', item_title)
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def title_field
|
19
|
+
item && item.fields.find do |field|
|
20
|
+
field.field_type == 'string' &&
|
21
|
+
field.appeareance[:type] == 'title'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def item_title
|
26
|
+
@item_title ||= seo_field_with_fallback(
|
27
|
+
:title,
|
28
|
+
title_field && item.send(title_field.api_key)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def suffix
|
33
|
+
(site.global_seo && site.global_seo.title_suffix) || ''
|
34
|
+
end
|
35
|
+
|
36
|
+
def item_title_with_suffix
|
37
|
+
if (item_title + suffix).size <= 60
|
38
|
+
item_title + suffix
|
39
|
+
else
|
40
|
+
item_title
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/base'
|
3
|
+
|
4
|
+
module Agave
|
5
|
+
module Utils
|
6
|
+
module MetaTags
|
7
|
+
class TwitterSite < Base
|
8
|
+
def build
|
9
|
+
card_tag('twitter:site', twitter_account) if twitter_account
|
10
|
+
end
|
11
|
+
|
12
|
+
def twitter_account
|
13
|
+
site.global_seo && site.global_seo.twitter_account
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'agave/utils/meta_tags/title'
|
3
|
+
require 'agave/utils/meta_tags/description'
|
4
|
+
require 'agave/utils/meta_tags/image'
|
5
|
+
require 'agave/utils/meta_tags/robots'
|
6
|
+
require 'agave/utils/meta_tags/og_locale'
|
7
|
+
require 'agave/utils/meta_tags/og_type'
|
8
|
+
require 'agave/utils/meta_tags/og_site_name'
|
9
|
+
require 'agave/utils/meta_tags/article_modified_time'
|
10
|
+
require 'agave/utils/meta_tags/article_publisher'
|
11
|
+
require 'agave/utils/meta_tags/twitter_card'
|
12
|
+
require 'agave/utils/meta_tags/twitter_site'
|
13
|
+
|
14
|
+
module Agave
|
15
|
+
module Utils
|
16
|
+
class SeoTagsBuilder
|
17
|
+
META_TAGS = [
|
18
|
+
MetaTags::Title,
|
19
|
+
MetaTags::Description,
|
20
|
+
MetaTags::Image,
|
21
|
+
MetaTags::Robots,
|
22
|
+
MetaTags::OgLocale,
|
23
|
+
MetaTags::OgType,
|
24
|
+
MetaTags::OgSiteName,
|
25
|
+
MetaTags::ArticleModifiedTime,
|
26
|
+
MetaTags::ArticlePublisher,
|
27
|
+
MetaTags::TwitterCard,
|
28
|
+
MetaTags::TwitterSite
|
29
|
+
].freeze
|
30
|
+
|
31
|
+
attr_reader :site, :item
|
32
|
+
|
33
|
+
def initialize(item, site)
|
34
|
+
@item = item
|
35
|
+
@site = site
|
36
|
+
end
|
37
|
+
|
38
|
+
def meta_tags
|
39
|
+
META_TAGS.map do |klass|
|
40
|
+
klass.new(item, site).build
|
41
|
+
end.flatten.compact
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|