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