matrix_sdk 0.0.2 → 0.0.3

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
  SHA256:
3
- metadata.gz: 6d0b5d000dfb07e1f488a66587a403c087c7056b2cde52cd2ee87e4835972a23
4
- data.tar.gz: 1fdd6f7a913b42cf8654eeed0b198d14337f47ab7da71baf43c1b2779d752eb5
3
+ metadata.gz: fc787a1c2e4bac79cf05357500571df2e7734464023a5182d08614b9e45e9aac
4
+ data.tar.gz: 465ea39af281892dcb299014b8a5b4bc0c869f6914974f40cb6fd21301090129
5
5
  SHA512:
6
- metadata.gz: 466f80ee4d8b06c1827de39e7526a23e62e654db99c2102db5552492992a58fd6f6a4883d1c90d2a577c345d67312de51d5cbdb0a2bfbcab461278141dffcbc4
7
- data.tar.gz: 189b5b6243fb574b60ac02036850bfe33f20499b4a88ea9840491892f840fd367167be5233da73e08811d6d8721523bce9027e4907ea6c927a9c70a8c1ed20cc
6
+ metadata.gz: a18893ee520aedfacc011cf5888b310875ee6929fa94967a0eeee01e91d592a56b19b190e6400e5e9338ccf477f9ac4cb1c480866fb720c1eecee7f0fb005a6f
7
+ data.tar.gz: ed1d6b9eaad9795147ffb8bf319c4fed25598147a2af2f97048eb0285684c32fc7809e36ad891917f3499105778eb11409d8577941258c9fb94cee84b4c41dbd
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,33 @@
1
+ ---
2
+ image: "ruby:2.4"
3
+
4
+ # Cache gems in between builds
5
+ cache:
6
+ paths:
7
+ - vendor/ruby
8
+
9
+ before_script:
10
+ - gem install bundler --no-ri --no-rdoc
11
+ - bundle install -j $(nproc) --path vendor
12
+
13
+ rubocop:
14
+ before_script: []
15
+ script:
16
+ - gem install rubocop --no-ri --no-rdoc
17
+ - rubocop
18
+
19
+ # rspec:
20
+ # script:
21
+ # - rspec spec
22
+
23
+ pages:
24
+ stage: deploy
25
+ before_script: []
26
+ script:
27
+ - gem install yard
28
+ - yard doc -o public/
29
+ artifacts:
30
+ paths:
31
+ - public/
32
+ only:
33
+ - master
data/.rubocop.yml CHANGED
@@ -8,6 +8,9 @@ AllCops:
8
8
  Style/Documentation:
9
9
  Enabled: false
10
10
 
11
+ Metrics/ClassLength:
12
+ Enabled: false
13
+
11
14
  Metrics/MethodLength:
12
15
  Max: 40
13
16
 
data/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ ## v0.0.3 - 2018-08-14
2
+
3
+ - Adds missing accessors for HTTP timeout
4
+ - Adds methods for checking auth status to client API
5
+ - Adds a wrapper class for API responses to ease use
6
+ - Adds option (and defaults) to store login details on registration
7
+ - Allows creating a MatrixSdk::Client off of an existing MatrixSdk::Api
8
+ - Extends event handling
9
+
10
+ - Fixes batch handling in sync
11
+ - Fixes event handling in the sample
12
+ - Removes unimplemented API methods to avoid confusion
13
+
14
+ - Plenty of documentation work
15
+
16
+ ## v0.0.2 - 2018-05-11
17
+
18
+ - Fixes for multiple issues discovered after initial release
19
+ - Adds additional API methods
20
+ - Higher-level client API gets room and user abstractions
21
+
22
+ ## v0.0.1 - 2018-05-06
23
+
24
+ Initial release
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  A Ruby gem for easing the development of software that communicates with servers implementing the Matrix protocol.
4
4
 
5
+ Live YARD documentation can be found at; http://aleol57.gitlab-pages.liu.se/ruby-matrix-sdk
5
6
 
6
7
  ## Example usage
7
8
 
@@ -11,7 +11,7 @@ class SimpleClient < MatrixSdk::Client
11
11
  end
12
12
 
13
13
  def add_listener(room)
14
- room.on_event { |ev| on_message(room, ev) }
14
+ room.on_event.add_handler { |ev| on_message(room, ev) }
15
15
  end
16
16
 
17
17
  def run
@@ -26,20 +26,22 @@ class SimpleClient < MatrixSdk::Client
26
26
  end
27
27
 
28
28
  def on_message(room, event)
29
- puts "Event: #{ev}"
30
- case ev[:type]
29
+ case event.type
31
30
  when 'm.room.member'
32
- puts "#{Time.now.strftime '%H:%M'} #{event[:content][:displayname]} joined." if event['membership'] == 'join'
31
+ puts "[#{Time.now.strftime '%H:%M'}] #{event[:content][:displayname]} joined." if event.membership == 'join'
33
32
  when 'm.room.message'
