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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d80671a3dbded76f91c18e695619655ce13d9c5f
4
- data.tar.gz: '0038c0da7907c73851346844cdb4b4193c68cb33'
3
+ metadata.gz: aa8b67e12775bcb352e3dfe5d3559a5660886466
4
+ data.tar.gz: 6ce50f9338ad89bfb0afb17f829690765eb155aa
5
5
  SHA512:
6
- metadata.gz: 6cf477a98e648f45c0c1a58db4e129390aeb11b790c58e869aa4c04a4fcdc969e6e5eedad59284a87c8062e117aacb88ad70a8e3c787cf39a3303fb7a6c96ef1
7
- data.tar.gz: bbe022265510923399d63b67933ea84b48aa2a50c85433ed9d52a5ad6e46d09582d3ad7fff5bc95937c1f39aefccaa761de7698d21b4236feb1424cae1fe8021
6
+ metadata.gz: a943fe7c8dc7c1aa7de0dcbe12034f0573a63b7585e4c7bc0747fd1565e11dc3f3c8161d3e26d147b8a5afe2b14fcd341163b0a1cb93cf8ba054fa2c3894edc0
7
+ data.tar.gz: 895c2e375956d444995e033e1cdc61e8618a1ad66a2a6590178ec95d0985af3173179baa13cead0ca1afa4e4a9a05939c852e1b2d75c602cac745e238abae59b
@@ -0,0 +1 @@
1
+ 2.3.1
@@ -0,0 +1,7 @@
1
+ ## 0.1.1 (April 16, 2018)
2
+
3
+ Support passing in a permanent room token to `Client` instead of relying on OAuth.
4
+
5
+ ## 0.1.0
6
+
7
+ Initial release
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Stride
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stride`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Write usage instructions here
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
 
@@ -1,5 +1,28 @@
1
- require "stride/version"
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
- # Your code goes here...
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,14 @@
1
+ module Stride
2
+ class AuthorizedRequest < BaseRequest
3
+ private
4
+
5
+ attr_accessor :access_token
6
+
7
+ def headers
8
+ {
9
+ authorization: "Bearer #{access_token}",
10
+ 'content-type': 'application/json'
11
+ }
12
+ end
13
+ end
14
+ 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
@@ -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
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Stride
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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.0
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: 2017-10-04 00:00:00.000000000 Z
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.6.11
155
+ rubygems_version: 2.5.1
96
156
  signing_key:
97
157
  specification_version: 4
98
158
  summary: Ruby wrapper for the Stride API