gitter-api 0.1.0

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 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: []