34
- user = get_user event[:sender]
35
- admin_level = get_user_level(room, user.id)
36
- prefix = (admin_level >= 100 ? '@' : (admin_level >= 50 ? '+' : ' '))
37
- if %w[m.text m.notice].include? event[:content][:msgtype]
38
- puts "#{Time.now.strftime '%H:%M'} <#{prefix}#{user.display_name}> #{event[:content][:body]}"
33
+ user = get_user event.sender
34
+ admin_level = get_user_level(room, user.id) || 0
35
+ prefix = ' '
36
+ prefix = '+' if admin_level >= 50
37
+ prefix = '@' if admin_level >= 100
38
+ if %w[m.text m.notice].include? event.content[:msgtype]
39
+ notice = event.content[:msgtype] == 'm.notice'
40
+ puts "[#{Time.now.strftime '%H:%M'}] <#{prefix}#{user.display_name}> #{"\033[1;30m" if notice}#{event.content[:body]}#{"\033[0m" if notice}"
39
41
  elsif event[:content][:msgtype] == 'm.emote'
40
- puts "#{Time.now.strftime '%H:%M'} *#{prefix}#{user.display_name} #{event[:content][:body]}"
42
+ puts "[#{Time.now.strftime '%H:%M'}] *#{prefix}#{user.display_name} #{event.content[:body]}"
41
43
  else
42
- puts "#{Time.now.strftime '%H:%M'} <#{prefix}#{user.display_name}> [#{event[:content][:msgtype]}] #{event[:content][:body]} - #{api.get_download_url event[:content][:url]}"
44
+ puts "[#{Time.now.strftime '%H:%M'}] <#{prefix}#{user.display_name}> (#{event.content[:msgtype]}) #{event.content[:body]} - #{api.get_download_url event.content[:url]}"
43
45
  end
44
46
  end
45
47
  end
@@ -54,6 +56,7 @@ if $PROGRAM_NAME == __FILE__
54
56
  end
55
57
 
56
58
  client = SimpleClient.new ARGV.first
59
+ ARGV.shift
57
60
 
58
61
  print 'Username: '
59
62
  user = STDIN.gets.strip
@@ -87,7 +90,9 @@ if $PROGRAM_NAME == __FILE__
87
90
  room.send_text msg
88
91
  end
89
92
  end
93
+ rescue Interrupt
94
+ puts 'Interrupted, exiting...'
90
95
  ensure
91
- client.logout if client
96
+ client.logout if client && client.logged_in?
92
97
  end
93
98
  end
@@ -7,14 +7,31 @@ require 'uri'
7
7
 
8
8
  module MatrixSdk
9
9
  class Api
10
- attr_accessor :access_token, :device_id
11
- attr_reader :homeserver, :validate_certificate
12
-
13
- ignore_inspect :access_token
14
-
10
+ USER_AGENT = "Ruby Matrix SDK v#{MatrixSdk::VERSION}".freeze
11
+ DEFAULT_HEADERS = {
12
+ 'accept' => 'application/json',
13
+ 'user-agent' => USER_AGENT
14
+ }.freeze
15
+
16
+ attr_accessor :access_token, :device_id, :autoretry, :global_headers
17
+ attr_reader :homeserver, :validate_certificate, :read_timeout
18
+
19
+ ignore_inspect :access_token, :logger
20
+
21
+ # @param homeserver [String,URI] The URL to the Matrix homeserver, without the /_matrix/ part
22
+ # @param params [Hash] Additional parameters on creation
23
+ # @option params [String] :access_token The access token to use for the connection
24
+ # @option params [String] :device_id The ID of the logged in decide to use
25
+ # @option params [Boolean] :autoretry (true) Should requests automatically be retried in case of rate limits
26
+ # @option params [Boolean] :validate_certificate (false) Should the connection require valid SSL certificates
27
+ # @option params [Integer] :transaction_id (0) The starting ID for transactions
28
+ # @option params [Numeric] :backoff_time (5000) The request backoff time in milliseconds
29
+ # @option params [Numeric] :read_timeout (240) The timeout in seconds for reading responses
30
+ # @option params [Hash] :global_headers Additional headers to set for all requests
31
+ # @option params [Boolean] :skip_login Should the API skip logging in if the HS URL contains user information
15
32
  def initialize(homeserver, params = {})
16
33
  @homeserver = homeserver
17
- @homeserver = URI.parse(@homeserver.to_s) unless @homeserver.is_a? URI
34
+ @homeserver = URI.parse("#{'https://' unless @homeserver.start_with? 'http'}#{@homeserver}") unless @homeserver.is_a? URI
18
35
  if @homeserver.path.end_with? '_matrix/'
19
36
  @homeserver.path = begin
20
37
  split = @homeserver.path.rpartition '_matrix/'
@@ -26,24 +43,41 @@ module MatrixSdk
26
43
 
27
44
  @access_token = params.fetch(:access_token, nil)
28
45
  @device_id = params.fetch(:device_id, nil)
46
+ @autoretry = params.fetch(:autoretry, true)
29
47
  @validate_certificate = params.fetch(:validate_certificate, false)
30
48
  @transaction_id = params.fetch(:transaction_id, 0)
31
49
  @backoff_time = params.fetch(:backoff_time, 5000)
50
+ @read_timeout = params.fetch(:read_timeout, 240)
51
+ @global_headers = DEFAULT_HEADERS.dup
52
+ @global_headers.merge!(params.fetch(:global_headers)) if params.key? :global_headers
32
53
 
33
54
  login(user: @homeserver.user, password: @homeserver.password) if @homeserver.user && @homeserver.password && !@access_token && !params[:skip_login]
34
55
  @homeserver.userinfo = '' unless params[:skip_login]
35
56
  end
36
57
 
58
+ # Gets the logger for the API
59
+ # @return [Logging::Logger] The API-scope logger
37
60
  def logger
38
- @logger ||= Logging.logger[self.class.name]
61
+ @logger ||= Logging.logger[self]
62
+ end
63
+
64
+ # @param seconds [Numeric]
65
+ # @return [Numeric]
66
+ def read_timeout=(seconds)
67
+ @http.finish if @http && @read_timeout != seconds
68
+ @read_timeout = seconds
39
69
  end
40
70
 
71
+ # @param validate [Boolean]
72
+ # @return [Boolean]
41
73
  def validate_certificate=(validate)
42
74
  # The HTTP connection needs to be reopened if this changes
43
75
  @http.finish if @http && validate != @validate_certificate
44
76
  @validate_certificate = validate
45
77
  end
46
78
 
79
+ # @param hs_info [URI]
80
+ # @return [URI]
47
81
  def homeserver=(hs_info)
48
82
  # TODO: DNS query for SRV information about HS?
49
83
  return unless hs_info.is_a? URI
@@ -51,10 +85,34 @@ module MatrixSdk
51
85
  @homeserver = hs_info
52
86
  end
53
87
 
54
- def api_versions
55
- request(:get, :client, '/versions')
88
+ # Gets the available client API versions
89
+ # @return [Array]
90
+ def client_api_versions
91
+ @client_api_versions ||= request(:get, :client, '/versions').versions
92
+ end
93
+
94
+ # Gets the server version
95
+ # @note This uses the unstable federation/v1 API
96
+ def server_version
97
+ Response.new(self, request(:get, :federation_v1, '/version').server).tap do |resp|
98
+ resp.instance_eval <<-'CODE', __FILE__, __LINE__ - 1
99
+ def to_s
100
+ "#{name} #{version}"
101
+ end
102
+ CODE
103
+ end
56
104
  end
57
105
 
106
+ # Runs the client API /sync method
107
+ # @param params [Hash] The sync options to use
108
+ # @option params [Numeric] :timeout (30.0) The timeout in seconds for the sync
109
+ # @option params :since The value of the batch token to base the sync from
110
+ # @option params [String,Hash] :filter The filter to use on the sync
111
+ # @option params [Boolean] :full_state Should the sync include the full state
112
+ # @option params [Boolean] :set_presence Should the sync set the user status to online
113
+ # @return [Response]
114
+ # @see https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-sync
115
+ # For more information on the parameters and what they mean
58
116
  def sync(params = {})
59
117
  query = {
60
118
  timeout: 30.0
@@ -68,29 +126,76 @@ module MatrixSdk
68
126
  request(:get, :client_r0, '/sync', query: query)
69
127
  end
70
128
 
129
+ # Registers a user using the client API /register endpoint
130
+ #
131
+ # @example Regular user registration and login
132
+ # api.register(username: 'example', password: 'NotARealPass')
133
+ # # => { user_id: '@example:matrix.org', access_token: '...', home_server: 'matrix.org', device_id: 'ABCD123' }
134
+ # api.whoami?
135
+ # # => { user_id: '@example:matrix.org' }
136
+ #
137
+ # @param params [Hash] The registration information, all not handled by Ruby will be passed as JSON in the body
138
+ # @option params [String,Symbol] :kind ('user') The kind of registration to use
139
+ # @option params [Boolean] :store_token (true) Should the resulting access token be stored for the API
140
+ # @option params [Boolean] :store_device_id (store_token value) Should the resulting device ID be stored for the API
141
+ # @return [Response]
142
+ # @see https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-register
143
+ # For options that are permitted in this call
71
144
  def register(params = {})
72
145
  kind = params.delete(:kind) { 'user' }
146
+ store_token = params.delete(:store_token) { true }
147
+ store_device_id = params.delete(:store_device_id) { store_token }
73
148
 
74
- request(:post, :client_r0, '/register', body: params, query: { kind: kind })
149
+ request(:post, :client_r0, '/register', body: params, query: { kind: kind }).tap do |resp|
150
+ @access_token = resp.token if resp.key?(:token) && store_token
151
+ @device_id = resp.device_id if resp.key?(:device_id) && store_device_id
152
+ end
75
153
  end
76
154
 
155
+ # Logs in using the client API /login endpoint, and optionally stores the resulting access for API usage
156
+ #
157
+ # @example Logging in with username and password
158
+ # api.login(user: 'example', password: 'NotARealPass')
159
+ # # => { user_id: '@example:matrix.org', access_token: '...', home_server: 'matrix.org', device_id: 'ABCD123' }
160
+ # api.whoami?
161
+ # # => { user_id: '@example:matrix.org' }
162
+ #
163
+ # @example Advanced login, without storing details
164
+ # api.whoami?
165
+ # # => { user_id: '@example:matrix.org' }
166
+ # api.login(medium: 'email', address: 'someone@somewhere.net', password: '...', store_token: false)
167
+ # # => { user_id: '@someone:matrix.org', access_token: ...
168
+ # api.whoami?.user_id
169
+ # # => '@example:matrix.org'
170
+ #
171
+ # @param params [Hash] The login information to use, along with options for said log in
172
+ # @option params [Boolean] :store_token (true) Should the resulting access token be stored for the API
173
+ # @option params [Boolean] :store_device_id (store_token value) Should the resulting device ID be stored for the API
174
+ # @option params [String] :login_type ('m.login.password') The type of login to attempt
175
+ # @option params [String] :initial_device_display_name (USER_AGENT) The device display name to specify for this login attempt
176
+ # @option params [String] :device_id The device ID to set on the login
177
+ # @return [Response] A response hash with the parameters :user_id, :access_token, :home_server, and :device_id.
178
+ # @see https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-login
179
+ # The Matrix Spec, for more information about the call and response
77
180
  def login(params = {})
78
181
  options = {}
79
182
  options[:store_token] = params.delete(:store_token) { true }
80
- options[:store_device_id] = params.delete(:store_device_id) { true }
183
+ options[:store_device_id] = params.delete(:store_device_id) { options[:store_token] }
81
184
 
82
185
  data = {
83
186
  type: params.delete(:login_type) { 'm.login.password' },
84
- initial_device_display_name: params.delete(:initial_device_display_name) { user_agent }
187
+ initial_device_display_name: params.delete(:initial_device_display_name) { USER_AGENT }
85
188
  }.merge params
86
189
  data[:device_id] = device_id if device_id
87
190
 
88
191
  request(:post, :client_r0, '/login', body: data).tap do |resp|
89
- @access_token = resp[:token] if resp[:token] && options[:store_token]
90
- @device_id = resp[:device_id] if resp[:device_id] && options[:store_device_id]
192
+ @access_token = resp.token if resp.key?(:token) && options[:store_token]
193
+ @device_id = resp.device_id if resp.key?(:device_id) && options[:store_device_id]
91
194
  end
92
195
  end
93
196
 
197
+ # Logs out the currently logged in user
198
+ # @return [Response]
94
199
  def logout
95
200
  request(:post, :client_r0, '/logout')
96
201
  end
@@ -106,14 +211,20 @@ module MatrixSdk
106
211
  end
107
212
 
108
213
  def join_room(id_or_alias)
109
- request(:post, :client_r0, "/join/#{CGI.escape id_or_alias}")
214
+ id_or_alias = CGI.escape id_or_alias.to_s
215
+
216
+ request(:post, :client_r0, "/join/#{id_or_alias}")
110
217
  end
111
218
 
112
219
  def send_state_event(room_id, event_type, content, params = {})
113
220
  query = {}
114
221
  query[:ts] = params[:timestamp].to_i if params.key? :timestamp
115
222
 
116
- request(:put, :client_r0, "/rooms/#{room_id}/state/#{event_type}#{"/#{params[:state_key]}" if params.key? :state_key}", body: content, query: query)
223
+ room_id = CGI.escape room_id.to_s
224
+ event_type = CGI.escape event_type.to_s
225
+ state_key = CGI.escape params[:state_key].to_s if params.key? :state_key
226
+
227
+ request(:put, :client_r0, "/rooms/#{room_id}/state/#{event_type}#{"/#{state_key}" unless state_key.nil?}", body: content, query: query)
117
228
  end
118
229
 
119
230
  def send_message_event(room_id, event_type, content, params = {})
@@ -123,6 +234,10 @@ module MatrixSdk
123
234
  txn_id = transaction_id
124
235
  txn_id = params.fetch(:txn_id, "#{txn_id}#{Time.now.to_i}")
125
236
 
237
+ room_id = CGI.escape room_id.to_s
238
+ event_type = CGI.escape event_type.to_s
239
+ txn_id = CGI.escape txn_id.to_s
240
+
126
241
  request(:put, :client_r0, "/rooms/#{room_id}/send/#{event_type}/#{txn_id}", body: content, query: query)
127
242
  end
128
243
 
@@ -136,6 +251,10 @@ module MatrixSdk
136
251
  txn_id = transaction_id
137
252
  txn_id = params.fetch(:txn_id, "#{txn_id}#{Time.now.to_i}")
138
253
 
254
+ room_id = CGI.escape room_id.to_s
255
+ event_type = CGI.escape event_type.to_s
256
+ txn_id = CGI.escape txn_id.to_s
257
+
139
258
  request(:put, :client_r0, "/rooms/#{room_id}/redact/#{event_type}/#{txn_id}", body: content, query: query)
140
259
  end
141
260
 
@@ -195,11 +314,20 @@ module MatrixSdk
195
314
  }
196
315
  query[:to] = params[:to] if params.key? :to
197
316
 
317
+ room_id = CGI.escape room_id.to_s
318
+
198
319
  request(:get, :client_r0, "/rooms/#{room_id}/messages", query: query)
199
320
  end
200
321
 
322
+ def get_room_state(room_id, state_type)
323
+ room_id = CGI.escape room_id.to_s
324
+ state_type = CGI.escape state_type.to_s
325
+
326
+ request(:get, :client_r0, "/rooms/#{room_id}/state/#{state_type}")
327
+ end
328
+
201
329
  def get_room_name(room_id)
202
- request(:get, :client_r0, "/rooms/#{room_id}/state/m.room.name")
330
+ get_room_state(room_id, 'm.room.name')
203
331
  end
204
332
 
205
333
  def set_room_name(room_id, name, params = {})
@@ -210,7 +338,7 @@ module MatrixSdk
210
338
  end
211
339
 
212
340
  def get_room_topic(room_id)
213
- request(:get, :client_r0, "/rooms/#{room_id}/state/m.room.topic")
341
+ get_room_state(room_id, 'm.room.topic')
214
342
  end
215
343
 
216
344
  def set_room_topic(room_id, topic, params = {})
@@ -221,7 +349,7 @@ module MatrixSdk
221
349
  end
222
350
 
223
351
  def get_power_levels(room_id)
224
- request(:get, :client_r0, "/rooms/#{room_id}/state/m.room.power_levels")
352
+ get_room_state(room_id, 'm.room.power_levels')
225
353
  end
226
354
 
227
355
  def set_power_levels(room_id, content)
@@ -230,10 +358,14 @@ module MatrixSdk
230
358
  end
231
359
 
232
360
  def leave_room(room_id)
361
+ room_id = CGI.escape room_id.to_s
362
+
233
363
  request(:post, :client_r0, "/rooms/#{room_id}/leave")
234
364
  end
235
365
 
236
366
  def forget_room(room_id)
367
+ room_id = CGI.escape room_id.to_s
368
+
237
369
  request(:post, :client_r0, "/rooms/#{room_id}/forget")
238
370
  end
239
371
 
@@ -241,6 +373,9 @@ module MatrixSdk
241
373
  content = {
242
374
  user_id: user_id
243
375
  }
376
+
377
+ room_id = CGI.escape room_id.to_s
378
+
244
379
  request(:post, :client_r0, "/rooms/#{room_id}/invite", body: content)
245
380
  end
246
381
 
@@ -249,6 +384,9 @@ module MatrixSdk
249
384
  end
250
385
 
251
386
  def get_membership(room_id, user_id)
387
+ room_id = CGI.escape room_id.to_s
388
+ user_id = CGI.escape user_id.to_s
389
+
252
390
  request(:get, :client_r0, "/rooms/#{room_id}/state/m.room.member/#{user_id}")
253
391
  end
254
392
 
@@ -268,6 +406,9 @@ module MatrixSdk
268
406
  user_id: user_id,
269
407
  reason: params[:reason] || ''
270
408
  }
409
+
410
+ room_id = CGI.escape room_id.to_s
411
+
271
412
  request(:post, :client_r0, "/rooms/#{room_id}/ban", body: content)
272
413
  end
273
414
 
@@ -275,14 +416,24 @@ module MatrixSdk
275
416
  content = {
276
417
  user_id: user_id
277
418
  }
419
+
420
+ room_id = CGI.escape room_id.to_s
421
+
278
422
  request(:post, :client_r0, "/rooms/#{room_id}/unban", body: content)
279
423
  end
280
424
 
281
425
  def get_user_tags(user_id, room_id)
426
+ room_id = CGI.escape room_id.to_s
427
+ user_id = CGI.escape user_id.to_s
428
+
282
429
  request(:get, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags")
283
430
  end
284
431
 
285
432
  def remove_user_tag(user_id, room_id, tag)
433
+ room_id = CGI.escape room_id.to_s
434
+ user_id = CGI.escape user_id.to_s
435
+ tag = CGI.escape tag.to_s
436
+
286
437
  request(:delete, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags/#{tag}")
287
438
  end
288
439
 
@@ -293,34 +444,47 @@ module MatrixSdk
293
444
  content = {}
294
445
  content[:order] = params[:order] if params.key? :order
295
446
  end
447
+
448
+ room_id = CGI.escape room_id.to_s
449
+ user_id = CGI.escape user_id.to_s
450
+ tag = CGI.escape tag.to_s
451
+
296
452
  request(:put, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags/#{tag}", body: content)
297
453
  end
298
454
 
299
- def get_account_data(user_id, type)
300
- request(:get, :client_r0, "/user/#{user_id}/account_data/#{type}")
301
- end
455
+ # def get_account_data(user_id, type)
456
+ # request(:get, :client_r0, "/user/#{user_id}/account_data/#{type}")
457
+ # end
302
458
 
303
- def set_account_data(user_id, type, account_data)
304
- request(:put, :client_r0, "/user/#{user_id}/account_data/#{type}", body: account_data)
305
- end
459
+ def set_account_data(user_id, type_key, account_data)
460
+ user_id = CGI.escape user_id.to_s
461
+ type_key = CGI.escape type_key.to_s
306
462
 
307
- def get_room_account_data(user_id, room_id, type)
308
- request(:get, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type}")
463
+ request(:put, :client_r0, "/user/#{user_id}/account_data/#{type_key}", body: account_data)
309
464
  end
310
465
 
311
- def set_room_account_data(user_id, room_id, type, account_data)
312
- request(:put, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type}", body: account_data)
313
- end
466
+ # def get_room_account_data(user_id, room_id, type)
467
+ # request(:get, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type}")
468
+ # end
469
+
470
+ def set_room_account_data(user_id, room_id, type_key, account_data)
471
+ user_id = CGI.escape user_id.to_s
472
+ room_id = CGI.escape room_id.to_s
473
+ type_key = CGI.escape type_key.to_s
314
474
 
315
- def get_room_state(room_id)
316
- request(:get, :client_r0, "/rooms/#{room_id}/state")
475
+ request(:put, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type_key}", body: account_data)
317
476
  end
318
477
 
319
478
  def get_filter(user_id, filter_id)
479
+ user_id = CGI.escape user_id.to_s
480
+ filter_id = CGI.escape filter_id.to_s
481
+
320
482
  request(:get, :client_r0, "/user/#{user_id}/filter/#{filter_id}")
321
483
  end
322
484
 
323
485
  def create_filter(user_id, filter_params)
486
+ user_id = CGI.escape user_id.to_s
487
+
324
488
  request(:post, :client_r0, "/user/#{user_id}/filter", body: filter_params)
325
489
  end
326
490
 
@@ -329,17 +493,24 @@ module MatrixSdk
329
493
  end
330
494
 
331
495
  def get_display_name(user_id)
496
+ user_id = CGI.escape user_id.to_s
497
+
332
498
  request(:get, :client_r0, "/profile/#{user_id}/displayname")
333
499
  end
334
500
 
335
501
  def set_display_name(user_id, display_name)
336
502
  content = {
337
- display_name: display_name
503
+ displayname: display_name
338
504
  }
505
+
506
+ user_id = CGI.escape user_id.to_s
507
+
339
508
  request(:put, :client_r0, "/profile/#{user_id}/displayname", body: content)
340
509
  end
341
510
 
342
511
  def get_avatar_url(user_id)
512
+ user_id = CGI.escape user_id.to_s
513
+
343
514
  request(:get, :client_r0, "/profile/#{user_id}/avatar_url")
344
515
  end
345
516
 
@@ -347,6 +518,9 @@ module MatrixSdk
347
518
  content = {
348
519
  avatar_url: url
349
520
  }
521
+
522
+ user_id = CGI.escape user_id.to_s
523
+
350
524
  request(:put, :client_r0, "/profile/#{user_id}/avatar_url", body: content)
351
525
  end
352
526
 
@@ -355,11 +529,14 @@ module MatrixSdk
355
529
  raise 'Not a mxc:// URL' unless mxcurl.is_a? URI::MATRIX
356
530
 
357
531
  homeserver.dup.tap do |u|
358
- u.path = "/_matrix/media/r0/download/#{mxcurl.full_path}"
532
+ full_path = CGI.escape mxcurl.full_path.to_s
533
+ u.path = "/_matrix/media/r0/download/#{full_path}"
359
534
  end
360
535
  end
361
536
 
362
537
  def get_room_id(room_alias)
538
+ room_alias = CGI.escape room_alias.to_s
539
+
363
540
  request(:get, :client_r0, "/directory/room/#{room_alias}")
364
541
  end
365
542
 
@@ -367,14 +544,21 @@ module MatrixSdk
367
544
  content = {
368
545
  room_id: room_id
369
546
  }
547
+
548
+ room_alias = CGI.escape room_alias.to_s
549
+
370
550
  request(:put, :client_r0, "/directory/room/#{room_alias}", body: content)
371
551
  end
372
552
 
373
553
  def remove_room_alias(room_alias)
554
+ room_alias = CGI.escape room_alias.to_s
555
+
374
556
  request(:delete, :client_r0, "/directory/room/#{room_alias}")
375
557
  end
376
558
 
377
559
  def get_room_members(room_id)
560
+ room_id = CGI.escape room_id.to_s
561
+
378
562
  request(:get, :client_r0, "/rooms/#{room_id}/members")
379
563
  end
380
564
 
@@ -382,6 +566,7 @@ module MatrixSdk
382
566
  content = {
383
567
  join_rule: join_rule
384
568
  }
569
+
385
570
  send_state_event(room_id, 'm.room.join_rules', content)
386
571
  end
387
572
 
@@ -400,7 +585,7 @@ module MatrixSdk
400
585
  def request(method, api, path, options = {})
401
586
  url = homeserver.dup.tap do |u|
402
587
  u.path = api_to_path(api) + path
403
- u.query = [u.query, options[:query].map { |k, v| "#{k}#{"=#{v}" unless v.nil?}" }].flatten.reject(&:nil?).join('&') if options[:query]
588
+ u.query = [u.query, URI.encode_www_form(options.fetch(:query))].flatten.compact.join('&') if options[:query]
404
589
  u.query = nil if u.query.nil? || u.query.empty?
405
590
  end
406
591
  request = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new url.request_uri
@@ -408,10 +593,13 @@ module MatrixSdk
408
593
  request.body = request.body.to_json if options.key?(:body) && !request.body.is_a?(String)
409
594
  request.body_stream = options[:body_stream] if options.key? :body_stream
410
595
 
411
- request.content_type = 'application/json' if request.body || request.body_stream
596
+ global_headers.each { |h, v| request[h] = v }
597
+ if request.body || request.body_stream
598
+ request.content_type = 'application/json'
599
+ request.content_length = (request.body || request.body_stream).size
600
+ end
412
601
 
413
602
  request['authorization'] = "Bearer #{access_token}" if access_token
414
- request['user-agent'] = user_agent
415
603
  if options.key? :headers
416
604
  options[:headers].each do |h, v|
417
605
  request[h.to_s.downcase] = v
@@ -428,13 +616,14 @@ module MatrixSdk
428
616
  data = JSON.parse(response.body, symbolize_names: true) rescue nil
429
617
 
430
618
  if response.is_a? Net::HTTPTooManyRequests
619
+ raise MatrixRequestError.new(data, response.code) unless autoretry
431
620
  failures += 1
432
621
  waittime = data[:retry_after_ms] || data[:error][:retry_after_ms] || @backoff_time
433
622
  sleep(waittime.to_f / 1000.0)
434
623
  next
435
624
  end
436
625
 
437
- return data if response.is_a? Net::HTTPSuccess
626
+ return MatrixSdk::Response.new self, data if response.is_a? Net::HTTPSuccess
438
627
  raise MatrixRequestError.new(data, response.code) if data
439
628
  raise MatrixConnectionError, response
440
629
  end
@@ -443,6 +632,8 @@ module MatrixSdk
443
632
  private
444
633
 
445
634
  def print_http(http)
635
+ return unless logger.debug?
636
+
446
637
  if http.is_a? Net::HTTPRequest
447
638
  dir = '>'
448
639
  logger.debug "#{dir} Sending a #{http.method} request to `#{http.path}`:"
@@ -450,11 +641,12 @@ module MatrixSdk
450
641
  dir = '<'
451
642
  logger.debug "#{dir} Received a #{http.code} #{http.message} response:"
452
643
  end
453
- http.to_hash.map { |k, v| "#{k}: #{k == 'authorization' ? '[redacted]' : v.join(', ')}" }.each do |h|
644
+ http.to_hash.map { |k, v| "#{k}: #{k == 'authorization' ? '[ REDACTED ]' : v.join(', ')}" }.each do |h|
454
645
  logger.debug "#{dir} #{h}"
455
646
  end
456
647
  logger.debug dir
457
- logger.debug "#{dir} #{http.body.length < 200 ? http.body : http.body.slice(0..200) + '... [truncated]'}" if http.body
648
+ clean_body = JSON.parse(http.body).each { |k, v| v.replace('[ REDACTED ]') if %w[password access_token].include? k }.to_json if http.body
649
+ logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
458
650
  end
459
651
 
460
652
  def transaction_id
@@ -472,13 +664,10 @@ module MatrixSdk
472
664
  @http ||= Net::HTTP.new homeserver.host, homeserver.port
473
665
  return @http if @http.active?
474
666
 
667
+ @http.read_timeout = read_timeout
475
668
  @http.use_ssl = homeserver.scheme == 'https'
476
669
  @http.verify_mode = validate_certificate ? ::OpenSSL::SSL::VERIFY_NONE : nil
477
670
  @http.start
478
671
  end
479
-
480
- def user_agent
481
- "Ruby Matrix SDK v#{MatrixSdk::VERSION}"
482
- end
483
672
  end
484
673
  end
@@ -7,13 +7,13 @@ module MatrixSdk
7
7
  extend Forwardable
8
8
 
9
9
  attr_reader :api
10
- attr_accessor :cache, :mxid, :sync_filter
10
+ attr_writer :mxid
11
+ attr_accessor :cache, :sync_filter
11
12
 
12
13
  events :event, :presence_event, :invite_event, :left_event, :ephemeral_event
13
14
  ignore_inspect :api,
14
15
  :on_event, :on_presence_event, :on_invite_event, :on_left_event, :on_ephemeral_event
15
16
 
16
- alias user_id mxid
17
17
  alias user_id= mxid=
18
18
 
19
19
  def_delegators :@api,
@@ -23,19 +23,27 @@ module MatrixSdk
23
23
  def initialize(hs_url, params = {})
24
24
  event_initialize
25
25
 
26
- params[:user_id] = params[:mxid] if params[:mxid]
27
- raise ArgumentError, 'Must provide user_id with access_token' if params[:access_token] && !params[:user_id]
26
+ params[:user_id] ||= params[:mxid] if params[:mxid]
28
27
 
29
- @api = Api.new hs_url, params
28
+ if hs_url.is_a? Api
29
+ @api = hs_url
30
+ params.each do |k, v|
31
+ api.instance_variable_set("@#{k}", v) if api.instance_variable_defined? "@#{k}"
32
+ end
33
+ else
34
+ @api = Api.new hs_url, params
35
+ end
30
36
 
31
37
  @rooms = {}
32
- @cache = :all
38
+ @users = {}
39
+ @cache = params.fetch(:client_cache, :all)
33
40
 
34
41
  @sync_token = nil
35
42
  @sync_thread = nil
36
43
  @sync_filter = { room: { timeline: { limit: params.fetch(:sync_filter_limit, 20) } } }
37
44
 
38
45
  @should_listen = false
46
+ @next_batch = nil
39
47
 
40
48
  @bad_sync_timeout_limit = 60 * 60
41
49
 
@@ -47,13 +55,20 @@ module MatrixSdk
47
55
 
48
56
  return unless params[:user_id]
49
57
  @mxid = params[:user_id]
50
- sync
51
58
  end
52
59
 
53
60
  def logger
54
- @logger ||= Logging.logger[self.class.name]
61
+ @logger ||= Logging.logger[self]
62
+ end
63
+
64
+ def mxid
65
+ @mxid ||= begin
66
+ api.whoami?[:user_id] if api && api.access_token
67
+ end
55
68
  end
56
69
 
70
+ alias user_id mxid
71
+
57
72
  def rooms
58
73
  @rooms.values
59
74
  end
@@ -72,7 +87,7 @@ module MatrixSdk
72
87
  data = api.login(user: username, password: password)
73
88
  post_authentication(data)
74
89
 
75
- sync(timeout: params.fetch(:sync_timeout, 15)) unless params[:no_sync]
90
+ sync(timeout: params.fetch(:sync_timeout, 15), full_state: params.fetch(:full_state, false)) unless params[:no_sync]
76
91
  end
77
92
 
78
93
  def logout
@@ -81,6 +96,10 @@ module MatrixSdk
81
96
  @mxid = nil
82
97
  end
83
98
 
99
+ def logged_in?
100
+ !(mxid.nil? || @api.access_token.nil?)
101
+ end
102
+
84
103
  def create_room(room_alias = nil, params = {})
85
104
  api.create_room(params.merge(room_alias: room_alias))
86
105
  end
@@ -95,7 +114,11 @@ module MatrixSdk
95
114
  end
96
115
 
97
116
  def get_user(user_id)
98
- User.new(self, user_id)
117
+ if cache == :all
118
+ @users[user_id] ||= User.new(self, user_id)
119
+ else
120
+ User.new(self, user_id)
121
+ end
99
122
  end
100
123
 
101
124
  def remove_room_alias(room_alias)
@@ -108,8 +131,8 @@ module MatrixSdk
108
131
  raise MatrixUnexpectedResponseError, 'Upload succeeded, but no media URI returned'
109
132
  end
110
133
 
111
- def listen_for_events(timeout = 30)
112
- sync(timeout: timeout)
134
+ def listen_for_events(timeout = 30, arguments = {})
135
+ sync(arguments.merge(timeout: timeout))
113
136
  end
114
137
 
115
138
  def start_listener_thread(params = {})
@@ -131,12 +154,14 @@ module MatrixSdk
131
154
  def listen_forever(params = {})
132
155
  timeout = params.fetch(:timeout, 30)
133
156
  params[:bad_sync_timeout] = params.fetch(:bad_sync_timeout, 5)
157
+ params[:sync_interval] = params.fetch(:sync_interval, 30)
134
158
 
135
159
  bad_sync_timeout = params[:bad_sync_timeout]
136
160
  while @should_listen
137
161
  begin
138
162
  sync(timeout: timeout)
139
163
  bad_sync_timeout = params[:bad_sync_timeout]
164
+ sleep(params[:sync_interval]) if params[:sync_interval] > 0
140
165
  rescue MatrixRequestError => ex
141
166
  logger.warn("A #{ex.class} occurred during sync")
142
167
  if ex.httpstatus >= 500
@@ -191,7 +216,12 @@ module MatrixSdk
191
216
  end
192
217
 
193
218
  def sync(params = {})
194
- data = api.sync params.merge(filter: sync_filter.to_json)
219
+ extra_params = {
220
+ filter: sync_filter.to_json
221
+ }
222
+ extra_params[:since] = @next_batch unless @next_batch.nil?
223
+ data = api.sync params.merge(extra_params)
224
+ @next_batch = data[:next_batch]
195
225
 
196
226
  data[:presence][:events].each do |presence_update|
197
227
  fire_presence_event(MatrixEvent.new(self, presence_update))
@@ -52,13 +52,23 @@ end
52
52
  def ignore_inspect(*symbols)
53
53
  class_eval %*
54
54
  def inspect
55
- "#<\#{self.class.name}:\#{"%016x" % (object_id << 1)} \#{instance_variables.reject { |f| %i[#{symbols.map { |s| "@#{s}" }.join ' '}].include? f }.map { |f| "\#{f}=\#{instance_variable_get(f).inspect}" }.join ' ' }>"
55
+ "\#{to_s[0..-2]} \#{instance_variables
56
+ .reject { |f| %i[#{symbols.map { |s| "@#{s}" }.join ' '}].include? f }
57
+ .map { |f| "\#{f}=\#{instance_variable_get(f).inspect}" }.join " " }}>"
56
58
  end
57
59
  *, __FILE__, __LINE__ - 4
58
60
  end
59
61
 
60
62
  module MatrixSdk
61
63
  class EventHandlerArray < Hash
64
+ attr_accessor :reraise_exceptions
65
+
66
+ def initialize(*args)
67
+ @reraise_exceptions = false
68
+
69
+ super(*args)
70
+ end
71
+
62
72
  def add_handler(filter = nil, id = nil, &block)
63
73
  id ||= block.hash
64
74
  self[id] = { filter: filter, id: id, block: block }
@@ -70,9 +80,19 @@ module MatrixSdk
70
80
 
71
81
  def fire(event, filter = nil)
72
82
  reverse_each do |_k, h|
73
- h[:block].call(event) unless event.matches?(h[:filter], filter)
83
+ begin
84
+ h[:block].call(event) if event.matches?(h[:filter], filter)
85
+ rescue StandardError => ex
86
+ logger.error "#{ex.class.name} occurred when firing event (#{event})\n#{ex}"
87
+
88
+ raise ex if @reraise_exceptions
89
+ end
74
90
  end
75
91
  end
92
+
93
+ def logger
94
+ @logger ||= Logging.logger[self]
95
+ end
76
96
  end
77
97
 
78
98
  class Event
@@ -115,5 +135,22 @@ module MatrixSdk
115
135
  to_match == filter
116
136
  end
117
137
  end
138
+
139
+ def [](key)
140
+ event[key]
141
+ end
142
+
143
+ def to_s
144
+ "#{event[:type]}: #{event.reject { |k, _v| k == :type }.to_json}"
145
+ end
146
+
147
+ def method_missing(method, *args)
148
+ return event[method] if event.key? method
149
+ super
150
+ end
151
+
152
+ def respond_to_missing?(method)
153
+ event.key? method
154
+ end
118
155
  end
119
156
  end
@@ -0,0 +1,41 @@
1
+ module MatrixSdk
2
+ # An usability wrapper for API responses as an extended [Hash]
3
+ # All results can be read as both hash keys and as read-only methods on the key
4
+ #
5
+ # @example Simple usage of the response wrapper to get the avatar URL
6
+ # resp = api.get_avatar_url(api.whoami?.user_id)
7
+ # # => { avatar_url: 'mxc://matrix.org/SDGdghriugerRg' }
8
+ # resp.is_a? Hash
9
+ # # => true
10
+ # resp.key? :avatar_url
11
+ # # => true
12
+ # resp.avatar_url
13
+ # # => 'mxc://matrix.org/SDGdghriugerRg'
14
+ # resp.api.set_avatar_url(...)
15
+ # # => {}
16
+ #
17
+ # @since 0.0.3
18
+ # @see Hash
19
+ # @!attribute [r] api
20
+ # @return [Api] The API connection that returned the response
21
+ module Response
22
+ def self.new(api, data)
23
+ data.extend(Extensions)
24
+ data.instance_variable_set(:@api, api)
25
+ data
26
+ end
27
+
28
+ module Extensions
29
+ attr_reader :api
30
+
31
+ def respond_to_missing?(name, *_args)
32
+ key? name
33
+ end
34
+
35
+ def method_missing(name, *args)
36
+ return fetch(name) if key?(name) && args.empty?
37
+ super
38
+ end
39
+ end
40
+ end
41
+ end
@@ -78,7 +78,7 @@ module MatrixSdk
78
78
  end
79
79
 
80
80
  def logger
81
- Logging.logger[self.class.name]
81
+ @logger ||= Logging.logger[self]
82
82
  end
83
83
 
84
84
  #
@@ -261,34 +261,54 @@ module MatrixSdk
261
261
  # User Management
262
262
  #
263
263
 
264
+ # Invites a user into the room
265
+ # @param user_id [String,User] the MXID of the user
266
+ # @return [Boolean] wether the action succeeded
264
267
  def invite_user(user_id)
268
+ user_id = user_id.id if user_id.is_a? MatrixSdk::User
265
269
  client.api.invite_user(id, user_id)
266
270
  true
267
271
  rescue MatrixError
268
272
  false
269
273
  end
270
274
 
275
+ # Kicks a user from the room
276
+ # @param user_id [String,User] the MXID of the user
277
+ # @param reason [String] the reason for the kick
278
+ # @return [Boolean] wether the action succeeded
271
279
  def kick_user(user_id, reason = '')
280
+ user_id = user_id.id if user_id.is_a? MatrixSdk::User
272
281
  client.api.kick_user(id, user_id, reason: reason)
273
282
  true
274
283
  rescue MatrixError
275
284
  false
276
285
  end
277
286
 
287
+ # Bans a user from the room
288
+ # @param user_id [String,User] the MXID of the user
289
+ # @param reason [String] the reason for the ban
290
+ # @return [Boolean] wether the action succeeded
278
291
  def ban_user(user_id, reason = '')
292
+ user_id = user_id.id if user_id.is_a? MatrixSdk::User
279
293
  client.api.ban_user(id, user_id, reason: reason)
280
294
  true
281
295
  rescue MatrixError
282
296
  false
283
297
  end
284
298
 
299
+ # Unbans a user from the room
300
+ # @param user_id [String,User] the MXID of the user
301
+ # @return [Boolean] wether the action succeeded
285
302
  def unban_user(user_id)
303
+ user_id = user_id.id if user_id.is_a? MatrixSdk::User
286
304
  client.api.unban_user(id, user_id)
287
305
  true
288
306
  rescue MatrixError
289
307
  false
290
308
  end
291
309
 
310
+ # Requests to be removed from the room
311
+ # @return [Boolean] wether the request succeeded
292
312
  def leave
293
313
  client.api.leave_room(id)
294
314
  client.rooms.delete id
@@ -297,14 +317,25 @@ module MatrixSdk
297
317
  false
298
318
  end
299
319
 
320
+ # Retrieves a custom entry from the room-specific account data
321
+ # @param type [String] the data type to retrieve
322
+ # @return [Hash] the data that was stored under the given type
300
323
  def get_account_data(type)
301
324
  client.api.get_room_account_data(client.mxid, id, type)
302
325
  end
303
326
 
327
+ # Stores a custom entry into the room-specific account data
328
+ # @param type [String] the data type to store
329
+ # @param account_data [Hash] the data to store
304
330
  def set_account_data(type, account_data)
305
331
  client.api.set_room_account_data(client.mxid, id, type, account_data)
306
332
  end
307
333
 
334
+ # Changes the room-specific user profile
335
+ # @param params [Hash] the user profile changes to apply
336
+ # @option params [String] :display_name the new display name to use in the room
337
+ # @option params [String,URI] :avatar_url the new avatar URL to use in the room
338
+ # @note the avatar URL should be a mxc:// URI
308
339
  def set_user_profile(params = {})
309
340
  return nil unless params[:display_name] || params[:avatar_url]
310
341
  data = client.api.get_membership(id, client.mxid)
@@ -339,6 +370,8 @@ module MatrixSdk
339
370
  nil
340
371
  end
341
372
 
373
+ # Reloads the name of the room
374
+ # @return [Boolean] if the name was changed or not
342
375
  def reload_name!
343
376
  data = client.api.get_room_name(id)
344
377
  changed = data[:name] != name
@@ -355,6 +388,8 @@ module MatrixSdk
355
388
  nil
356
389
  end
357
390
 
391
+ # Reloads the topic of the room
392
+ # @return [Boolean] if the topic was changed or not
358
393
  def reload_topic!
359
394
  data = client.api.get_room_topic(id)
360
395
  changed = data[:topic] != topic
@@ -395,7 +430,7 @@ module MatrixSdk
395
430
 
396
431
  def invite_only=(invite_only)
397
432
  self.join_rule = invite_only ? :invite : :public
398
- @join_rule == :invite # rubocop:disable Lint/Void
433
+ @join_rule == :invite
399
434
  end
400
435
 
401
436
  def join_rule=(join_rule)
@@ -407,7 +442,7 @@ module MatrixSdk
407
442
 
408
443
  def allow_guests=(allow_guests)
409
444
  self.guest_access = (allow_guests ? :can_join : :forbidden)
410
- @guest_access == :can_join # rubocop:disable Lint/Void
445
+ @guest_access == :can_join
411
446
  end
412
447
 
413
448
  def guest_access=(guest_access)
@@ -417,6 +452,10 @@ module MatrixSdk
417
452
  nil
418
453
  end
419
454
 
455
+ # Modifies the power levels of the room
456
+ # @param users [Hash] the user-specific power levels to set or remove
457
+ # @param users_default [Hash] the default user power levels to set
458
+ # @return [Boolean] if the change was successful
420
459
  def modify_user_power_levels(users = nil, users_default = nil)
421
460
  return false if users.nil? && users_default.nil?
422
461
  data = client.api.get_power_levels(id)
@@ -434,6 +473,10 @@ module MatrixSdk
434
473
  false
435
474
  end
436
475
 
476
+ # Modifies the required power levels for actions in the room
477
+ # @param events [Hash] the event-specific power levels to change
478
+ # @param params [Hash] other power-level params to change
479
+ # @return [Boolean] if the change was successful
437
480
  def modify_required_power_levels(events = nil, params = {})
438
481
  return false if events.nil? && (params.nil? || params.empty?)
439
482
  data = client.api.get_power_levels(id)
@@ -3,9 +3,17 @@ require 'matrix_sdk'
3
3
  module MatrixSdk
4
4
  # A class for tracking information about a user on Matrix
5
5
  class User
6
+ # @!attribute [r] id
7
+ # @return [String] the MXID of the user
8
+ # @!attribute [r] client
9
+ # @return [Client] the client for the user
6
10
  attr_reader :id, :client
7
11
  alias user_id :id
8
12
 
13
+ # @!method inspect
14
+ # An inspect method that skips a handful of instance variables to avoid
15
+ # flooding the terminal with debug data.
16
+ # @return [String] a regular inspect string without the data for some variables
9
17
  ignore_inspect :client
10
18
 
11
19
  def initialize(client, id, data = {})
@@ -20,10 +28,14 @@ module MatrixSdk
20
28
  end
21
29
  end
22
30
 
31
+ # @!attribute [r] display_name
32
+ # @return [String] the display name
23
33
  def display_name
24
34
  @display_name ||= client.api.get_display_name(id)[:displayname]
25
35
  end
26
36
 
37
+ # @!attribute [w] display_name
38
+ # @param name [String] the display name to set
27
39
  def display_name=(name)
28
40
  client.api.set_display_name(id, name)
29
41
  @display_name = name
@@ -31,14 +43,18 @@ module MatrixSdk
31
43
  nil
32
44
  end
33
45
 
46
+ # Gets a friendly name of the user
47
+ # @return [String] either the display name or MXID if unset
34
48
  def friendly_name
35
49
  display_name || id
36
50
  end
37
51
 
52
+ # @!attribute [r] avatar_url
38
53
  def avatar_url
39
54
  @avatar_url ||= client.api.get_avatar_url(id)[:avatar_url]
40
55
  end
41
56
 
57
+ # @!attribute [w] avatar_url
42
58
  def avatar_url=(url)
43
59
  client.api.set_avatar_url(id, url)
44
60
  @avatar_url = url
@@ -1,3 +1,3 @@
1
1
  module MatrixSdk
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
data/lib/matrix_sdk.rb CHANGED
@@ -6,6 +6,7 @@ autoload :Logging, 'logging'
6
6
  module MatrixSdk
7
7
  autoload :Api, 'matrix_sdk/api'
8
8
  autoload :Client, 'matrix_sdk/client'
9
+ autoload :Response, 'matrix_sdk/response'
9
10
  autoload :Room, 'matrix_sdk/room'
10
11
  autoload :User, 'matrix_sdk/user'
11
12
 
@@ -19,9 +20,9 @@ module MatrixSdk
19
20
  end
20
21
 
21
22
  def self.logger
22
- @logger ||= Logging.logger[name].tap do |logger|
23
+ @logger ||= Logging.logger[self].tap do |logger|
23
24
  logger.add_appenders Logging.appenders.stdout
24
- logger.level = :warn
25
+ logger.level = :info
25
26
  end
26
27
  end
27
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matrix_sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Olofsson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-11 00:00:00.000000000 Z
11
+ date: 2018-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logging
@@ -74,8 +74,10 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".gitlab-ci.yml"
77
78
  - ".rubocop.yml"
78
79
  - ".travis.yml"
80
+ - CHANGELOG.md
79
81
  - Gemfile
80
82
  - LICENSE.txt
81
83
  - README.md
@@ -86,6 +88,7 @@ files:
86
88
  - lib/matrix_sdk/client.rb
87
89
  - lib/matrix_sdk/errors.rb
88
90
  - lib/matrix_sdk/extensions.rb
91
+ - lib/matrix_sdk/response.rb
89
92
  - lib/matrix_sdk/room.rb
90
93
  - lib/matrix_sdk/user.rb
91
94
  - lib/matrix_sdk/version.rb