gitter-api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3324810a0534c18ad4957d40b6b4cc97f52f424fdcf2a111f3ac0b3dcf41e5be
4
+ data.tar.gz: 90ae6c39f509fcd48b1c818b18ebb8eb58d3b3b71215d194e2d1bfcb49397596
5
+ SHA512:
6
+ metadata.gz: a211a4432bd3cbac69976e99f87a498778040b77277ab019c6bf6bae810a078cab5271801ae5718ed77ccd74b5e95f1855c845d141bd0a68022322feeb63d1bb
7
+ data.tar.gz: 3462797ccbd1771b6dd11df29d7689099d0365e2d22047223815d5a7b3115d8c09dafd15013c8397f78c4b3b775e35ee20da711b515f482a606472f6469baa67
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Nick LaMuro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,176 @@
1
+ gitter-api-ruby
2
+ ===============
3
+
4
+ A ruby client for the [gitter][] API.
5
+
6
+ Includes an `ActiveRecord`-like interface with models that are parsed from
7
+ the responses, as well as a lower level request/json-response interface.
8
+
9
+
10
+ Installation
11
+ ------------
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'gitter-api-ruby'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ ```console
22
+ $ bundle
23
+ ```
24
+
25
+ Or install it yourself as:
26
+
27
+ ```console
28
+ $ gem install gitter-api-ruby
29
+ ```
30
+
31
+
32
+ Usage
33
+ -----
34
+
35
+ ### Client Setup
36
+
37
+ The `Gitter::API::Client` is the main http component, and is in charge of auth
38
+ and configuration of the base endpoint.
39
+
40
+ In most cases, only a token is needed for the client instance:
41
+
42
+ ``` ruby
43
+ client = Gitter::API::Client.new :token => "1a2b3c4d5e6f7a8b9c0d"
44
+ ```
45
+
46
+ ### Configuration
47
+
48
+ There are a few tunables that can be configured globally, or for each instance
49
+ of `Gitter::API::Client`:
50
+
51
+ ``` ruby
52
+ Config.api_prefix
53
+ #=> "/v1"
54
+ Config.api_url
55
+ #=> "https://api.gitter.im"
56
+ Config.ssl_verify
57
+ #=> false
58
+
59
+ Config.api_prefix = "/api/v1"
60
+ client = Gitter::API::Client.new :api_uri => URI("http://localhost:4000")
61
+ client.api_prefix
62
+ #=> "/api/v1"
63
+ client.api_url
64
+ #=> "https://api.gitter.im"
65
+ client.ssl_verify
66
+ #=> false
67
+ ```
68
+
69
+ ### Making requests
70
+
71
+ `Gitter::API::Client` provides `ActiveRecord`-like response objects for each of
72
+ it's high level methods found on the client itself, as well as what is
73
+ available from the returned objects:
74
+
75
+ ```ruby
76
+ # Fetching the configured user:
77
+ client.user
78
+ #=> #<Gitter::API::User:0x00007ff49b293c01 ... >
79
+
80
+ # Fetch rooms/private chats for the configured user
81
+ client.user.rooms
82
+ client.rooms # equivalent with the above, but memoized to the client object
83
+ #=> #<Gitter::API::Room::Collection:0x00007ff49b293c02 ... >
84
+
85
+ # API Collections are Enumerable
86
+ client.rooms.map(&:uri)
87
+ #=> ["gitterHQ/sandbox", "gitterHQ/api"]
88
+
89
+ client.rooms.first
90
+ #=> #<Gitter::API::Room:0x00007ff49b293c03 ... >
91
+
92
+ # Advanced example:
93
+ #
94
+ # print the first 50 chars of the last 5 messages from each room
95
+ client.rooms.each do |room|
96
+ puts room.name
97
+ puts "-" * room.name.size
98
+
99
+ puts room.messages(:limit => 5).map {|msg| "@#{msg.user.username}: #{msg.text[0, 50]}..." }
100
+ puts
101
+ end
102
+ #=> gitterHQ/api
103
+ #=> ----------------
104
+ #=> @alice: Hey...
105
+ #=> @bob: Hi...
106
+ #=> @alice: I stole your identity...
107
+ #=> @bob: Oh... that isn't good...
108
+ #=> @bob: Good thing I am a fictional user, huh...
109
+ #=>
110
+ #=> gitterHQ/sandbox
111
+ #=> ------------
112
+ #=> ...
113
+ ```
114
+
115
+ Not everything is currently implemented by the client, but for everything else,
116
+ the raw `.get`, `.post`, and `.put` methods of the client are available to
117
+ execute requests on those missing endpoints:
118
+
119
+ ```ruby
120
+ # Note: `/v1/users/me` (plural form) is a dummy route... do not use
121
+ client.get "/v1/user/me"
122
+ #=> { "user" => "NickLaMuro", "id" => ... }
123
+
124
+ # Bulk "mark messages as read" for a particular room to reduce number of http
125
+ # requests
126
+ #
127
+ # https://developer.gitter.im/docs/user-resource#mark-unread-items-as-read
128
+ #
129
+ # (currently not a high level method for this, only for single messages)
130
+ room = client.rooms.first
131
+ msg_ids = room.unread_messages.map(&:id)
132
+ payload = { "chat" => msg_ids }
133
+ mark_read_uri = "/v1/user/#{client.user.id}/rooms/#{room.id}/unreadItems"
134
+
135
+ client.post mark_read_uri, payload
136
+ ```
137
+
138
+
139
+ ### Developer Setup
140
+
141
+ Clone as you would...
142
+
143
+ This plugin requires zero dependencies to work with (besides what is included
144
+ with ruby for a while now), so there is nothing required to install and get
145
+ setup.
146
+
147
+ However, to work with the gitter API, you will need on of two things:
148
+
149
+ - A local running copy of [gitter-webapp][]
150
+ - An API key from the public instance of [gitter][]
151
+
152
+ The first option has a pretty lengthy setup process, so that will not be
153
+ covered here, but a viable option if you don't want to make a mess of a
154
+ community room while doing your testing.
155
+
156
+ For the section option, it doesn't take much:
157
+
158
+ 1. Grab your API key from https://developer.gitter.im/apps
159
+ 2. Save it as a one line file in top level of this repo: `.gitter.token`
160
+ 3. Run `rake console`
161
+
162
+ From there, `client` is a configured `Gitter::API::Client` instance for you to
163
+ start testing with.
164
+
165
+
166
+ TODO
167
+ ----
168
+
169
+ - Implement missing top-level functions (user bans, leave rooms, etc.)
170
+ - Support app client keys (is this different at all?)
171
+ - Add integration tests (run a local copy of gitter)
172
+ - CI testing
173
+
174
+
175
+ [gitter]: https://gitter.im
176
+ [gitter-webapp]: https://gitlab.com/gitlab-org/gitter/webapp
data/lib/gitter/api.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'gitter/api/version'
2
+ require 'gitter/api/client'
3
+
4
+ module Gitter # :nodoc:
5
+ # = gitter-api-ruby
6
+ #
7
+ # A ruby gitter api client library
8
+ #
9
+ # == Classes
10
+ #
11
+ # See the below classes for more information.
12
+ #
13
+ # === Client
14
+ #
15
+ # * +Gitter::API::Client+
16
+ #
17
+ # === Models
18
+ #
19
+ # * +Gitter::API::User+
20
+ # * +Gitter::API::Room+
21
+ # * +Gitter::API::Message+
22
+ #
23
+ # :main:
24
+ #
25
+ module API
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ module Gitter
2
+ module API
3
+ # Base model that other +Gitter::API+ models inherit from
4
+ #
5
+ # See:
6
+ #
7
+ # - +Gitter::API::Message+
8
+ # - +Gitter::API::Room+
9
+ # - +Gitter::API::User+
10
+ #
11
+ class Base
12
+ # Configured client that fetched the record
13
+ #
14
+ # Used for subsequent calls (instance methods)
15
+ #
16
+ attr_reader :client
17
+
18
+ # All models should call this in their overrides, and configure their
19
+ # specific model attributes in the override from the +@data+ that was passed
20
+ # in.
21
+ #
22
+ # Note: +@data+ is set, but is not a formal accessor. Currently just
23
+ # available for debugging if needed.
24
+ #
25
+ def initialize client, data # :nodoc:
26
+ @client = client
27
+ @data = data
28
+ end
29
+
30
+ # Helper method for fetching the API prefix from the client
31
+ #
32
+ def api_prefix
33
+ client.api_prefix
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,121 @@
1
+ require "json"
2
+
3
+ require 'gitter/api/util/net_http_client'
4
+
5
+ require 'gitter/api/config'
6
+ require 'gitter/api/collectable'
7
+
8
+ # models
9
+ require 'gitter/api/base'
10
+ require 'gitter/api/user'
11
+ require 'gitter/api/room'
12
+ require 'gitter/api/message'
13
+
14
+ module Gitter
15
+ module API
16
+ # The +Gitter::API::Client+ is the main http component, and is in charge of auth
17
+ # and configuration of the base endpoint of the gitter API that is being
18
+ # connected to and interacted with.
19
+ #
20
+ # == Usage
21
+ #
22
+ # === Client Setup
23
+ #
24
+ # In most cases, only a token is needed for the client instance:
25
+ #
26
+ # client = Gitter::API::Client.new :token => "1a2b3c4d5e6f7a8b9c0d"
27
+ #
28
+ # === Example Queries
29
+ #
30
+ # Fetching the configured user:
31
+ #
32
+ # client.user
33
+ # #=> #<Gitter::API::User:0x00007ff49b293c01 ... >
34
+ #
35
+ # Fetch rooms/private chats for the configured user:
36
+ #
37
+ # client.rooms
38
+ # client.user.rooms # same as client.rooms, but is not memoized
39
+ # #=> #<Gitter::API::Room::Collection:0x00007ff49b293c02 ... >
40
+ #
41
+ # API Collections are Enumerable:
42
+ #
43
+ # client.rooms.map(&:uri)
44
+ # #=> ["gitterHQ/sandbox", "gitterHQ/api"]
45
+ #
46
+ # See individual model classes for more examples
47
+ #
48
+ #
49
+ # == Additional methods
50
+ #
51
+ # +Gitter::API::User+ and +Gitter::API::Room+ each provide methods that are
52
+ # included in the client as base methods. Refer to those classes for more
53
+ # info.
54
+ #
55
+ class Client
56
+
57
+ include Net::HTTP::RestClientModule
58
+
59
+ include User::ClientMethods
60
+ include Room::ClientMethods
61
+
62
+ # See Gitter::API::Config#api_uri
63
+ attr_reader :api_uri
64
+
65
+ # See Gitter::API::Config#api_prefix
66
+ attr_reader :api_prefix
67
+
68
+ # Client User API token
69
+ attr_reader :auth_token
70
+
71
+ # See Gitter::API::Config#ssl_verify
72
+ attr_reader :ssl_verify
73
+
74
+ # Set for +Net::HTTP::RestClientModule+
75
+ #
76
+ alias uri api_uri # :nodoc:
77
+
78
+ # Initialize a new +Gitter::API::Client+
79
+ #
80
+ # Aside from :token, all other options will be defaulted to what is
81
+ # configured in +Gitter::API::Config+
82
+ #
83
+ # See +Gitter::API::Config+ for defaults.
84
+ #
85
+ # ==== Options
86
+ #
87
+ # (symbol keys only)
88
+ #
89
+ # [*:token* (String)] (required) Auth token for the API client user
90
+ #
91
+ # [*:api_prefix* (String)] Path prefix for all API routes
92
+ # [*:api_uri* (URI)] Endpoint URI of the configured gitter API
93
+ # [*:ssl_verify* (Boolean)] Indicates if net/http should verify ssl certs
94
+ #
95
+ def initialize options = {}
96
+ @api_prefix = options[:api_prefix] || Config.api_prefix
97
+ @api_uri = options[:api_uri] || Config.api_uri
98
+ @auth_token = options[:token]
99
+ @ssl_verify = options.key? :ssl_verify ? options[:ssl_verify] : Config.ssl_verify
100
+ end
101
+
102
+ private
103
+
104
+ # Override of the default in Net::HTTP::RestClientModule
105
+ #
106
+ def response_builder response
107
+ JSON.parse response.body
108
+ end
109
+
110
+ # Override of the default in Net::HTTP::RestClientModule
111
+ #
112
+ def default_headers
113
+ @headers ||= {
114
+ "Accept" => "application/json",
115
+ "Content-Type" => "application/json",
116
+ "Authorization" => "Bearer #{auth_token}"
117
+ }
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,97 @@
1
+ module Gitter
2
+ module API
3
+ # = Gitter::API::Collectable
4
+ #
5
+ # This is a support module for Gitter::API models that allows for defining
6
+ # a subclass based on the included class that is a Enumberable collection
7
+ # of base class, in a similar vein to how ActiveRecord::Relation is used to
8
+ # represent a collection of ActiveRecord objects.
9
+ #
10
+ # Allows for initializing on a shared interface where only the +parent+ and
11
+ # +data+ blob (array of hash data objects for the given base record) need
12
+ # to be passed in.
13
+ #
14
+ # For models that have different initialization argument schema (e.g.
15
+ # Gitter::API::Message), this collectable_args can be defined on the
16
+ # included class that will override the args passed to +.new+ when
17
+ # instanciating each record in the collection.
18
+ #
19
+ # == Example Usage
20
+ #
21
+ # For Gitter::API::User, this is pretty straight forward:
22
+ #
23
+ # class Gitter::API::User
24
+ # include Collectable
25
+ # end
26
+ #
27
+ # But for Gitter::API::Message, since +room_id+ needs to be supplied for
28
+ # that class, it has `collectable_args` defined to support that when
29
+ # instanciating the collection.
30
+ #
31
+ # class Gitter::API::Message
32
+ # include Collectable
33
+ #
34
+ # def self.collectable_args parent, item_data # :nodoc:
35
+ # room_id = parent.respond_to? :room_id ? parent.room_id : nil
36
+ # [parent.client, room_id, item_data]
37
+ # end
38
+ # end
39
+ #
40
+ # So when each message is created it will receive +client+, +room_id+, and
41
+ # +data+ as arguments for each object instanciated instead of the default
42
+ # +client+ and +data+ only.
43
+ #
44
+ module Collectable # :nodoc: all
45
+
46
+ # Defines the following on the newly created sub class
47
+ #
48
+ # - .base_class
49
+ # - .initialize (new)
50
+ # - #collectable_args (used in initialize)
51
+ # - #each
52
+ # - #last
53
+ # - #parent (used in collectable_args)
54
+ #
55
+ def self.included base_class
56
+ collection_class = Class.new
57
+ collection_class.send :include, Enumerable
58
+ collection_class.instance_variable_set :@base_class, base_class
59
+
60
+ collection_class.module_eval <<-CLASS
61
+ def self.base_class
62
+ @base_class
63
+ end
64
+
65
+ def initialize parent, data
66
+ @parent = parent
67
+ @items = data.map do |item_data|
68
+ self.class.base_class.new *(collectable_args item_data)
69
+ end
70
+ end
71
+
72
+ def collectable_args item_data
73
+ if self.class.base_class.respond_to? :collectable_args
74
+ self.class.base_class.collectable_args parent, item_data
75
+ else
76
+ [parent.client, item_data]
77
+ end
78
+ end
79
+
80
+ def each
81
+ @items.each { |item| yield item }
82
+ end
83
+
84
+ def last
85
+ @items.last
86
+ end
87
+
88
+ def parent
89
+ @parent
90
+ end
91
+ CLASS
92
+
93
+ base_class.const_set :Collection, collection_class
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,85 @@
1
+ module Gitter
2
+ module API
3
+ # A singleton class for holding on to default values for the
4
+ # Gitter::API::Client for the given session.
5
+ #
6
+ # When making changes here, it will affect every Gitter::API::Client that
7
+ # is configured going forward, unless the values are changed on client
8
+ # instanciation via the config hash.
9
+ #
10
+ # == Tunable attributes
11
+ #
12
+ # - +api_prefix+
13
+ # - +api_url+
14
+ # - +ssl_verify+
15
+ #
16
+ #
17
+ class Config
18
+ # API prefix for production https://api.gitter.im ("/v1")
19
+ DEFAULT_API_PREFIX = "/v1"
20
+
21
+ # Default API URL ("https://api.gitter.im")
22
+ DEFAULT_API_URL = "https://api.gitter.im"
23
+
24
+ class << self
25
+ # Path prefix for API routes
26
+ #
27
+ # Generally in development (localhost), "/api/v1" should be used instead
28
+ # of the default ("/v1")
29
+ attr_accessor :api_prefix
30
+
31
+ # Endpoint URL for the Gitter API
32
+ attr_accessor :api_url
33
+
34
+ # Whether or not to verify SSL certs (default is +true+)
35
+ #
36
+ # Set to +false+ when using +localhost+ (development) since a local
37
+ # server most likely will not have valid https certs
38
+ attr_accessor :ssl_verify
39
+
40
+ # :doc:
41
+ # The prefix for the API endpoints (default: +/v1+)
42
+ #
43
+ # In development using a local gitter instance, it should be +/api/v1+,
44
+ # but in production it is just +/v1+
45
+ def api_prefix
46
+ @api_url || DEFAULT_API_PREFIX
47
+ end
48
+
49
+ # :doc:
50
+ # Endpoint URL for the Gitter API (default: "https://api.gitter.im")
51
+ #
52
+ # For local instances of +gitter-webapp+, the URL can then be set to
53
+ # +http://localhost:5000+.
54
+ #
55
+ def api_url
56
+ @api_url || DEFAULT_API_URL
57
+ end
58
+
59
+ # :doc:
60
+ # Reset the reference for @api_url
61
+ #
62
+ # Also clears the cache for +@api_uri+
63
+ #
64
+ def api_url= url
65
+ @api_url = url
66
+ @api_uri = nil # clear @api_uri cache when @api_url is set
67
+ end
68
+
69
+ # :doc:
70
+ # URI object cache of the api_url
71
+ #
72
+ def api_uri
73
+ @api_uri ||= URI(api_url)
74
+ end
75
+
76
+ # :doc:
77
+ # If the base endpoint should verify SSL cert (default: true)
78
+ #
79
+ def ssl_verify
80
+ @ssl_verify || true
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,136 @@
1
+ module Gitter
2
+ module API
3
+ # Model representation of the +/room/:room_id/chatMessages*+ REST endpoints
4
+ # in the gitter API
5
+ #
6
+ class Message < Base
7
+ include Collectable
8
+
9
+ # See Gitter::API::Collectable
10
+ #
11
+ def self.collectable_args parent, item_data # :nodoc:
12
+ room_id = parent.respond_to? :room_id ? parent.room_id : nil
13
+
14
+ [parent.client, room_id, item_data]
15
+ end
16
+
17
+ # Message id (from gitter)
18
+ attr_reader :id
19
+
20
+ # +Gitter::API::User+ that sent the message
21
+ attr_reader :user
22
+
23
+ # Original message in plain-text/markdown
24
+ attr_reader :text
25
+
26
+ # HTML formatted message (formatted on the API server)
27
+ attr_reader :html
28
+
29
+ # Indicates if the message has been read by the client user
30
+ attr_reader :unread
31
+
32
+ # Number of users that have read the message
33
+ attr_reader :read_by
34
+
35
+ # ISO formatted date of when the message originally sent
36
+ attr_reader :created_at
37
+
38
+ # ISO formatted data of when the message was edited last (if it has been)
39
+ attr_reader :updated_at
40
+
41
+ # List of +Gitter::API::User+ mentioned in the message
42
+ attr_reader :mentions
43
+
44
+ # List of github issues referened in the message
45
+ attr_reader :issues
46
+
47
+ # List of URLs present in the message
48
+ attr_reader :urls
49
+
50
+ # *INTERNAL* *METHOD*
51
+ #
52
+ # Initialize a new +Gitter::API::Message+
53
+ #
54
+ # Used by +Gitter::API::Room+ when fetching messages, so favor using that
55
+ # instead.
56
+ #
57
+ # ==== Parameters
58
+ #
59
+ # *Note:* messages in the Gitter schema don't have a `room_id`, so that
60
+ # is passed in as an additional arg here.
61
+ #
62
+ # [*client* (Gitter::API::Client)] Configured client object
63
+ # [*room_id* (String)] Room ID message came from
64
+ # [*data* (Hash)] Initialization data
65
+ #
66
+ # ==== Options
67
+ #
68
+ # (string keys only)
69
+ #
70
+ # [*id* (String)] Message id
71
+ # [*user* (String)] +Gitter::API::User+ that sent the message
72
+ # [*text* (String)] Original message in plain-text/markdown
73
+ # [*html* (String)] HTML formatted message
74
+ # [*unread* (Boolean)] Indicates if current user has read the message
75
+ # [*read_by* (Integer)] Number of users that have read the message
76
+ # [*created_at* (Date)] ISO formatted date of the message
77
+ # [*updated_at* (Date)] ISO formatted date of the message if edited
78
+ # [*mentions* (Array<User>)] +Gitter::API::User+(s) mentioned in message
79
+ # [*issues* (Array<String>)] List of #Issues referenced in the message
80
+ # [*urls* (Array<String>)] List of URLs present in message
81
+ #
82
+ def initialize client, room_id, data
83
+ super client, data
84
+
85
+ @room_id = room_id
86
+
87
+ @id = data["id"]
88
+ @user = User.new client, data["fromUser"]
89
+ @text = data["text"]
90
+ @html = data["html"]
91
+ @unread = data["unread"]
92
+
93
+ @read_by = data["readBy"]
94
+ @created_at = data["sent"]
95
+ @updated_at = data["editedAt"]
96
+
97
+ @mentions = data["mentions"].map { |user| User.new client, user }
98
+ @issues = data["issues"]
99
+ @urls = data["urls"]
100
+ end
101
+
102
+ # Edit/update a Message's text
103
+ #
104
+ # The html will be reformated on the server, and returned as part of the
105
+ # +data+ when returned.
106
+ #
107
+ # A new instance of Gitter::API::Message is the turn value
108
+ #
109
+ # :return: Gitter::API::Message
110
+ #
111
+ # ==== Parameters
112
+ #
113
+ # [*text* (String)] New text to update the message record to
114
+ #
115
+ def update text
116
+ payload = { "text" => message }.to_json
117
+ data = client.post "#{api_prefix}/rooms/#{room_id}/chatMessages/#{id}", payload
118
+
119
+ new client, room_id, data
120
+ end
121
+
122
+ # Mark the message as read for the client user
123
+ #
124
+ # :return: true
125
+ #
126
+ def mark_as_read
127
+ payload = { "chat" => [id] }.to_json
128
+ path = "/#{api_prefix}/user/#{client.user.id}/rooms/#{room_id}/unreadItems"
129
+
130
+ client.post path, payload
131
+
132
+ true
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,267 @@
1
+ module Gitter
2
+ module API
3
+ # Model representation of the +/room/:room_id/*+ REST endpoints in the
4
+ # gitter API
5
+ #
6
+ class Room < Base
7
+ include Collectable
8
+
9
+ # Room id
10
+ attr_reader :id
11
+
12
+ # Room name
13
+ attr_reader :name
14
+
15
+ # Room topic
16
+ attr_reader :topic
17
+
18
+ # Indicates if the room is a one on one chat
19
+ attr_reader :one_on_one
20
+
21
+ # Indicates if the room is configured with notifications for the user
22
+ attr_reader :lurk
23
+
24
+ # Indicates if the room is public
25
+ attr_reader :public
26
+
27
+ # Number of unread mentions for this room
28
+ attr_reader :mentions
29
+
30
+ # Number of users in the room
31
+ attr_reader :user_count
32
+
33
+ # Number of unread messages for this room
34
+ attr_reader :unread_items
35
+
36
+ # Array of tags for the room
37
+ attr_reader :tags
38
+
39
+ # Room URI on gitter
40
+ attr_reader :uri
41
+
42
+ # Room url
43
+ attr_reader :url
44
+
45
+ # Used by Collectable
46
+ alias room_id id # :nodoc:
47
+
48
+ # Find a room given a URI
49
+ #
50
+ # See Gitter::API::Room::ClientMethods#find_room
51
+ #
52
+ # ==== Parameters
53
+ #
54
+ # [*uri* (String)] Room URI on Gitter
55
+ #
56
+ # ==== Example
57
+ #
58
+ # client.find "gitterhq/sandbox"
59
+ # #=> <#Gitter::API::Room name="gitterhq/sandbox" ...>
60
+ #
61
+ # :return: Gitter::API::Room
62
+ #
63
+ def self.find uri
64
+ Client.find_room uri
65
+ end
66
+
67
+ # *INTERNAL* *METHOD*
68
+ #
69
+ # Initialize a new Gitter::API::Room
70
+ #
71
+ # Use Gitter::API::Room::ClientMethods (found of Gitter::API::Client) to
72
+ # initialize and make use of the instance methods.
73
+ #
74
+ # ==== Parameters
75
+ #
76
+ # [*client* (Gitter::API::Client)] Configured client object
77
+ # [*data* (Hash)] Initialization data
78
+ #
79
+ # ==== Options
80
+ #
81
+ # (string keys only)
82
+ #
83
+ # [*id* (String)] Room id
84
+ # [*name* (String)] Room name
85
+ # [*topic* (String)] Room topic
86
+ # [*one_on_one* (Boolean)] Indicates if one on one chat
87
+ # [*lurk* (Boolean)] Indicates if notifications disabled
88
+ # [*public* (Boolean)] Indicates if public room
89
+ # [*unread_items* (Integer)] Number of unread messages
90
+ # [*mentions* (Integer)] Number of unread mentions
91
+ # [*user_count* (Integer)] Number of users in the room
92
+ # [*tags* (Array<String>)] Tags that define the room
93
+ # [*uri* (String)] Room URI on Gitter
94
+ # [*url* (String)] Path to the room on gitter
95
+ #
96
+ def initialize client, data
97
+ super
98
+
99
+ @id = data["id"]
100
+ @name = data["name"]
101
+ @topic = data["topic"]
102
+ @one_on_one = data["oneOnOne"]
103
+ @lurk = data["lurk"]
104
+ @public = data["public"]
105
+ @mentions = data["mentions"]
106
+ @user_count = data["userCount"]
107
+ @unread_items = data["unreadItems"]
108
+ @tags = data["tags"]
109
+ @uri = data["uri"]
110
+ @url = data["url"]
111
+ end
112
+
113
+ # List users of a room
114
+ #
115
+ # ==== Options
116
+ #
117
+ # [*:search* (String)] Filter based on search query
118
+ # [*:limit* (Integer)] Limit number of records returned
119
+ # [*:skip* (Integer)] Return users after skiping N records
120
+ #
121
+ # :return: Gitter::API::User::Collection
122
+ #
123
+ def users options = {}
124
+ query = {
125
+ "skip" => options[:skip],
126
+ "limit" => options[:limit],
127
+ "q" => options[:search]
128
+ }
129
+
130
+ data = client.get "/#{api_prefix}/rooms/#{id}/users", query
131
+
132
+ User::Collection.new self, data
133
+ end
134
+
135
+ # List recent messages of a room
136
+ #
137
+ # ==== Options
138
+ #
139
+ # [*:search* (String)] Filter based on search query
140
+ # [*:before* (String)] Limit messages to before a date
141
+ # [*:after* (String)] Limit messages to after a date
142
+ # [*:around* (String)] Limit messages to around a date
143
+ # [*:limit* (Integer)] Limit number of records returned
144
+ # [*:skip* (Integer)] Return users after skiping N records
145
+ #
146
+ # Returns a collection of most recent messages, with the oldest of that
147
+ # collection being first in the returned list.
148
+ #
149
+ # :return: Gitter::API::User::Collection
150
+ #
151
+ def messages options = {}
152
+ query = {
153
+ "skip" => options[:skip],
154
+ "beforeId" => options[:before],
155
+ "afterId" => options[:after],
156
+ "aroundId" => options[:around],
157
+ "limit" => options[:limit],
158
+ "q" => options[:search]
159
+ }
160
+
161
+ data = client.get "/v1/rooms/#{id}/chatMessages", query
162
+
163
+ Message::Collection.new self, data
164
+ end
165
+
166
+ # Join the current room
167
+ #
168
+ # :return: Gitter::API::Room
169
+ #
170
+ def join
171
+ payload = { "id" => id }.to_json
172
+ data = client.post "#{api_prefix}/user/#{client.user.id}/rooms", payload
173
+
174
+ self
175
+ end
176
+
177
+ # Send a message to the current room
178
+ #
179
+ # ==== Parameters
180
+ #
181
+ # [*message* (String)] Message to send to the room
182
+ #
183
+ # Messages should be in plain text/mardown format, and will be converted
184
+ # to html on the server side.
185
+ #
186
+ # :return: Gitter::API::Message
187
+ #
188
+ def send_message message
189
+ payload = { "text" => message }.to_json
190
+ data = client.post "#{api_prefix}/rooms/#{id}/chatMessages", payload
191
+
192
+ Message.new client, id, data
193
+ end
194
+
195
+ # Unread messages in the room for the current user
196
+ #
197
+ # :return: Gitter::API::Message::Collection
198
+ #
199
+ def unread_messages
200
+ data = client.get "#{api_prefix}/user/#{client.user.id}/rooms/#{id}/unreadItems"
201
+
202
+ Message::Collection.new self, data
203
+ end
204
+
205
+ # +Gitter::API::Room+ based methods that are available on any
206
+ # +Gitter::API::Client+ instance
207
+ #
208
+ module ClientMethods
209
+ # Memoized version of User#rooms for the api client user
210
+ #
211
+ # ==== Parameters
212
+ #
213
+ # [*refresh* (Boolean)] set to true refresh memoization
214
+ #
215
+ # :return: Gitter::API::Room::Collection
216
+ #
217
+ def rooms refresh = false
218
+ return @rooms unless @rooms.nil? || refresh
219
+
220
+ @rooms = user.rooms
221
+ end
222
+
223
+ # Find a room based off of uri
224
+ #
225
+ # ==== Parameters
226
+ #
227
+ # [*uri* (String)] Room URI on Gitter
228
+ #
229
+ # ==== Example
230
+ #
231
+ # client.join_room "gitterhq/sandbox"
232
+ # #=> <#Gitter::API::Room name="gitterhq/sandbox" ...>
233
+ #
234
+ # :return: Gitter::API::Room
235
+ #
236
+ def find_room uri
237
+ payload = { "uri" => uri }.to_json
238
+ data = self.post "#{api_prefix}/rooms", payload
239
+
240
+ Room.new(self, data)
241
+ end
242
+
243
+ # Join a room from the top level client using the api user
244
+ #
245
+ # ==== Parameters
246
+ #
247
+ # [*uri* (String)] Room URI on Gitter
248
+ #
249
+ # ==== Example
250
+ #
251
+ # client.join_room "gitterhq/sandbox"
252
+ # #=> <#Gitter::API::Room name="gitterhq/sandbox" ...>
253
+ #
254
+ # :return: Gitter::API::Room
255
+ #
256
+ def join_room uri
257
+ has_room = rooms.detect { |room| room.uri == uri }
258
+
259
+ return has_room if has_room
260
+
261
+ @rooms = nil # clear rooms cache
262
+ self.class.find_room(uri).join
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,78 @@
1
+ module Gitter
2
+ module API
3
+ # Model representation of the +/user/*+ REST endpoints in the gitter API
4
+ #
5
+ class User < Base
6
+ include Collectable
7
+
8
+ # ID (from the API)
9
+ attr_reader :id
10
+
11
+ # Name of the user
12
+ attr_reader :display_name
13
+
14
+ # Username (minus the '@')
15
+ attr_reader :username
16
+
17
+ # The relative path the the user's page in the gitter webapp
18
+ attr_reader :url
19
+
20
+ # *INTERNAL* *METHOD*
21
+ #
22
+ # Initialize a new +Gitter::API::User+
23
+ #
24
+ # <tt>Gitter::API::Client#user</tt> will return on of these objects, as
25
+ # well as some methods on +Gitter::API::Room+ and when instanciating a
26
+ # +Gitter::API::Message+, so favor instanciating that way.
27
+ #
28
+ # ==== Parameters
29
+ #
30
+ # [*client* (Gitter::API::Client)] Configured client object
31
+ # [*data* (Hash)] Initialization data
32
+ #
33
+ # ==== Options
34
+ #
35
+ # (string keys only)
36
+ #
37
+ # [*id* (String)] User id
38
+ # [*display_name* (String)] Gitter/GitHub user real name
39
+ # [*username* (String)] Gitter/GitHub username (without '@')
40
+ # [*url* (String)] Path to the user on Gitter
41
+ #
42
+ def initialize client, data
43
+ super
44
+
45
+ @id = data["id"] || data["userId"]
46
+ @display_name = data["displayName"]
47
+ @username = data["username"] || data["screenName"]
48
+ @url = data["url"]
49
+ end
50
+
51
+ # Fetch the all of the room records for a given user
52
+ #
53
+ # Includes one on one conversations, since those are considered "rooms"
54
+ # as well (based on their schema)
55
+ #
56
+ # Returns a Gitter::API::Room::Collection
57
+ def rooms
58
+ data = client.get "#{api_prefix}/rooms"
59
+
60
+ Room::Collection.new self, data
61
+ end
62
+
63
+ # +Gitter::API::User+ based methods that are available on any
64
+ # +Gitter::API::Client+ instance
65
+ module ClientMethods
66
+ # Fetch the configured user
67
+ #
68
+ # Returns a Gitter::API::User instance
69
+ def user refresh = false
70
+ return @user unless @user.nil? || refresh
71
+
72
+ data = get "#{api_prefix}/user/me"
73
+ @user = User.new self, data
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,148 @@
1
+ require "net/http"
2
+
3
+ module Net # :nodoc:
4
+ class HTTP # :nodoc:
5
+ # == Net::HTTP::RestClientModule
6
+ #
7
+ # A wrapper library for NetHTTP to create a simplistic "Rest Client" class
8
+ #
9
+ # Simply `include Net::HTTP::RestClientModule` into a class, and make sure
10
+ # on initialization a `uri` method/accessor with a `URI` object is created.
11
+ #
12
+ # class MyRestClient
13
+ # include Net::HTTP::RestClientModule
14
+ #
15
+ # attr_accessor :uri
16
+ #
17
+ # def initialize
18
+ # @uri = URI("http://example.com")
19
+ # end
20
+ #
21
+ # # override this if needed, otherewise true by default
22
+ # def ssl_verify
23
+ # !!ENV["SHOULD_SSL_VERIFY"]
24
+ # end
25
+ # end
26
+ #
27
+ # # calling
28
+ # MyRestClient.new.get "/foo/bar"
29
+ # MyRestClient.new.post "/foo/bar"
30
+ # MyRestClient.new.put "/foo/bar"
31
+ #
32
+ #--
33
+ #
34
+ # TODO: Make query_params a little more generic
35
+ # TODO: Create a gem for this simple lib
36
+ #
37
+ module RestClientModule
38
+
39
+ # +Net::HTTP+ Connection object for the client object
40
+ #
41
+ # Will conigure it based off of the +uri+ method/accessor of current
42
+ # instance if one has not been instanciated yet.
43
+ #
44
+ def connection
45
+ return @connection if defined? @connection
46
+
47
+ verify_ssl = respond_to?(:ssl_verify) ? ssl_verify : true
48
+
49
+ @connection = Net::HTTP.new(uri.host, uri.port)
50
+ @connection.use_ssl = true if uri.scheme == "https"
51
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_NONE unless verify_ssl
52
+
53
+ @connection
54
+ end
55
+
56
+ # Send a +GET+ request to the configured +connection+
57
+ #
58
+ # ==== Parameters
59
+ #
60
+ # [*path* (String)] URL path for the request
61
+ # [*query_params* (Hash)] Query params to add to the path
62
+ # [*request_headers* (Hash)] Request specific headers
63
+ #
64
+ def get path, query_params = {}, request_headers = {}
65
+ if query_params.delete_if { |_,v| v.nil? }.empty?
66
+ get_uri = path
67
+ else
68
+ uri_class = uri.scheme == "https" ? URI::HTTPS : URI::HTTP
69
+ get_uri = uri_class.build :host => uri.host,
70
+ :path => path,
71
+ :query => URI.encode_www_form(query_params)
72
+ end
73
+
74
+ get_headers = headers request_headers
75
+ get_request = Net::HTTP::Get.new get_uri, get_headers
76
+
77
+ connection_do get_request
78
+ end
79
+
80
+ # Send a +POST+ request to the configured +connection+
81
+ #
82
+ # ==== Parameters
83
+ #
84
+ # [*path* (String)] URL path for the request
85
+ # [*payload* (Hash)] Request body
86
+ # [*request_headers* (Hash)] Request specific headers
87
+ #
88
+ def post path, payload, request_headers = {}
89
+ post_headers = headers request_headers
90
+ post_request = Net::HTTP::Post.new path, post_headers
91
+ post_request.body = payload
92
+
93
+ connection_do post_request
94
+ end
95
+
96
+ # Send a +PUT+ request to the configured +connection+
97
+ #
98
+ # ==== Parameters
99
+ #
100
+ # [*path* (String)] URL path for the request
101
+ # [*payload* (Hash)] Request body
102
+ # [*request_headers* (Hash)] Request specific headers
103
+ #
104
+ def put path, payload, request_headers = {}
105
+ put_headers = headers request_headers
106
+ put_request = Net::HTTP::Put.new path, put_headers
107
+ put_request.body = payload
108
+
109
+ connection_do put_request
110
+ end
111
+
112
+ private
113
+
114
+ # Helper for executing a request and building a response
115
+ def connection_do req
116
+ # puts "connection_do: #{req.method} #{req.path}" # debugging...
117
+ response = connection.start {|http| http.request req }
118
+ response_builder response
119
+ end
120
+
121
+ # Helper for building headers for a request
122
+ def headers request_headers = {}
123
+ default_headers.dup.merge request_headers
124
+ end
125
+
126
+ # :doc:
127
+ #
128
+ # Format and return a response
129
+ #
130
+ # Default return value is the +Net::HTTP::Request+ body, but the
131
+ # +response_builder+ method can be overwritten to configure out the data
132
+ # for a request is returned
133
+ def response_builder response
134
+ response.body
135
+ end
136
+
137
+ # :doc:
138
+ #
139
+ # Default headers for each request
140
+ #
141
+ # Can be overwritten in the included class to allow for specific headers
142
+ # to be added to every request (Auth headers, Accept headers, etc.)
143
+ def default_headers
144
+ {}
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,5 @@
1
+ module Gitter
2
+ module API
3
+ VERSION = "0.1.0" # :nodoc:
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitter-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick LaMuro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ description: |
42
+ A ruby client for the gitter (https://gitter.im) API.
43
+
44
+ Includes an `ActiveRecord`-like interface with models that are parsed from
45
+ the responses, as well as a lower level request/json-response interface.
46
+ email:
47
+ - nicklamuro@gmail.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - LICENSE.txt
53
+ - README.md
54
+ - lib/gitter/api.rb
55
+ - lib/gitter/api/base.rb
56
+ - lib/gitter/api/client.rb
57
+ - lib/gitter/api/collectable.rb
58
+ - lib/gitter/api/config.rb
59
+ - lib/gitter/api/message.rb
60
+ - lib/gitter/api/room.rb
61
+ - lib/gitter/api/user.rb
62
+ - lib/gitter/api/util/net_http_client.rb
63
+ - lib/gitter/api/version.rb
64
+ homepage: https://github.com/NickLaMuro/gitter-api-ruby
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 3.0.3
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: An(other) Ruby API client for Gitter
87
+ test_files: []