stride 0.1.0 → 0.1.1
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 +4 -4
- data/.ruby-version +1 -0
- data/CHANGELOG.md +7 -0
- data/README.md +130 -4
- data/lib/stride.rb +25 -2
- data/lib/stride/atlassian_document_format_expander.rb +117 -0
- data/lib/stride/authorized_request.rb +14 -0
- data/lib/stride/base_request.rb +52 -0
- data/lib/stride/bot_mention.rb +113 -0
- data/lib/stride/client.rb +66 -0
- data/lib/stride/configuration.rb +25 -0
- data/lib/stride/conversation.rb +47 -0
- data/lib/stride/conversation_roster.rb +43 -0
- data/lib/stride/installation.rb +22 -0
- data/lib/stride/markdown_document.rb +42 -0
- data/lib/stride/me.rb +38 -0
- data/lib/stride/message.rb +41 -0
- data/lib/stride/text_message.rb +36 -0
- data/lib/stride/token.rb +38 -0
- data/lib/stride/user.rb +59 -0
- data/lib/stride/user_message.rb +64 -0
- data/lib/stride/version.rb +1 -1
- data/stride.gemspec +3 -0
- metadata +63 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa8b67e12775bcb352e3dfe5d3559a5660886466
|
4
|
+
data.tar.gz: 6ce50f9338ad89bfb0afb17f829690765eb155aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a943fe7c8dc7c1aa7de0dcbe12034f0573a63b7585e4c7bc0747fd1565e11dc3f3c8161d3e26d147b8a5afe2b14fcd341163b0a1cb93cf8ba054fa2c3894edc0
|
7
|
+
data.tar.gz: 895c2e375956d444995e033e1cdc61e8618a1ad66a2a6590178ec95d0985af3173179baa13cead0ca1afa4e4a9a05939c852e1b2d75c602cac745e238abae59b
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.1
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# Stride
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
A ruby wrapper for Stride's API.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -20,9 +18,137 @@ Or install it yourself as:
|
|
20
18
|
|
21
19
|
$ gem install stride
|
22
20
|
|
21
|
+
## Configuration
|
22
|
+
|
23
|
+
Add to an initializer:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Stride.configure do |config|
|
27
|
+
config.client_id = "YOUR CLIENT ID"
|
28
|
+
config.client_secret = "YOUR CLIENT SECRET"
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
23
32
|
## Usage
|
24
33
|
|
25
|
-
|
34
|
+
### Acquiring an access token
|
35
|
+
|
36
|
+
This should be done for you in most cases, but if you need to acquire an access token from the Atlassian Identity API, you may do so:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Stride::Token.fetch!
|
40
|
+
```
|
41
|
+
|
42
|
+
This returns a `Token` instance, which will have an `access_token` attribute.
|
43
|
+
|
44
|
+
### Creating a client
|
45
|
+
|
46
|
+
Send in the cloud_id and conversation_id:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
cloud_id = '911f7ab7-0581-4082-bed3-bad889ec4c91'
|
50
|
+
conversation_id = '76987a29-b7d9-43c5-b071-7aab71d88a6b'
|
51
|
+
|
52
|
+
client = Stride::Client.new(cloud_id, conversation_id)
|
53
|
+
```
|
54
|
+
|
55
|
+
This will rely on OAuth to get a token. If you've generated a room token
|
56
|
+
[as described here](https://developer.atlassian.com/cloud/stride/security/authentication/),
|
57
|
+
then you can pass that in as a third parameter when initializing the client:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Stride::Client.new(cloud_id, conversation_id, access_token)
|
61
|
+
```
|
62
|
+
|
63
|
+
When you use this approach, the `client_id` and `client_secret` configuration
|
64
|
+
are unnecessary.
|
65
|
+
|
66
|
+
### Sending a message
|
67
|
+
|
68
|
+
If there's a specific cloud and conversation you want to send to, you can send an arbitrary message using `Stride::Client#send_message`. Refer to the [Stride API documentation](https://developer.atlassian.com/cloud/stride/blocks/message-format/) for details on the message format.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
message_body = {
|
72
|
+
version: 1,
|
73
|
+
type: 'doc',
|
74
|
+
content: [
|
75
|
+
{
|
76
|
+
type: 'paragraph',
|
77
|
+
content: [
|
78
|
+
{
|
79
|
+
type: 'text',
|
80
|
+
text: 'I am the egg man, they are the egg men'
|
81
|
+
}
|
82
|
+
]
|
83
|
+
}
|
84
|
+
]
|
85
|
+
}
|
86
|
+
|
87
|
+
client.send_message(message_body)
|
88
|
+
# => {"id"=>"5d6e39d3-ab1d-10e7-be03-02420aff0003"}
|
89
|
+
```
|
90
|
+
|
91
|
+
To send a plain text message as above, there's a convience method, `Stride::Client#send_text_message`:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
client.send_message('I am the egg man, they are the egg men')
|
95
|
+
# => {"id"=>"5d6e39d3-ab1d-10e7-be03-02420aff0003"}
|
96
|
+
```
|
97
|
+
|
98
|
+
To send a message from Markdown:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
client.send_markdown_message('Oh hi [click here](https://bonus.ly)')
|
102
|
+
```
|
103
|
+
|
104
|
+
We use Atlassian's service for rendering Markdown to Atlassian Document Format (ADF).
|
105
|
+
|
106
|
+
To send a user a message:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
client.send_user_message(user_id, 'Do you have any eggs?')
|
110
|
+
|
111
|
+
client.send_user_markdown_message(user_id, 'Do you have *any* eggs?')
|
112
|
+
```
|
113
|
+
|
114
|
+
### User Details
|
115
|
+
|
116
|
+
To get details about a user when you have the id:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
client.user(user_id)
|
120
|
+
```
|
121
|
+
|
122
|
+
This returns a `User` instance with the following attributes:
|
123
|
+
`:id, :user_name, :active, :display_name, :emails, :meta, :photos`
|
124
|
+
|
125
|
+
To get details about a conversation when you have the id:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
client.conversation
|
129
|
+
```
|
130
|
+
|
131
|
+
This returns a `Conversation` instance with the following attributes:
|
132
|
+
`:cloud_id, :id, :name, :topic, :type, :created, :modified, :avatar_url, :privacy, :is_archived`
|
133
|
+
|
134
|
+
To get the members of the conversation:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
client.conversation_roster.users
|
138
|
+
```
|
139
|
+
|
140
|
+
This will return an array of `User` instances for everyone in the conversation.
|
141
|
+
|
142
|
+
### Bot Details
|
143
|
+
|
144
|
+
To get information about your bot user, just call
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
client.me
|
148
|
+
```
|
149
|
+
|
150
|
+
This will return a `Me` instance with the following attributes:
|
151
|
+
`:account_id, :name, :email, :picture`
|
26
152
|
|
27
153
|
## Development
|
28
154
|
|
data/lib/stride.rb
CHANGED
@@ -1,5 +1,28 @@
|
|
1
|
-
require
|
1
|
+
require 'stride/version'
|
2
|
+
require 'stride/configuration'
|
3
|
+
require 'stride/atlassian_document_format_expander'
|
4
|
+
require 'stride/base_request'
|
5
|
+
require 'stride/authorized_request'
|
6
|
+
require 'stride/token'
|
7
|
+
require 'stride/message'
|
8
|
+
require 'stride/user_message'
|
9
|
+
require 'stride/text_message'
|
10
|
+
require 'stride/client'
|
11
|
+
require 'stride/installation'
|
12
|
+
require 'stride/user'
|
13
|
+
require 'stride/markdown_document'
|
14
|
+
require 'stride/conversation'
|
15
|
+
require 'stride/conversation_roster'
|
16
|
+
require 'stride/bot_mention'
|
17
|
+
require 'stride/me'
|
2
18
|
|
3
19
|
module Stride
|
4
|
-
|
20
|
+
class << self
|
21
|
+
attr_accessor :configuration
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure
|
25
|
+
self.configuration ||= Configuration.new
|
26
|
+
yield(configuration)
|
27
|
+
end
|
5
28
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Stride
|
2
|
+
class AtlassianDocumentFormatExpander
|
3
|
+
def initialize(initial_json)
|
4
|
+
self.initial_json = initial_json
|
5
|
+
end
|
6
|
+
|
7
|
+
def as_json
|
8
|
+
return initial_json unless initial_json.has_key?('content')
|
9
|
+
|
10
|
+
initial_json['content'] = ContentBlocks.new(initial_json['content']).as_json
|
11
|
+
initial_json
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_accessor :initial_json
|
17
|
+
|
18
|
+
class ContentBlocks
|
19
|
+
def initialize(initial_json)
|
20
|
+
self.initial_json = initial_json
|
21
|
+
end
|
22
|
+
|
23
|
+
def as_json
|
24
|
+
wrapped_blocks.map(&:as_json).flatten
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_accessor :initial_json
|
30
|
+
|
31
|
+
def wrapped_blocks
|
32
|
+
initial_json.map do |content_block_json|
|
33
|
+
if content_block_json.has_key?('content')
|
34
|
+
content_block_json['content'] = ContentBlocks.new(content_block_json['content']).as_json
|
35
|
+
content_block_json
|
36
|
+
else
|
37
|
+
ContentBlock.new(content_block_json)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ContentBlock
|
44
|
+
MENTION_REGEX = /@@([a-zA-Z]+)\|([a-zA-Z0-9\-:]+)@@/
|
45
|
+
MENTION_REGEX_WITHOUT_GROUPS = /@@[a-zA-Z]+\|[a-zA-Z0-9\-:]+@@/
|
46
|
+
|
47
|
+
def initialize(initial_json)
|
48
|
+
self.initial_json = initial_json
|
49
|
+
end
|
50
|
+
|
51
|
+
def as_json
|
52
|
+
split? ? split_json : initial_json
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_accessor :initial_json
|
58
|
+
|
59
|
+
def split?
|
60
|
+
initial_json.has_key?('text') && match_data.present?
|
61
|
+
end
|
62
|
+
|
63
|
+
def match_data
|
64
|
+
@match_data ||= initial_json['text'].match(MENTION_REGEX)
|
65
|
+
end
|
66
|
+
|
67
|
+
def split_json
|
68
|
+
split_blocks.map(&:as_json)
|
69
|
+
end
|
70
|
+
|
71
|
+
def split_blocks
|
72
|
+
return text_blocks_joined_by_mention_block if mention_in_middle?
|
73
|
+
|
74
|
+
if mention_at_beginning?
|
75
|
+
text_blocks_joined_by_mention_block.prepend mention_block
|
76
|
+
else
|
77
|
+
text_blocks_joined_by_mention_block << mention_block
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def text_blocks_joined_by_mention_block
|
82
|
+
@text_blocks_joined_by_mention_block ||= text_blocks.each_with_object([]) do |text_block, all_blocks|
|
83
|
+
all_blocks << text_block
|
84
|
+
all_blocks << mention_block unless text_block == text_blocks.last
|
85
|
+
end.reject { |block| block.as_json['text'] == '' }
|
86
|
+
end
|
87
|
+
|
88
|
+
def mention_in_middle?
|
89
|
+
text_blocks_joined_by_mention_block.count > 1
|
90
|
+
end
|
91
|
+
|
92
|
+
def mention_at_beginning?
|
93
|
+
(initial_json['text'] =~ MENTION_REGEX_WITHOUT_GROUPS) == 0
|
94
|
+
end
|
95
|
+
|
96
|
+
def text_blocks
|
97
|
+
@text_blocks ||= initial_json['text'].split(MENTION_REGEX_WITHOUT_GROUPS).map do |text|
|
98
|
+
self.class.new({
|
99
|
+
"type" => "text",
|
100
|
+
"text" => text
|
101
|
+
})
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def mention_block
|
106
|
+
@mention_block ||= self.class.new({
|
107
|
+
"type" => "mention",
|
108
|
+
"attrs" => {
|
109
|
+
"id" => match_data[2],
|
110
|
+
"text" => "@#{match_data[1]}",
|
111
|
+
"accessLevel" => "CONTAINER"
|
112
|
+
}
|
113
|
+
})
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Stride
|
2
|
+
class BaseRequest
|
3
|
+
def json
|
4
|
+
if result.code =~ /20\d/
|
5
|
+
JSON.parse(result.body)
|
6
|
+
else
|
7
|
+
raise ApiFailure.new(error_message)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def result
|
14
|
+
@result ||= Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
15
|
+
http.request(request)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def error_message
|
20
|
+
"Got a #{result.code} from Stride API: #{result.body}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def request
|
24
|
+
request_class.new(uri).tap do |req|
|
25
|
+
req.body = params.to_json if params.any?
|
26
|
+
headers.each do |key, value|
|
27
|
+
req[key] = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def request_class
|
33
|
+
Net::HTTP::Post
|
34
|
+
end
|
35
|
+
|
36
|
+
def uri
|
37
|
+
raise 'uri must be implemented per request'
|
38
|
+
end
|
39
|
+
|
40
|
+
def params
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
|
44
|
+
def headers
|
45
|
+
{
|
46
|
+
'content-type' => 'application/json'
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class ApiFailure < RuntimeError; end
|
52
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Stride
|
2
|
+
class BotMention
|
3
|
+
def initialize(json)
|
4
|
+
self.json = json
|
5
|
+
end
|
6
|
+
|
7
|
+
def text
|
8
|
+
json['message']['text']
|
9
|
+
end
|
10
|
+
|
11
|
+
def text_without_mentions
|
12
|
+
content_blocks.select(&:text?).map(&:text).join.strip
|
13
|
+
end
|
14
|
+
|
15
|
+
def mentions
|
16
|
+
content_blocks.select(&:mention?)
|
17
|
+
end
|
18
|
+
|
19
|
+
def sender_id
|
20
|
+
json['sender']['id']
|
21
|
+
end
|
22
|
+
|
23
|
+
def conversation
|
24
|
+
Conversation.new(json['conversation'])
|
25
|
+
end
|
26
|
+
|
27
|
+
def text_with_mentions_as_user_ids
|
28
|
+
content_blocks.map { |block| block.respond_to?(:at_id) ? block.at_id : block.text }.join.strip
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_accessor :json
|
34
|
+
|
35
|
+
def content_blocks
|
36
|
+
ContentBlock.wrap(content_json)
|
37
|
+
end
|
38
|
+
|
39
|
+
def content_json
|
40
|
+
content = json['message']['body']['content']
|
41
|
+
content.detect { |json| json['type'] == 'paragraph' } || content.first
|
42
|
+
end
|
43
|
+
|
44
|
+
class ContentBlock
|
45
|
+
def self.wrap(json)
|
46
|
+
json = json['content'] if json.has_key?('content')
|
47
|
+
json.map { |json_block| factory(json_block) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.factory(json_block)
|
51
|
+
json_block['type'] == 'text' ? TextBlock.new(json_block) : MentionBlock.new(json_block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(json)
|
55
|
+
self.json = json
|
56
|
+
end
|
57
|
+
|
58
|
+
def type
|
59
|
+
json['type']
|
60
|
+
end
|
61
|
+
|
62
|
+
def text?
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
def mention?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
attr_accessor :json
|
73
|
+
end
|
74
|
+
|
75
|
+
class TextBlock < ContentBlock
|
76
|
+
def text
|
77
|
+
json['text']
|
78
|
+
end
|
79
|
+
|
80
|
+
def text?
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class MentionBlock < ContentBlock
|
86
|
+
def text
|
87
|
+
attrs['text']
|
88
|
+
end
|
89
|
+
|
90
|
+
def id
|
91
|
+
attrs['id']
|
92
|
+
end
|
93
|
+
|
94
|
+
def access_level
|
95
|
+
attrs['accessLevel']
|
96
|
+
end
|
97
|
+
|
98
|
+
def mention?
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
def at_id
|
103
|
+
"@#{id}"
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def attrs
|
109
|
+
json['attrs']
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Stride
|
2
|
+
class Client
|
3
|
+
def initialize(cloud_id, conversation_id, permanent_token = nil)
|
4
|
+
self.cloud_id = cloud_id
|
5
|
+
self.conversation_id = conversation_id
|
6
|
+
self.permanent_token = permanent_token
|
7
|
+
end
|
8
|
+
|
9
|
+
# `message_body` is a formatted message in JSON
|
10
|
+
# See: https://developer.atlassian.com/cloud/stride/blocks/message-format/
|
11
|
+
def send_message(message_body)
|
12
|
+
Message.new(access_token, cloud_id, conversation_id, message_body).send!
|
13
|
+
end
|
14
|
+
|
15
|
+
# Convenience method for sending a plain text message
|
16
|
+
def send_text_message(message_text)
|
17
|
+
TextMessage.new(access_token, cloud_id, conversation_id, message_text).send!
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_user_message(user_id, message_body)
|
21
|
+
UserMessage.new(access_token, cloud_id, user_id, message_body).send!
|
22
|
+
end
|
23
|
+
|
24
|
+
def send_user_markdown_message(user_id, markdown)
|
25
|
+
send_user_message(user_id, MarkdownDocument.fetch!(access_token, markdown).as_json)
|
26
|
+
end
|
27
|
+
|
28
|
+
def send_markdown_message(markdown)
|
29
|
+
send_message(MarkdownDocument.fetch!(access_token, markdown).as_json)
|
30
|
+
end
|
31
|
+
|
32
|
+
def user(user_id)
|
33
|
+
User.fetch!(access_token, cloud_id, user_id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def conversation
|
37
|
+
Conversation.fetch!(access_token, cloud_id, conversation_id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def conversation_roster
|
41
|
+
ConversationRoster.fetch!(access_token, cloud_id, conversation_id)
|
42
|
+
end
|
43
|
+
|
44
|
+
def me
|
45
|
+
Me.fetch!(access_token)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
attr_accessor :cloud_id, :conversation_id, :permanent_token
|
51
|
+
|
52
|
+
def access_token
|
53
|
+
permanent_token || token.access_token
|
54
|
+
end
|
55
|
+
|
56
|
+
def token
|
57
|
+
return @token if have_token?
|
58
|
+
|
59
|
+
@token = Token.fetch!
|
60
|
+
end
|
61
|
+
|
62
|
+
def have_token?
|
63
|
+
!@token.nil? && @token.unexpired?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Stride
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :client_id, :client_secret, :production
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
self.production = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def api_base_url
|
10
|
+
production? ? 'https://api.atlassian.com' : 'https://api.stg.atlassian.com'
|
11
|
+
end
|
12
|
+
|
13
|
+
def api_audience
|
14
|
+
production? ? 'api.atlassian.com' : 'api.stg.atlassian.com'
|
15
|
+
end
|
16
|
+
|
17
|
+
def auth_api_base_url
|
18
|
+
production? ? 'https://auth.atlassian.com' : 'https://atlassian-account-stg.pus2.auth0.com'
|
19
|
+
end
|
20
|
+
|
21
|
+
def production?
|
22
|
+
!!production
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Stride
|
2
|
+
class Conversation
|
3
|
+
attr_accessor :cloud_id, :id, :name, :topic, :type, :created, :modified,
|
4
|
+
:avatar_url, :privacy, :is_archived
|
5
|
+
|
6
|
+
def self.fetch!(access_token, cloud_id, conversation_id)
|
7
|
+
new(Request.new(access_token, cloud_id, conversation_id).json)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(json)
|
11
|
+
self.id = json['id']
|
12
|
+
self.cloud_id = json['cloudId']
|
13
|
+
self.name = json['name']
|
14
|
+
self.topic = json['topic']
|
15
|
+
self.type = json['type']
|
16
|
+
self.created = json['created']
|
17
|
+
self.modified = json['modified']
|
18
|
+
self.avatar_url = json['avatarUrl']
|
19
|
+
self.privacy = json['privacy']
|
20
|
+
self.is_archived = json['isArchived']
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
class Request < AuthorizedRequest
|
26
|
+
def initialize(access_token, cloud_id, conversation_id)
|
27
|
+
self.access_token = access_token
|
28
|
+
self.cloud_id = cloud_id
|
29
|
+
self.conversation_id = conversation_id
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_accessor :cloud_id, :conversation_id
|
35
|
+
|
36
|
+
def uri
|
37
|
+
URI(
|
38
|
+
"#{Stride.configuration.api_base_url}/site/#{cloud_id}/conversation/#{conversation_id}"
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def request_class
|
43
|
+
Net::HTTP::Get
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Stride
|
2
|
+
class ConversationRoster
|
3
|
+
attr_accessor :access_token, :cloud_id, :ids
|
4
|
+
|
5
|
+
def self.fetch!(access_token, cloud_id, conversation_id)
|
6
|
+
new(access_token, cloud_id, Request.new(access_token, cloud_id, conversation_id).json)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(access_token, cloud_id, json)
|
10
|
+
self.access_token = access_token
|
11
|
+
self.cloud_id = cloud_id
|
12
|
+
self.ids = json['values']
|
13
|
+
end
|
14
|
+
|
15
|
+
def users
|
16
|
+
@users ||= ids.map { |id| User.fetch!(access_token, cloud_id, id) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
class Request < AuthorizedRequest
|
22
|
+
def initialize(access_token, cloud_id, conversation_id)
|
23
|
+
self.access_token = access_token
|
24
|
+
self.cloud_id = cloud_id
|
25
|
+
self.conversation_id = conversation_id
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_accessor :cloud_id, :conversation_id
|
31
|
+
|
32
|
+
def uri
|
33
|
+
URI(
|
34
|
+
"#{Stride.configuration.api_base_url}/site/#{cloud_id}/conversation/#{conversation_id}/roster"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def request_class
|
39
|
+
Net::HTTP::Get
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Stride
|
2
|
+
class Installation
|
3
|
+
attr_accessor :key, :product_type, :cloud_id, :resource_type, :resource_id,
|
4
|
+
:event_type, :user_id, :oauth_client_id, :version
|
5
|
+
|
6
|
+
def self.parse(json_string)
|
7
|
+
new(JSON.parse(json_string))
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(json)
|
11
|
+
self.key = json['key']
|
12
|
+
self.product_type = json['productType']
|
13
|
+
self.cloud_id = json['cloudId']
|
14
|
+
self.resource_type = json['resourceType']
|
15
|
+
self.resource_id = json['resourceId']
|
16
|
+
self.event_type = json['eventType']
|
17
|
+
self.user_id = json['userId']
|
18
|
+
self.oauth_client_id = json['oauthClientId']
|
19
|
+
self.version = json['version']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Stride
|
2
|
+
class MarkdownDocument
|
3
|
+
def initialize(request)
|
4
|
+
self.request = request
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.fetch!(access_token, markdown)
|
8
|
+
new(Request.new(access_token, markdown))
|
9
|
+
end
|
10
|
+
|
11
|
+
def as_json
|
12
|
+
AtlassianDocumentFormatExpander.new(request.json).as_json
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :request
|
18
|
+
|
19
|
+
class Request < AuthorizedRequest
|
20
|
+
def initialize(access_token, markdown)
|
21
|
+
self.access_token = access_token
|
22
|
+
self.markdown = markdown
|
23
|
+
end
|
24
|
+
|
25
|
+
def uri
|
26
|
+
URI(
|
27
|
+
"#{Stride.configuration.api_base_url}/pf-editor-service/convert?from=markdown&to=adf"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def params
|
32
|
+
{
|
33
|
+
input: markdown
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_accessor :markdown
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/stride/me.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Stride
|
2
|
+
class Me
|
3
|
+
attr_accessor :account_id, :name, :email, :picture
|
4
|
+
|
5
|
+
def self.fetch!(access_token)
|
6
|
+
new(MeRequest.new(access_token).json)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(json)
|
10
|
+
self.account_id = json['account_id']
|
11
|
+
self.name = json['name']
|
12
|
+
self.email = json['email']
|
13
|
+
self.picture = json['picture']
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
class MeRequest < AuthorizedRequest
|
19
|
+
def initialize(access_token)
|
20
|
+
self.access_token = access_token
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_accessor :cloud_id, :user_id
|
26
|
+
|
27
|
+
def uri
|
28
|
+
URI(
|
29
|
+
"#{Stride.configuration.api_base_url}/me"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def request_class
|
34
|
+
Net::HTTP::Get
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Stride
|
2
|
+
class Message
|
3
|
+
def initialize(access_token, cloud_id, conversation_id, message_body)
|
4
|
+
self.access_token = access_token
|
5
|
+
self.cloud_id = cloud_id
|
6
|
+
self.conversation_id = conversation_id
|
7
|
+
self.message_body = message_body
|
8
|
+
end
|
9
|
+
|
10
|
+
def send!
|
11
|
+
Request.new(access_token, cloud_id, conversation_id, message_body).json
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_accessor :access_token, :cloud_id, :conversation_id, :message_body
|
17
|
+
|
18
|
+
class Request < AuthorizedRequest
|
19
|
+
def initialize(access_token, cloud_id, conversation_id, message_body)
|
20
|
+
self.access_token = access_token
|
21
|
+
self.cloud_id = cloud_id
|
22
|
+
self.conversation_id = conversation_id
|
23
|
+
self.message_body = message_body
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_accessor :cloud_id, :conversation_id, :message_body
|
29
|
+
|
30
|
+
def uri
|
31
|
+
URI(
|
32
|
+
"#{Stride.configuration.api_base_url}/site/#{cloud_id}/conversation/#{conversation_id}/message"
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def params
|
37
|
+
message_body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Stride
|
2
|
+
class TextMessage
|
3
|
+
def initialize(access_token, cloud_id, conversation_id, message_text)
|
4
|
+
self.access_token = access_token
|
5
|
+
self.cloud_id = cloud_id
|
6
|
+
self.conversation_id = conversation_id
|
7
|
+
self.message_text = message_text
|
8
|
+
end
|
9
|
+
|
10
|
+
def send!
|
11
|
+
Message.new(access_token, cloud_id, conversation_id, message_body).send!
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_accessor :access_token, :cloud_id, :conversation_id, :message_text
|
17
|
+
|
18
|
+
def message_body
|
19
|
+
{
|
20
|
+
version: 1,
|
21
|
+
type: 'doc',
|
22
|
+
content: [
|
23
|
+
{
|
24
|
+
type: 'paragraph',
|
25
|
+
content: [
|
26
|
+
{
|
27
|
+
type: 'text',
|
28
|
+
text: message_text
|
29
|
+
}
|
30
|
+
]
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/stride/token.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Stride
|
2
|
+
class Token
|
3
|
+
attr_accessor :access_token, :refresh_time
|
4
|
+
|
5
|
+
def self.fetch!
|
6
|
+
new(Request.new.json)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(json)
|
10
|
+
self.access_token = json['access_token']
|
11
|
+
self.refresh_time = Time.now + json['expires_in']
|
12
|
+
end
|
13
|
+
|
14
|
+
def unexpired?
|
15
|
+
Time.now < refresh_time
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
class Request < BaseRequest
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def uri
|
25
|
+
@uri ||= URI(Stride.configuration.auth_api_base_url + '/oauth/token')
|
26
|
+
end
|
27
|
+
|
28
|
+
def params
|
29
|
+
{
|
30
|
+
grant_type: 'client_credentials',
|
31
|
+
client_id: Stride.configuration.client_id,
|
32
|
+
client_secret: Stride.configuration.client_secret,
|
33
|
+
audience: Stride.configuration.api_audience
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/stride/user.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Stride
|
2
|
+
class User
|
3
|
+
attr_accessor :id, :user_name, :active, :display_name, :emails, :meta, :photos
|
4
|
+
|
5
|
+
def initialize(json)
|
6
|
+
self.id = json['id']
|
7
|
+
self.user_name = json['userName']
|
8
|
+
self.active = json['active']
|
9
|
+
self.display_name = json['displayName']
|
10
|
+
self.emails = json['emails'].map { |email| Email.new(email['value'], email['primary']) }
|
11
|
+
self.meta = json['meta']
|
12
|
+
self.photos = json['photos'].map { |photo| Photo.new(photo['value'], photo['primary']) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.fetch!(access_token, cloud_id, user_id)
|
16
|
+
new(UserRequest.new(access_token, cloud_id, user_id).json)
|
17
|
+
end
|
18
|
+
|
19
|
+
def primary_email
|
20
|
+
emails.detect { |email| email.primary? }&.value
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
Email = Struct.new(:value, :primary) do
|
26
|
+
def primary?
|
27
|
+
primary
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Photo = Struct.new(:url, :primary) do
|
32
|
+
def primary?
|
33
|
+
primary
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class UserRequest < AuthorizedRequest
|
38
|
+
def initialize(access_token, cloud_id, user_id)
|
39
|
+
self.access_token = access_token
|
40
|
+
self.cloud_id = cloud_id
|
41
|
+
self.user_id = user_id
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_accessor :cloud_id, :user_id
|
47
|
+
|
48
|
+
def uri
|
49
|
+
URI(
|
50
|
+
"#{Stride.configuration.api_base_url}/scim/site/#{cloud_id}/Users/#{user_id}"
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def request_class
|
55
|
+
Net::HTTP::Get
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Stride
|
2
|
+
class UserMessage
|
3
|
+
def initialize(access_token, cloud_id, user_id, message_body)
|
4
|
+
self.access_token = access_token
|
5
|
+
self.cloud_id = cloud_id
|
6
|
+
self.user_id = user_id
|
7
|
+
self.message_body = message_body
|
8
|
+
end
|
9
|
+
|
10
|
+
def send!
|
11
|
+
UserInstallationRequest.new(access_token, cloud_id, user_id).json
|
12
|
+
Request.new(access_token, cloud_id, user_id, message_body).json
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :access_token, :cloud_id, :user_id, :message_body
|
18
|
+
|
19
|
+
class UserInstallationRequest < AuthorizedRequest
|
20
|
+
def initialize(access_token, cloud_id, user_id)
|
21
|
+
self.access_token = access_token
|
22
|
+
self.cloud_id = cloud_id
|
23
|
+
self.user_id = user_id
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_accessor :cloud_id, :user_id
|
29
|
+
|
30
|
+
def uri
|
31
|
+
URI(
|
32
|
+
"#{Stride.configuration.api_base_url}/site/#{cloud_id}/conversation/user/#{user_id}"
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_class
|
37
|
+
Net::HTTP::Get
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Request < AuthorizedRequest
|
42
|
+
def initialize(access_token, cloud_id, user_id, message_body)
|
43
|
+
self.access_token = access_token
|
44
|
+
self.cloud_id = cloud_id
|
45
|
+
self.user_id = user_id
|
46
|
+
self.message_body = message_body
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_accessor :cloud_id, :user_id, :message_body
|
52
|
+
|
53
|
+
def uri
|
54
|
+
URI(
|
55
|
+
"#{Stride.configuration.api_base_url}/site/#{cloud_id}/conversation/user/#{user_id}/message"
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def params
|
60
|
+
message_body
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/stride/version.rb
CHANGED
data/stride.gemspec
CHANGED
@@ -23,4 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.15"
|
24
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
25
|
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
spec.add_development_dependency "activesupport"
|
27
|
+
spec.add_development_dependency "webmock"
|
28
|
+
spec.add_development_dependency "pry"
|
26
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stride
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,48 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
55
97
|
description:
|
56
98
|
email:
|
57
99
|
- joncodes+github@gmail.com
|
@@ -61,7 +103,9 @@ extra_rdoc_files: []
|
|
61
103
|
files:
|
62
104
|
- ".gitignore"
|
63
105
|
- ".rspec"
|
106
|
+
- ".ruby-version"
|
64
107
|
- ".travis.yml"
|
108
|
+
- CHANGELOG.md
|
65
109
|
- CODE_OF_CONDUCT.md
|
66
110
|
- Gemfile
|
67
111
|
- LICENSE.txt
|
@@ -70,6 +114,22 @@ files:
|
|
70
114
|
- bin/console
|
71
115
|
- bin/setup
|
72
116
|
- lib/stride.rb
|
117
|
+
- lib/stride/atlassian_document_format_expander.rb
|
118
|
+
- lib/stride/authorized_request.rb
|
119
|
+
- lib/stride/base_request.rb
|
120
|
+
- lib/stride/bot_mention.rb
|
121
|
+
- lib/stride/client.rb
|
122
|
+
- lib/stride/configuration.rb
|
123
|
+
- lib/stride/conversation.rb
|
124
|
+
- lib/stride/conversation_roster.rb
|
125
|
+
- lib/stride/installation.rb
|
126
|
+
- lib/stride/markdown_document.rb
|
127
|
+
- lib/stride/me.rb
|
128
|
+
- lib/stride/message.rb
|
129
|
+
- lib/stride/text_message.rb
|
130
|
+
- lib/stride/token.rb
|
131
|
+
- lib/stride/user.rb
|
132
|
+
- lib/stride/user_message.rb
|
73
133
|
- lib/stride/version.rb
|
74
134
|
- stride.gemspec
|
75
135
|
homepage: https://github.com/bonusly/stride
|
@@ -92,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
152
|
version: '0'
|
93
153
|
requirements: []
|
94
154
|
rubyforge_project:
|
95
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.5.1
|
96
156
|
signing_key:
|
97
157
|
specification_version: 4
|
98
158
|
summary: Ruby wrapper for the Stride API
|