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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +14 -0
  4. data/CODE_OF_CONDUCT.md +49 -0
  5. data/CONTRIBUTORS.md +34 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +29 -0
  8. data/README.md +41 -0
  9. data/Rakefile +7 -0
  10. data/agave-client.gemspec +63 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/exe/agave +10 -0
  14. data/lib/agave.rb +11 -0
  15. data/lib/agave/api_client.rb +97 -0
  16. data/lib/agave/api_error.rb +23 -0
  17. data/lib/agave/cli.rb +93 -0
  18. data/lib/agave/dump/dsl/add_to_data_file.rb +14 -0
  19. data/lib/agave/dump/dsl/create_data_file.rb +14 -0
  20. data/lib/agave/dump/dsl/create_post.rb +33 -0
  21. data/lib/agave/dump/dsl/directory.rb +30 -0
  22. data/lib/agave/dump/dsl/root.rb +37 -0
  23. data/lib/agave/dump/format.rb +28 -0
  24. data/lib/agave/dump/format/json.rb +18 -0
  25. data/lib/agave/dump/format/toml.rb +31 -0
  26. data/lib/agave/dump/format/yaml.rb +55 -0
  27. data/lib/agave/dump/operation/add_to_data_file.rb +41 -0
  28. data/lib/agave/dump/operation/create_data_file.rb +28 -0
  29. data/lib/agave/dump/operation/create_post.rb +34 -0
  30. data/lib/agave/dump/operation/directory.rb +34 -0
  31. data/lib/agave/dump/operation/root.rb +27 -0
  32. data/lib/agave/dump/runner.rb +47 -0
  33. data/lib/agave/dump/ssg_detector.rb +36 -0
  34. data/lib/agave/json_api_deserializer.rb +38 -0
  35. data/lib/agave/json_api_serializer.rb +145 -0
  36. data/lib/agave/local/entities_repo.rb +46 -0
  37. data/lib/agave/local/field_type/boolean.rb +12 -0
  38. data/lib/agave/local/field_type/color.rb +63 -0
  39. data/lib/agave/local/field_type/date.rb +12 -0
  40. data/lib/agave/local/field_type/date_time.rb +12 -0
  41. data/lib/agave/local/field_type/file.rb +65 -0
  42. data/lib/agave/local/field_type/float.rb +12 -0
  43. data/lib/agave/local/field_type/gallery.rb +23 -0
  44. data/lib/agave/local/field_type/global_seo.rb +56 -0
  45. data/lib/agave/local/field_type/image.rb +82 -0
  46. data/lib/agave/local/field_type/integer.rb +12 -0
  47. data/lib/agave/local/field_type/json.rb +13 -0
  48. data/lib/agave/local/field_type/lat_lon.rb +30 -0
  49. data/lib/agave/local/field_type/link.rb +12 -0
  50. data/lib/agave/local/field_type/links.rb +21 -0
  51. data/lib/agave/local/field_type/rich_text.rb +21 -0
  52. data/lib/agave/local/field_type/seo.rb +33 -0
  53. data/lib/agave/local/field_type/slug.rb +12 -0
  54. data/lib/agave/local/field_type/string.rb +12 -0
  55. data/lib/agave/local/field_type/text.rb +12 -0
  56. data/lib/agave/local/field_type/theme.rb +43 -0
  57. data/lib/agave/local/field_type/video.rb +77 -0
  58. data/lib/agave/local/item.rb +179 -0
  59. data/lib/agave/local/items_repo.rb +210 -0
  60. data/lib/agave/local/json_api_entity.rb +78 -0
  61. data/lib/agave/local/loader.rb +60 -0
  62. data/lib/agave/local/site.rb +73 -0
  63. data/lib/agave/paginator.rb +33 -0
  64. data/lib/agave/repo.rb +93 -0
  65. data/lib/agave/site/client.rb +24 -0
  66. data/lib/agave/upload/file.rb +92 -0
  67. data/lib/agave/upload/image.rb +8 -0
  68. data/lib/agave/utils/favicon_tags_builder.rb +85 -0
  69. data/lib/agave/utils/locale_value.rb +15 -0
  70. data/lib/agave/utils/meta_tags/article_modified_time.rb +15 -0
  71. data/lib/agave/utils/meta_tags/article_publisher.rb +18 -0
  72. data/lib/agave/utils/meta_tags/base.rb +55 -0
  73. data/lib/agave/utils/meta_tags/description.rb +24 -0
  74. data/lib/agave/utils/meta_tags/image.rb +35 -0
  75. data/lib/agave/utils/meta_tags/og_locale.rb +15 -0
  76. data/lib/agave/utils/meta_tags/og_site_name.rb +18 -0
  77. data/lib/agave/utils/meta_tags/og_type.rb +18 -0
  78. data/lib/agave/utils/meta_tags/robots.rb +14 -0
  79. data/lib/agave/utils/meta_tags/title.rb +46 -0
  80. data/lib/agave/utils/meta_tags/twitter_card.rb +14 -0
  81. data/lib/agave/utils/meta_tags/twitter_site.rb +18 -0
  82. data/lib/agave/utils/seo_tags_builder.rb +45 -0
  83. data/lib/agave/version.rb +4 -0
  84. data/lib/agave/watch/site_change_watcher.rb +37 -0
  85. metadata +504 -0
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'agave/upload/file'
3
+
4
+ module Agave
5
+ module Upload
6
+ Image = Agave::Upload::File
7
+ end
8
+ end
@@ -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,14 @@
1
+ # frozen_string_literal: true
2
+ require 'agave/utils/meta_tags/base'
3
+
4
+ module Agave
5
+ module Utils
6
+ module MetaTags
7
+ class Robots < Base
8
+ def build
9
+ meta_tag('robots', 'noindex') if site.no_index
10
+ end
11
+ end
12
+ end
13
+ end
14
+ 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,14 @@
1
+ # frozen_string_literal: true
2
+ require 'agave/utils/meta_tags/base'
3
+
4
+ module Agave
5
+ module Utils
6
+ module MetaTags
7
+ class TwitterCard < Base
8
+ def build
9
+ card_tag('twitter:card', 'summary')
10
+ end
11
+ end
12
+ end
13
+ end
14
+ 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