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
@@ -0,0 +1,17 @@
|
|
1
|
+
module Apps
|
2
|
+
module Outlook
|
3
|
+
module Schema
|
4
|
+
module Concerns
|
5
|
+
module SortedPotentialActions
|
6
|
+
def serialize_actions
|
7
|
+
# OpenUri action is supposed to be last
|
8
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#openuri-action
|
9
|
+
actions.sort! { |a, b| a.class == b.class ? 0 : a.is_a?(OpenUri) ? -1 : 1 }
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'input'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#dateinput
|
7
|
+
class DateInput < Input
|
8
|
+
|
9
|
+
attr_accessor :include_time # Boolean - whether to select time in addition to date
|
10
|
+
|
11
|
+
def serialize
|
12
|
+
super.merge("includeTime" => include_time)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'action'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#httppost-action
|
7
|
+
class HttpPOST < Action
|
8
|
+
# CARD-ACTION-STATUS - include header in server HTTP POST response
|
9
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#reporting-an-actions-execution-success-or-failure
|
10
|
+
# CARD-UPDATE-IN-BODY - `true` value indicates to client to refresh content with response body
|
11
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#refresh-cards
|
12
|
+
RESPONSE_HEADERS = %w[
|
13
|
+
CARD-ACTION-STATUS
|
14
|
+
CARD-UPDATE-IN-BODY
|
15
|
+
]
|
16
|
+
MIME_TYPES = %w[
|
17
|
+
application/json
|
18
|
+
application/x-www-form-urlencoded
|
19
|
+
]
|
20
|
+
|
21
|
+
attr_accessor :target, # URL
|
22
|
+
:body, # body of the POST request
|
23
|
+
:body_content_type # MIME type of body
|
24
|
+
|
25
|
+
def headers
|
26
|
+
@headers ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def serialize
|
30
|
+
super.merge(
|
31
|
+
"target" => target,
|
32
|
+
"headers" => serialize_hash(headers),
|
33
|
+
"body" => body,
|
34
|
+
"bodyContentType" => body_content_type
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_header(name, value)
|
39
|
+
headers[name] = value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Apps
|
2
|
+
module Outlook
|
3
|
+
module Schema
|
4
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#inputs
|
5
|
+
class Input < Base
|
6
|
+
|
7
|
+
attr_accessor :id, # Uniquely identifies input in a form
|
8
|
+
:required,
|
9
|
+
:title, # Placeholder text or label
|
10
|
+
:value # Initial value of input
|
11
|
+
|
12
|
+
def serialize
|
13
|
+
super.merge(
|
14
|
+
"id" => id,
|
15
|
+
"isRequired" => required,
|
16
|
+
"title" => title,
|
17
|
+
"value" => value
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'action'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#invokeaddincommand-action
|
7
|
+
class InvokeAddInCommand < Action
|
8
|
+
|
9
|
+
attr_accessor :add_in_id, # UUID from add-in's manifest
|
10
|
+
# Specifies the ID of the add-in command button that opens
|
11
|
+
# the required taskpane. The command button ID is found in
|
12
|
+
# the id attribute of the Control element that defines the
|
13
|
+
# button in the add-in's manifest. The specified Control element
|
14
|
+
# MUST be defined inside a `MessageReadCommandSurface` extension point,
|
15
|
+
# be of type Button, and the control's Action must be of type `ShowTaskPane`.
|
16
|
+
:desktop_command_id,
|
17
|
+
# Optional. Developers may specify any valid JSON object in
|
18
|
+
# this field. The value is serialized into a string and made
|
19
|
+
# available to the add-in when the action is executed. This
|
20
|
+
# allows the action to pass initialization data to the add-in.
|
21
|
+
:initialization_context
|
22
|
+
|
23
|
+
def serialize
|
24
|
+
super.merge(
|
25
|
+
"addInId" => add_in_id,
|
26
|
+
"desktopCommandId" => desktop_command_id,
|
27
|
+
"initializationContext" => initialization_context
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'concerns/sections'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference
|
7
|
+
class MessageCard < Base
|
8
|
+
include Schema::Concerns::Sections
|
9
|
+
include Schema::Concerns::PotentialAction
|
10
|
+
include Schema::Concerns::SortedPotentialActions
|
11
|
+
|
12
|
+
HEADER_NAMES = %w[Card-Correlation-Id Action-Request-Id]
|
13
|
+
|
14
|
+
attr_accessor :correlation_id # UUID to track actions originating in email message
|
15
|
+
attr_accessor :originator # provider ID (required for actionable emails)
|
16
|
+
attr_accessor :hide_original_body # For email only (hide email content if message card is duplicate)
|
17
|
+
attr_accessor :summary, :title,
|
18
|
+
:text # Markdown
|
19
|
+
attr_accessor :theme_color
|
20
|
+
|
21
|
+
def context
|
22
|
+
'http://schema.org/extensions'
|
23
|
+
end
|
24
|
+
|
25
|
+
def serialize
|
26
|
+
super.merge(
|
27
|
+
"summary" => summary,
|
28
|
+
"themeColor" => theme_color,
|
29
|
+
"correlationId" => correlation_id,
|
30
|
+
"originator" => originator,
|
31
|
+
"hideOriginalBody" => hide_original_body,
|
32
|
+
"title" => title,
|
33
|
+
"text" => text
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'input'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#multichoiceinput
|
7
|
+
class MultichoiceInput < Input
|
8
|
+
STYLES = %w[normal expanded].freeze
|
9
|
+
|
10
|
+
attr_accessor :multiple, # Boolean - whether to allow selecting multiple choices
|
11
|
+
:style # `normal` - dropdown
|
12
|
+
# `expanded` - radio button list
|
13
|
+
|
14
|
+
def choices
|
15
|
+
@choices ||= {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def serialize
|
19
|
+
super.merge(
|
20
|
+
"isMultiSelect" => multiple,
|
21
|
+
"style" => style,
|
22
|
+
"choices" => serialize_hash(choices, key: 'display')
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_choice(name, value)
|
27
|
+
choices[name] = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'action'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#openuri-action
|
7
|
+
class OpenUri < Action
|
8
|
+
OPERATING_SYSTEMS = %w[default windows iOS android].freeze
|
9
|
+
|
10
|
+
def targets
|
11
|
+
@targets ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize
|
15
|
+
super.merge("targets" => serialize_hash(targets, key: 'os', value: 'uri'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_target(url, os: 'default')
|
19
|
+
targets[os] = url
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Apps
|
2
|
+
module Outlook
|
3
|
+
module Schema
|
4
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#section-fields
|
5
|
+
class Section < Base
|
6
|
+
include Schema::Concerns::PotentialAction
|
7
|
+
include Schema::Concerns::SortedPotentialActions
|
8
|
+
|
9
|
+
attr_accessor :title,
|
10
|
+
:text # Markdown
|
11
|
+
attr_accessor :start_group # boolean, used to separate sections with divider lines
|
12
|
+
attr_accessor :activity_title, # Markdown
|
13
|
+
:activity_subtitle, :activity_text, :activity_image
|
14
|
+
attr_accessor :hero_image, # url
|
15
|
+
:hero_title
|
16
|
+
|
17
|
+
# Hash of key/value pairs displayed to call out specific points
|
18
|
+
def facts
|
19
|
+
@facts ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Photo gallery (URL => title)
|
23
|
+
def images
|
24
|
+
@images ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def serialize
|
28
|
+
super.merge(
|
29
|
+
"title" => title,
|
30
|
+
"startGroup" => start_group,
|
31
|
+
"activityTitle" => activity_title,
|
32
|
+
"activitySubtitle" => activity_subtitle,
|
33
|
+
"activityText" => activity_text,
|
34
|
+
"activityImage" => activity_image,
|
35
|
+
"heroImage" => hero_image && serialize_image(hero_image => hero_title, key: 'image', value: 'title'),
|
36
|
+
"text" => text,
|
37
|
+
"facts" => serialize_hash(facts),
|
38
|
+
"images" => serialize_hash(images, key: 'image', value: 'title')
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_fact(name, value)
|
43
|
+
facts[name] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_image(url, title: nil)
|
47
|
+
images[url] = title
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'input'
|
2
|
+
|
3
|
+
module Apps
|
4
|
+
module Outlook
|
5
|
+
module Schema
|
6
|
+
# See: https://docs.microsoft.com/en-us/outlook/actionable-messages/card-reference#textinput
|
7
|
+
class TextInput < Input
|
8
|
+
|
9
|
+
attr_accessor :multiline, :max_length
|
10
|
+
|
11
|
+
def serialize
|
12
|
+
super.merge(
|
13
|
+
"isMultiline" => multiline,
|
14
|
+
"maxLength" => max_length
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/apps/version.rb
CHANGED
data/lib/examples.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
|
2
|
+
def divide(char = '#')
|
3
|
+
puts ""
|
4
|
+
puts char * 72
|
5
|
+
puts ""
|
6
|
+
end
|
7
|
+
|
8
|
+
def show(caption, object)
|
9
|
+
puts caption
|
10
|
+
puts ""
|
11
|
+
|
12
|
+
if object.is_a?(String)
|
13
|
+
puts object
|
14
|
+
else
|
15
|
+
pp object
|
16
|
+
end
|
17
|
+
|
18
|
+
puts ""
|
19
|
+
end
|
20
|
+
|
21
|
+
divide
|
22
|
+
|
23
|
+
require_relative 'apps/gmail/markup'
|
24
|
+
|
25
|
+
puts "GMAIL TESTS"
|
26
|
+
|
27
|
+
# Confirm Action (takes additional keyword options)
|
28
|
+
confirm_action = Apps::Gmail::Markup.confirm_action('Button Text', 'http://example.org/confirm/endpoint')
|
29
|
+
|
30
|
+
show 'confirm_action.as_json', confirm_action.as_json
|
31
|
+
# => {"@context"=>"http://schema.org", "@type"=>"EmailMessage", "potentialAction"=>{"@type"=>"ConfirmAction", "handler"=>{"@type"=>"HttpActionHandler", "url"=>"http://example.org/confirm/endpoint"}}}
|
32
|
+
|
33
|
+
show 'confirm_action.to_json', confirm_action.to_json
|
34
|
+
# => {"@context":"http://schema.org","@type":"EmailMessage","potentialAction":{"@type":"ConfirmAction","handler":{"@type":"HttpActionHandler","url":"http://example.org/confirm/endpoint"}}}
|
35
|
+
|
36
|
+
# NOTE: `to_script` is only available on "context" objects that represent the root of the markup
|
37
|
+
# needed for embedding in emails. This is the object returned by each of the helper methods
|
38
|
+
# above for each "Action"
|
39
|
+
show 'confirm_action.to_script', confirm_action.to_script
|
40
|
+
# =>
|
41
|
+
# <script type="application/ld+json">
|
42
|
+
# {
|
43
|
+
# "@context": "http://schema.org",
|
44
|
+
# "@type": "EmailMessage",
|
45
|
+
# "potentialAction": {
|
46
|
+
# "@type": "ConfirmAction",
|
47
|
+
# "handler": {
|
48
|
+
# "@type": "HttpActionHandler",
|
49
|
+
# "url": "http://example.org/confirm/endpoint"
|
50
|
+
# }
|
51
|
+
# }
|
52
|
+
# }
|
53
|
+
# </script>
|
54
|
+
|
55
|
+
# Save Action (takes additional keyword options)
|
56
|
+
save_action = Apps::Gmail::Markup.save_action('Button Text', 'http://example.org/save/endpoint')
|
57
|
+
|
58
|
+
show 'save_action', save_action.to_script
|
59
|
+
|
60
|
+
# RSVP Action (takes additional keyword options)
|
61
|
+
rsvp_action = Apps::Gmail::Markup.rsvp_action('Event Name',
|
62
|
+
yes_url: 'http://example.org/yes/endpoint',
|
63
|
+
no_url: 'http://example.org/no/endpoint',
|
64
|
+
maybe_url: 'http://example.org/maybe/endpoint'
|
65
|
+
)
|
66
|
+
|
67
|
+
show 'rsvp_action', rsvp_action.to_script
|
68
|
+
|
69
|
+
# View Action (takes additional keyword options)
|
70
|
+
view_action = Apps::Gmail::Markup.view_action('Button Text', 'http://example.org/save/endpoint')
|
71
|
+
|
72
|
+
show 'view_action', view_action.to_script
|
73
|
+
|
74
|
+
# Track Action (takes additional keyword options)
|
75
|
+
track_action = Apps::Gmail::Markup.track_action('Button Text', 'http://example.org/save/endpoint')
|
76
|
+
|
77
|
+
show 'track_action', track_action.to_script
|
78
|
+
|
79
|
+
divide
|
80
|
+
|
81
|
+
require_relative 'apps/outlook/actionable_messages'
|
82
|
+
|
83
|
+
puts "OUTLOOK TESTS"
|
84
|
+
|
85
|
+
message_card = Apps::Outlook::ActionableMessages.message_card('Summary text', 'Title text')
|
86
|
+
|
87
|
+
section = message_card.add_section('Section title', start_group: true, activity_image: 'http://img')
|
88
|
+
section.add_fact('Username', 'joelvh')
|
89
|
+
section.actions << Apps::Outlook::Schema::OpenUri.new(name: 'Section open uri action').tap { |s| s.add_target('http://target/section')}
|
90
|
+
|
91
|
+
show "section.actions", section.actions
|
92
|
+
|
93
|
+
pp message_card.serialize
|
94
|
+
|
95
|
+
section2 = message_card.add_section('Section 2 title', start_group: false, activity_image: 'http://img2')
|
96
|
+
section2.add_image('http://gallery1')
|
97
|
+
section2.add_image('http://gallery2', title: 'Gallery 2 caption')
|
98
|
+
|
99
|
+
message_card.actions << Apps::Outlook::Schema::OpenUri.new(name: 'Card open uri action')
|
100
|
+
|
101
|
+
action_card = Apps::Outlook::Schema::ActionCard.new(name: 'Action card form')
|
102
|
+
|
103
|
+
action_card.inputs << Apps::Outlook::Schema::DateInput.new(id: 'due_date', title: 'Due Date', value: '2008-01-01')
|
104
|
+
action_card.inputs << Apps::Outlook::Schema::TextInput.new(id: 'username', title: 'Username', value: 'fakeuser')
|
105
|
+
action_card.inputs << Apps::Outlook::Schema::MultichoiceInput.new(id: 'rating', title: 'Rating', value: '3').tap do |multi|
|
106
|
+
multi.add_choice('1 Star', '1')
|
107
|
+
multi.add_choice('3 Star', '3')
|
108
|
+
multi.add_choice('5 Star', '5')
|
109
|
+
end
|
110
|
+
|
111
|
+
section2.actions << action_card
|
112
|
+
|
113
|
+
show "message_card.actions", message_card.actions
|
114
|
+
|
115
|
+
pp message_card.serialize
|
116
|
+
|
117
|
+
divide('-')
|
118
|
+
|
119
|
+
puts message_card.to_script
|
120
|
+
|
121
|
+
divide
|
data/package.json
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"name": "apps",
|
3
|
+
"version": "0.3.0",
|
4
|
+
"description": "Easily integrate with multiple platform apps/add-ins/add-ons marketplaces.",
|
5
|
+
"main": "index.js",
|
6
|
+
"repository": "https://github.com/joelvh/apps",
|
7
|
+
"author": "Joel Van Horn <joel@joelvanhorn.com>",
|
8
|
+
"license": "MIT",
|
9
|
+
"dependencies": {
|
10
|
+
"generator-office": "^1.1.7"
|
11
|
+
}
|
12
|
+
}
|