apps 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/README.md +103 -19
- data/bin/setup +1 -2
- data/exe/apps +0 -0
- data/lib/apps/common/schema.rb +8 -0
- data/lib/apps/common/schema/base.rb +91 -0
- data/lib/apps/common/schema/concerns.rb +10 -0
- data/lib/apps/common/schema/concerns/potential_action.rb +35 -0
- data/lib/apps/gmail/markup.rb +158 -0
- data/lib/apps/gmail/schema.rb +21 -0
- data/lib/apps/gmail/schema/action.rb +19 -0
- data/lib/apps/gmail/schema/confirm_action.rb +21 -0
- data/lib/apps/gmail/schema/email_message.rb +15 -0
- data/lib/apps/gmail/schema/event.rb +41 -0
- data/lib/apps/gmail/schema/parcel_delivery.rb +43 -0
- data/lib/apps/gmail/schema/place.rb +24 -0
- data/lib/apps/gmail/schema/postal_address.rb +22 -0
- data/lib/apps/gmail/schema/rsvp_action.rb +25 -0
- data/lib/apps/gmail/schema/save_action.rb +20 -0
- data/lib/apps/gmail/schema/track_action.rb +20 -0
- data/lib/apps/gmail/schema/view_action.rb +20 -0
- data/lib/apps/outlook/actionable_messages.rb +13 -0
- data/lib/apps/outlook/schema.rb +20 -0
- data/lib/apps/outlook/schema/action.rb +14 -0
- data/lib/apps/outlook/schema/action_card.rb +42 -0
- data/lib/apps/outlook/schema/concerns.rb +14 -0
- data/lib/apps/outlook/schema/concerns/sections.rb +27 -0
- data/lib/apps/outlook/schema/concerns/sorted_potential_action.rb +17 -0
- data/lib/apps/outlook/schema/date_input.rb +17 -0
- data/lib/apps/outlook/schema/http_post.rb +44 -0
- data/lib/apps/outlook/schema/input.rb +23 -0
- data/lib/apps/outlook/schema/invoke_add_in_command.rb +33 -0
- data/lib/apps/outlook/schema/message_card.rb +39 -0
- data/lib/apps/outlook/schema/multichoice_input.rb +32 -0
- data/lib/apps/outlook/schema/open_uri.rb +24 -0
- data/lib/apps/outlook/schema/section.rb +52 -0
- data/lib/apps/outlook/schema/text_input.rb +20 -0
- data/lib/apps/version.rb +4 -1
- data/lib/examples.rb +121 -0
- data/package.json +12 -0
- metadata +37 -16
- data/lib/apps/adapters/gmail/markup.rb +0 -42
- data/lib/apps/adapters/gmail/markup/action.rb +0 -23
- data/lib/apps/adapters/gmail/markup/base.rb +0 -37
- data/lib/apps/adapters/gmail/markup/base_context.rb +0 -23
- data/lib/apps/adapters/gmail/markup/confirm_action.rb +0 -23
- data/lib/apps/adapters/gmail/markup/email_message.rb +0 -22
- data/lib/apps/adapters/gmail/markup/event.rb +0 -40
- data/lib/apps/adapters/gmail/markup/parcel_delivery.rb +0 -47
- data/lib/apps/adapters/gmail/markup/place.rb +0 -27
- data/lib/apps/adapters/gmail/markup/postal_address.rb +0 -26
- data/lib/apps/adapters/gmail/markup/rsvp_action.rb +0 -27
- data/lib/apps/adapters/gmail/markup/save_action.rb +0 -22
- data/lib/apps/adapters/gmail/markup/track_action.rb +0 -24
- data/lib/apps/adapters/gmail/markup/view_action.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76c0dd94631910ba52d822088647ffbe60838983b938472cb3d94d006e632720
|
4
|
+
data.tar.gz: 9001b062a90772948b2472bf08ca3ce4e1cdb58d74a590c08a67bed9e91d23b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '058630fac77f03e0e9feb6b8648ad1809b8ba8de5990ae9323be349c16aad07734c153626180237e81013c920bcb4cca8fa98afb760738c13ce7214d20294dbd'
|
7
|
+
data.tar.gz: e937dcfa758a607370a5548eff21772f77c21c7445542b3a81e8225da497f689d355e27ee1d7ebafcb9724dd1a0606813fb25164443dec39fd1a386b518e98a6
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -4,9 +4,9 @@ This is a toolkit to easily integrate into platform marketplaces and extension p
|
|
4
4
|
|
5
5
|
The Apps gem is currently under development, with the goal of facilitating the following:
|
6
6
|
|
7
|
-
*
|
8
|
-
* [
|
9
|
-
* [
|
7
|
+
* Gmail
|
8
|
+
* [Add-ons](https://developers.google.com/gmail/add-ons/)
|
9
|
+
* [Email Markup](https://developers.google.com/gmail/markup/)
|
10
10
|
* AMP Pages
|
11
11
|
* Microsoft Office 365
|
12
12
|
* [Outlook Add-ins](https://docs.microsoft.com/en-us/outlook/add-ins/)
|
@@ -14,8 +14,8 @@ The Apps gem is currently under development, with the goal of facilitating the f
|
|
14
14
|
* Slack
|
15
15
|
* Bots
|
16
16
|
* Commands
|
17
|
-
* Heroku
|
18
|
-
*
|
17
|
+
* Heroku Elements Marketplace
|
18
|
+
* [Add-ons](https://devcenter.heroku.com/articles/building-an-add-on)
|
19
19
|
* Facebook
|
20
20
|
* Instant Articles
|
21
21
|
|
@@ -39,20 +39,75 @@ Or install it yourself as:
|
|
39
39
|
|
40
40
|
### Gmail Email Markup
|
41
41
|
|
42
|
-
You can generate [schema.org](http://schema.org) markup for email in Gmail utilizing simple helper classes.
|
43
|
-
|
44
|
-
*
|
45
|
-
*
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
You can generate [schema.org](http://schema.org) markup for email in Gmail utilizing simple helper classes. Use the helper methods in `Apps::Gmail::Markup` to easily define your markup.
|
43
|
+
|
44
|
+
* [Confirm Action](https://developers.google.com/gmail/markup/reference/one-click-action)
|
45
|
+
* [Save Action](https://developers.google.com/gmail/markup/reference/one-click-action)
|
46
|
+
* [RSVP Action](https://developers.google.com/gmail/markup/reference/rsvp-action)
|
47
|
+
* [View Action](https://developers.google.com/gmail/markup/reference/go-to-action)
|
48
|
+
* [Track Action](https://developers.google.com/gmail/markup/reference/go-to-action)
|
49
|
+
|
50
|
+
Explore `Apps::Gmail::Markup` and related classes to see how you can customize your metadata.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
require 'apps/gmail/markup'
|
54
|
+
|
55
|
+
# Confirm Action (takes additional keyword options)
|
56
|
+
confirm_action = Apps::Gmail::Markup.confirm_action('Button Text', 'http://example.org/confirm/endpoint')
|
57
|
+
|
58
|
+
confirm_action.as_json
|
59
|
+
# => {"@context"=>"http://schema.org", "@type"=>"EmailMessage", "potentialAction"=>{"@type"=>"ConfirmAction", "handler"=>{"@type"=>"HttpActionHandler", "url"=>"http://example.org/confirm/endpoint"}}}
|
60
|
+
|
61
|
+
puts confirm_action.to_json
|
62
|
+
# => {"@context":"http://schema.org","@type":"EmailMessage","potentialAction":{"@type":"ConfirmAction","handler":{"@type":"HttpActionHandler","url":"http://example.org/confirm/endpoint"}}}
|
63
|
+
|
64
|
+
# NOTE: `to_script` is only available on "context" objects that represent the root of the markup
|
65
|
+
# needed for embedding in emails. This is the object returned by each of the helper methods
|
66
|
+
# above for each "Action"
|
67
|
+
puts confirm_action.to_script
|
68
|
+
# =>
|
69
|
+
# <script type="application/ld+json">
|
70
|
+
# {
|
71
|
+
# "@context": "http://schema.org",
|
72
|
+
# "@type": "EmailMessage",
|
73
|
+
# "potentialAction": {
|
74
|
+
# "@type": "ConfirmAction",
|
75
|
+
# "handler": {
|
76
|
+
# "@type": "HttpActionHandler",
|
77
|
+
# "url": "http://example.org/confirm/endpoint"
|
78
|
+
# }
|
79
|
+
# }
|
80
|
+
# }
|
81
|
+
# </script>
|
82
|
+
|
83
|
+
# Save Action (takes additional keyword options)
|
84
|
+
save_action = Apps::Gmail::Markup.save_action('Button Text', 'http://example.org/save/endpoint')
|
85
|
+
|
86
|
+
# RSVP Action (takes additional keyword options)
|
87
|
+
rsvp_action = Apps::Gmail::Markup.rsvp_action('Event Name',
|
88
|
+
yes_url: 'http://example.org/yes/endpoint',
|
89
|
+
no_url: 'http://example.org/no/endpoint',
|
90
|
+
maybe_url: 'http://example.org/maybe/endpoint'
|
91
|
+
)
|
92
|
+
|
93
|
+
# View Action (takes additional keyword options)
|
94
|
+
view_action = Apps::Gmail::Markup.view_action('Button Text', 'http://example.org/save/endpoint')
|
95
|
+
|
96
|
+
# Track Action (takes additional keyword options)
|
97
|
+
track_action = Apps::Gmail::Markup.track_action('Button Text', 'http://example.org/save/endpoint')
|
98
|
+
```
|
99
|
+
|
100
|
+
You need to [register with Google](https://developers.google.com/gmail/markup/registering-with-google) to get your actions approved.
|
101
|
+
|
102
|
+
**Related Resoures:**
|
103
|
+
|
104
|
+
* [Embeding JSON-LD in HTML Documents](https://json-ld.org/spec/latest/json-ld/#embedding-json-ld-in-html-documents)
|
105
|
+
* [Test Your Schemas](https://developers.google.com/gmail/markup/testing-your-schema)
|
106
|
+
* [Email Markup Tester](https://www.google.com/webmasters/markup-tester/)
|
107
|
+
* [Structured Data Markup Helper](https://www.google.com/webmasters/markup-helper/?email=true)
|
108
|
+
* [Register with Google](https://developers.google.com/gmail/markup/registering-with-google)
|
109
|
+
* Articles:
|
110
|
+
* [A Guide to Setting up Gmail Inbox Actions](http://blog.meldium.com/home/2014/5/19/setting-up-gmail-inbox-actions) by Meldium
|
56
111
|
|
57
112
|
#### TODO
|
58
113
|
|
@@ -60,6 +115,35 @@ You can generate [schema.org](http://schema.org) markup for email in Gmail utili
|
|
60
115
|
* Email Markup helpers for other Gmail-supported metadata need to be implemented
|
61
116
|
* Additional Gmail integrations need to be developed
|
62
117
|
|
118
|
+
### Microsoft Office 365
|
119
|
+
|
120
|
+
* [Office Developer](https://github.com/OfficeDev) - git repositories of example projects for Outlook Add-ins, etc.
|
121
|
+
* [Yeoman generator](https://github.com/OfficeDev/generator-office) - generator for creating [Microsoft office Add-ins](https://docs.microsoft.com/en-us/office/dev/add-ins/)
|
122
|
+
* [Message Card Playground](https://messagecardplayground.azurewebsites.net/) - test schema.org markup and how it generates add-in UI
|
123
|
+
|
124
|
+
#### Outlook: Actionable Messages via Email
|
125
|
+
|
126
|
+
All Actionable Card markup schemas supported by Microsoft Office are implemented in this library (see [Actionable message card reference](https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference)).
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
require 'apps/outlook/actionable_messages'
|
130
|
+
|
131
|
+
message_card = Apps::Outlook::ActionableMessages.message_card('Summary text', 'Title text')
|
132
|
+
```
|
133
|
+
|
134
|
+
You can take a look at (and run) [lib/examples.rb](./lib/examples.rb) to see some sample markup.
|
135
|
+
|
136
|
+
$ ruby lib/examples.rb
|
137
|
+
|
138
|
+
You can get more example schemas or copy/paste the output of `examples.rb` to test rendering here: https://messagecardplayground.azurewebsites.net/
|
139
|
+
|
140
|
+
**Related Resources:**
|
141
|
+
|
142
|
+
* [Actionable Messages via Email](https://docs.microsoft.com/en-us/outlook/actionable-messages/actionable-messages-via-email)
|
143
|
+
* [Actionable message card reference](https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference)
|
144
|
+
* [Register your service with the actionable email developer dashboard](https://docs.microsoft.com/en-us/outlook/actionable-messages/actionable-email-dev-dashboard)
|
145
|
+
* [Register your connector with the Office 365 Connectors developer dashboard](https://docs.microsoft.com/en-us/outlook/actionable-messages/connectors-dev-dashboard) - setup a connector for users to authorize your add-in
|
146
|
+
|
63
147
|
## Development
|
64
148
|
|
65
149
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/setup
CHANGED
data/exe/apps
CHANGED
File without changes
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Common
|
5
|
+
module Schema
|
6
|
+
class Base
|
7
|
+
DEFAULT_CONTEXT = 'http://schema.org'
|
8
|
+
|
9
|
+
attr_reader :context, # the schema.org URL if not the default
|
10
|
+
:force_context # force including the default schema.org context if none specified
|
11
|
+
|
12
|
+
def initialize(**attrs)
|
13
|
+
prune(attrs).each { |name, value| instance_variable_set(:"@#{name}", value) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
@type ||= self.class.name.split('::')[-1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize
|
21
|
+
{
|
22
|
+
"@context" => serialized_context,
|
23
|
+
"@type" => type
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def serialize_hash(hash, key: 'name', value: 'value')
|
28
|
+
hash.map do |k, v|
|
29
|
+
{
|
30
|
+
key => k,
|
31
|
+
value => v
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def serialized_context
|
37
|
+
if force_context
|
38
|
+
context || DEFAULT_CONTEXT
|
39
|
+
else
|
40
|
+
context
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def as_json(force_context: false)
|
45
|
+
serialized = serialize
|
46
|
+
|
47
|
+
if force_context == true
|
48
|
+
serialized['@context'] ||= DEFAULT_CONTEXT
|
49
|
+
elsif force_context.is_a?(String)
|
50
|
+
serialized['@context'] = force_context
|
51
|
+
end
|
52
|
+
|
53
|
+
prune serialized
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_json(force_context: false, pretty: false)
|
57
|
+
hash = as_json(force_context: force_context)
|
58
|
+
|
59
|
+
pretty ? JSON.pretty_generate(hash) : JSON.dump(hash)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_script(force_context: false, pretty: true)
|
63
|
+
json = to_json(pretty: pretty, force_context: force_context)
|
64
|
+
|
65
|
+
%`<script type="application/ld+json">\n#{json}\n</script>`
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def prune(hash)
|
71
|
+
hash.each_with_object({}) do |(key, value), result|
|
72
|
+
# recursive prune
|
73
|
+
result[key] = case value
|
74
|
+
when nil
|
75
|
+
next
|
76
|
+
when Array
|
77
|
+
next if value.empty?
|
78
|
+
value.map{ |v| v.is_a?(Hash) ? prune(v) : v }
|
79
|
+
when Hash
|
80
|
+
value = prune value
|
81
|
+
next if value.empty?
|
82
|
+
value
|
83
|
+
else
|
84
|
+
value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Apps
|
2
|
+
module Common
|
3
|
+
module Schema
|
4
|
+
module Concerns
|
5
|
+
module PotentialAction
|
6
|
+
# Handles the case when there is one action
|
7
|
+
def action
|
8
|
+
actions.first if actions.size == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def actions
|
12
|
+
@actions ||= [@action].compact
|
13
|
+
end
|
14
|
+
|
15
|
+
def serialize
|
16
|
+
if actions.any?
|
17
|
+
super.merge("potentialAction" => serialize_actions)
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def serialize_actions
|
24
|
+
# Gmail uses a hash for one action and an array for multiple.
|
25
|
+
# Outlook uses an array regardless and breaks if it's a hash.
|
26
|
+
# So we will always return an array.
|
27
|
+
|
28
|
+
# action&.serialize || actions.map(&:serialize)
|
29
|
+
actions.map(&:serialize)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require_relative 'schema'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Gmail
|
5
|
+
module Markup
|
6
|
+
class << self
|
7
|
+
# {
|
8
|
+
# "@context": "http://schema.org",
|
9
|
+
# "@type": "EmailMessage",
|
10
|
+
# "potentialAction": {
|
11
|
+
# "@type": "ConfirmAction",
|
12
|
+
# "handler": {
|
13
|
+
# "@type": "HttpActionHandler",
|
14
|
+
# "url": "https://example.org/confirm/endpoint"
|
15
|
+
# },
|
16
|
+
# "name": "Action Name"
|
17
|
+
# }
|
18
|
+
# }
|
19
|
+
def confirm_action(name, url, **attrs)
|
20
|
+
action = Schema::ConfirmAction.new(name: name, url: url)
|
21
|
+
root = Schema::EmailMessage.new(action: action, **attrs)
|
22
|
+
|
23
|
+
root
|
24
|
+
end
|
25
|
+
|
26
|
+
# {
|
27
|
+
# "@context": "http://schema.org",
|
28
|
+
# "@type": "EmailMessage",
|
29
|
+
# "potentialAction": {
|
30
|
+
# "@type": "SaveAction",
|
31
|
+
# "handler": {
|
32
|
+
# "@type": "HttpActionHandler",
|
33
|
+
# "url": "https://example.org/save/endpoint"
|
34
|
+
# },
|
35
|
+
# "name": "Action Name"
|
36
|
+
# }
|
37
|
+
# }
|
38
|
+
def save_action(name, url, **attrs)
|
39
|
+
action = Schema::SaveAction.new(name: name, url: url)
|
40
|
+
root = Schema::EmailMessage.new(action: action, **attrs)
|
41
|
+
|
42
|
+
root
|
43
|
+
end
|
44
|
+
|
45
|
+
# {
|
46
|
+
# "@context": "http://schema.org",
|
47
|
+
# "@type": "Event",
|
48
|
+
# "name": "Action Name",
|
49
|
+
# "location": {
|
50
|
+
# "@type": "Place",
|
51
|
+
# "address": {
|
52
|
+
# "@type": "PostalAddress"
|
53
|
+
# }
|
54
|
+
# },
|
55
|
+
# "potentialAction": [
|
56
|
+
# {
|
57
|
+
# "@type": "RsvpAction",
|
58
|
+
# "handler": {
|
59
|
+
# "@type": "HttpActionHandler",
|
60
|
+
# "url": "http://example.org/yes/endpoint"
|
61
|
+
# },
|
62
|
+
# "rsvpResponse": "yes",
|
63
|
+
# "attendance": "http://schema.org/RsvpAttendance/Yes"
|
64
|
+
# },
|
65
|
+
# {
|
66
|
+
# "@type": "RsvpAction",
|
67
|
+
# "handler": {
|
68
|
+
# "@type": "HttpActionHandler",
|
69
|
+
# "url": "http://example.org/no/endpoint"
|
70
|
+
# },
|
71
|
+
# "rsvpResponse": "no",
|
72
|
+
# "attendance": "http://schema.org/RsvpAttendance/No"
|
73
|
+
# },
|
74
|
+
# {
|
75
|
+
# "@type": "RsvpAction",
|
76
|
+
# "handler": {
|
77
|
+
# "@type": "HttpActionHandler",
|
78
|
+
# "url": "http://example.org/maybe/endpoint"
|
79
|
+
# },
|
80
|
+
# "rsvpResponse": "maybe",
|
81
|
+
# "attendance": "http://schema.org/RsvpAttendance/Maybe"
|
82
|
+
# }
|
83
|
+
# ]
|
84
|
+
# }
|
85
|
+
def rsvp_action(name, yes_url: nil, no_url: nil, maybe_url: nil, **attrs)
|
86
|
+
Schema::Event.new(name: name, **attrs).tap do |root|
|
87
|
+
root.build_location unless root.location
|
88
|
+
root.build_rsvp_actions unless root.actions.any?
|
89
|
+
|
90
|
+
responses = {
|
91
|
+
'Yes' => yes_url,
|
92
|
+
'No' => no_url,
|
93
|
+
'Maybe' => maybe_url
|
94
|
+
}
|
95
|
+
|
96
|
+
# Specify RSVP URLs
|
97
|
+
responses.each do |response, url|
|
98
|
+
next if url.nil?
|
99
|
+
|
100
|
+
action = root.actions.find { |action| action.response == response }
|
101
|
+
action ||= root.add_action_for(response)
|
102
|
+
|
103
|
+
action.url = url
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# {
|
109
|
+
# "@context": "http://schema.org",
|
110
|
+
# "@type": "EmailMessage",
|
111
|
+
# "potentialAction": {
|
112
|
+
# "@type": "ViewAction",
|
113
|
+
# "name": "Action Name",
|
114
|
+
# "target": "http://example.org/view/endpoint"
|
115
|
+
# }
|
116
|
+
# }
|
117
|
+
def view_action(name, target, **attrs)
|
118
|
+
action = Schema::ViewAction.new(name: name, target: target)
|
119
|
+
root = Schema::EmailMessage.new(action: action, **attrs)
|
120
|
+
|
121
|
+
root
|
122
|
+
end
|
123
|
+
|
124
|
+
# {
|
125
|
+
# "@context": "http://schema.org",
|
126
|
+
# "@type": "ParcelDelivery",
|
127
|
+
# "deliveryAddress": {
|
128
|
+
# "@type": "PostalAddress"
|
129
|
+
# },
|
130
|
+
# "carrier": {
|
131
|
+
# "@type": "Organization"
|
132
|
+
# },
|
133
|
+
# "itemShipped": {
|
134
|
+
# "@type": "Product"
|
135
|
+
# },
|
136
|
+
# "partOfOrder": {
|
137
|
+
# "@type": "Order",
|
138
|
+
# "merchant": {
|
139
|
+
# "@type": "Organization"
|
140
|
+
# }
|
141
|
+
# },
|
142
|
+
# "potentialAction": {
|
143
|
+
# "@type": "TrackAction",
|
144
|
+
# "name": "Action Name",
|
145
|
+
# "target": "https://example.org/track/endpoint"
|
146
|
+
# }
|
147
|
+
# }
|
148
|
+
def track_action(name, target, **attrs)
|
149
|
+
action = Schema::TrackAction.new(name: name, target: target)
|
150
|
+
|
151
|
+
Schema::ParcelDelivery.new(action: action, **attrs).tap do |root|
|
152
|
+
root.build_delivery_address unless root.delivery_address
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|