agave-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|