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 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