matrix_sdk 1.5.0 → 2.0.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.
@@ -22,6 +22,17 @@ module MatrixSdk
22
22
  # @return [Api] The API connection that returned the response
23
23
  module Response
24
24
  def self.new(api, data)
25
+ if data.is_a? Array
26
+ raise ArgumentError, 'Input data was not an array of hashes' unless data.all? { |v| v.is_a? Hash }
27
+
28
+ data.each do |value|
29
+ Response.new api, value
30
+ end
31
+ return data
32
+ end
33
+
34
+ raise ArgumentError, 'Input data was not a hash' unless data.is_a? Hash
35
+
25
36
  data.extend(Extensions)
26
37
  data.instance_variable_set(:@api, api)
27
38
 
@@ -58,10 +58,34 @@ module MatrixSdk
58
58
 
59
59
  alias room_id id
60
60
 
61
+ # Create a new room instance
62
+ #
63
+ # @note This method isn't supposed to be used directly, rather rooms should
64
+ # be retrieved from the Client abstraction.
65
+ #
66
+ # @param client [Client] The underlying connection
67
+ # @param room_id [MXID] The room ID
68
+ # @param data [Hash] Additional data to assign to the room
69
+ # @option data [String] :name The current name of the room
70
+ # @option data [String] :topic The current topic of the room
71
+ # @option data [String,MXID] :canonical_alias The canonical alias of the room
72
+ # @option data [Array(String,MXID)] :aliases All non-canonical aliases of the room
73
+ # @option data [:invite,:public] :join_rule The join rule for the room
74
+ # @option data [:can_join,:forbidden] :guest_access The guest access setting for the room
75
+ # @option data [Boolean] :world_readable If the room is readable by the entire world
76
+ # @option data [Array(User)] :members The list of joined members
77
+ # @option data [Array(Object)] :events The list of current events in the room
78
+ # @option data [Boolean] :members_loaded If the list of members is already loaded
79
+ # @option data [Integer] :event_history_limit (10) The limit of events to store for the room
80
+ # @option data [String,URI] :avatar_url The avatar URL for the room
81
+ # @option data [String] :prev_batch The previous batch token for backfill
61
82
  def initialize(client, room_id, data = {})
83
+ raise ArgumentError, 'Must be given a Client instance' unless client.is_a? Client
84
+
85
+ room_id = MXID.new room_id unless room_id.is_a?(MXID)
86
+ raise ArgumentError, 'room_id must be a valid Room ID' unless room_id.room_id?
87
+
62
88
  event_initialize
63
- @client = client
64
- @id = room_id.to_s
65
89
 
66
90
  @name = nil
67
91
  @topic = nil
@@ -82,6 +106,9 @@ module MatrixSdk
82
106
  instance_variable_set("@#{k}", v) if instance_variable_defined? "@#{k}"
83
107
  end
84
108
 
109
+ @client = client
110
+ @id = room_id.to_s
111
+
85
112
  @name_checked = Time.new(0)
86
113
 
87
114
  logger.debug "Created room #{room_id}"
@@ -116,20 +143,27 @@ module MatrixSdk
116
143
  end
117
144
 
118
145
  # Populates and returns the #members array
146
+ #
147
+ # @return [Array(User)] The list of members in the room
119
148
  def joined_members
120
149
  return members if @members_loaded && !members.empty?
121
150
 
122
- client.api.get_room_members(id)[:chunk].each do |chunk|
123
- next unless chunk [:content][:membership] == 'join'
124
-
125
- ensure_member(User.new(client, chunk[:state_key], display_name: chunk[:content].fetch(:displayname, nil)))
151
+ client.api.get_room_joined_members(id)[:joined].each do |mxid, data|
152
+ ensure_member(User.new(client, mxid.to_s,
153
+ display_name: data.fetch(:display_name, nil),
154
+ avatar_url: data.fetch(:avatar_url, nil)))
126
155
  end
127
156
  @members_loaded = true
128
157
  members
129
158
  end
130
159
 
160
+ # Gets the current name of the room, querying the API if necessary
161
+ #
162
+ # @note Will cache the current name for 15 minutes
163
+ #
164
+ # @return [String,nil] The room name - if any
131
165
  def name
132
- return @name if Time.now - @name_checked < 10
166
+ return @name if Time.now - @name_checked < 900
133
167
 
134
168
  @name_checked = Time.now
135
169
  @name ||= client.api.get_room_name(id)
@@ -139,6 +173,8 @@ module MatrixSdk
139
173
  end
140
174
 
141
175
  # Gets the avatar url of the room - if any
176
+ #
177
+ # @return [String,nil] The avatar URL - if any
142
178
  def avatar_url
143
179
  @avatar_url ||= client.api.get_room_avatar(id).url
144
180
  rescue MatrixNotFoundError
@@ -169,23 +205,26 @@ module MatrixSdk
169
205
  #
170
206
 
171
207
  # Sends a plain-text message to the room
208
+ #
172
209
  # @param text [String] the message to send
173
210
  def send_text(text)
174
211
  client.api.send_message(id, text)
175
212
  end
176
213
 
177
214
  # Sends a custom HTML message to the room
215
+ #
178
216
  # @param html [String] the HTML message to send
179
217
  # @param body [String,nil] a plain-text representation of the object
180
- # (Will default to the HTML with tags stripped away)
181
- # @param msg_type [String] A message type for the message
218
+ # (Will default to the HTML with all tags stripped away)
219
+ # @param msgtype [String] ('m.text') The message type for the message
220
+ # @param format [String] ('org.matrix.custom.html') The message format
182
221
  # @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-room-message-msgtypes
183
222
  # Possible message types as defined by the spec
184
- def send_html(html, body = nil, msg_type = 'm.text')
223
+ def send_html(html, body = nil, msgtype: nil, format: nil)
185
224
  content = {
186
225
  body: body || html.gsub(/<\/?[^>]*>/, ''),
187
- msgtype: msg_type,
188
- format: 'org.matrix.custom.html',
226
+ msgtype: msgtype || 'm.text',
227
+ format: format || 'org.matrix.custom.html',
189
228
  formatted_body: html
190
229
  }
191
230
 
@@ -193,12 +232,14 @@ module MatrixSdk
193
232
  end
194
233
 
195
234
  # Sends an emote (/me) message to the room
235
+ #
196
236
  # @param text [String] the emote to send
197
237
  def send_emote(text)
198
238
  client.api.send_emote(id, text)
199
239
  end
200
240
 
201
241
  # Sends a link to a generic file to the room
242
+ #
202
243
  # @param url [String,URI] the URL to the file
203
244
  # @param name [String] the name of the file
204
245
  # @param file_info [Hash] extra information about the file
@@ -212,12 +253,14 @@ module MatrixSdk
212
253
  end
213
254
 
214
255
  # Sends a notice (bot) message to the room
256
+ #
215
257
  # @param text [String] the notice to send
216
258
  def send_notice(text)
217
259
  client.api.send_notice(id, text)
218
260
  end
219
261
 
220
262
  # Sends a link to an image to the room
263
+ #
221
264
  # @param url [String,URI] the URL to the image
222
265
  # @param name [String] the name of the image
223
266
  # @param image_info [Hash] extra information about the image
@@ -233,6 +276,7 @@ module MatrixSdk
233
276
  end
234
277
 
235
278
  # Sends a location object to the room
279
+ #
236
280
  # @param geo_uri [String,URI] the geo-URL (e.g. geo:<coords>) of the location
237
281
  # @param name [String] the name of the location
238
282
  # @param thumbnail_url [String,URI] the URL to a thumbnail image of the location
@@ -243,6 +287,7 @@ module MatrixSdk
243
287
  end
244
288
 
245
289
  # Sends a link to a video to the room
290
+ #
246
291
  # @param url [String,URI] the URL to the video
247
292
  # @param name [String] the name of the video
248
293
  # @param video_info [Hash] extra information about the video
@@ -259,6 +304,7 @@ module MatrixSdk
259
304
  end
260
305
 
261
306
  # Sends a link to an audio clip to the room
307
+ #
262
308
  # @param url [String,URI] the URL to the audio clip
263
309
  # @param name [String] the name of the audio clip
264
310
  # @param audio_info [Hash] extra information about the audio clip
@@ -271,6 +317,7 @@ module MatrixSdk
271
317
  end
272
318
 
273
319
  # Redacts a message from the room
320
+ #
274
321
  # @param event_id [String] the ID of the event to redact
275
322
  # @param reason [String,nil] the reason for the redaction
276
323
  def redact_message(event_id, reason = nil)
@@ -278,7 +325,18 @@ module MatrixSdk
278
325
  true
279
326
  end
280
327
 
328
+ # Reports a message in the room
329
+ #
330
+ # @param event_id [MXID,String] The ID of the event to redact
331
+ # @param reason [String] The reason for the report
332
+ # @param score [Integer] The severity of the report in the range of -100 - 0
333
+ def report_message(event_id, reason:, score: -100)
334
+ client.api.report_event(id, event_id, reason: reason, score: score)
335
+ true
336
+ end
337
+
281
338
  # Backfills messages into the room history
339
+ #
282
340
  # @param reverse [Boolean] whether to fill messages in reverse or not
283
341
  # @param limit [Integer] the maximum number of messages to backfill
284
342
  # @note This will trigger the `on_event` events as messages are added
@@ -298,6 +356,7 @@ module MatrixSdk
298
356
  #
299
357
 
300
358
  # Invites a user into the room
359
+ #
301
360
  # @param user_id [String,User] the MXID of the user
302
361
  # @return [Boolean] wether the action succeeded
303
362
  def invite_user(user_id)
@@ -307,6 +366,7 @@ module MatrixSdk
307
366
  end
308
367
 
309
368
  # Kicks a user from the room
369
+ #
310
370
  # @param user_id [String,User] the MXID of the user
311
371
  # @param reason [String] the reason for the kick
312
372
  # @return [Boolean] wether the action succeeded
@@ -317,6 +377,7 @@ module MatrixSdk
317
377
  end
318
378
 
319
379
  # Bans a user from the room
380
+ #
320
381
  # @param user_id [String,User] the MXID of the user
321
382
  # @param reason [String] the reason for the ban
322
383
  # @return [Boolean] wether the action succeeded
@@ -327,6 +388,7 @@ module MatrixSdk
327
388
  end
328
389
 
329
390
  # Unbans a user from the room
391
+ #
330
392
  # @param user_id [String,User] the MXID of the user
331
393
  # @return [Boolean] wether the action succeeded
332
394
  def unban_user(user_id)
@@ -336,6 +398,7 @@ module MatrixSdk
336
398
  end
337
399
 
338
400
  # Requests to be removed from the room
401
+ #
339
402
  # @return [Boolean] wether the request succeeded
340
403
  def leave
341
404
  client.api.leave_room(id)
@@ -344,6 +407,7 @@ module MatrixSdk
344
407
  end
345
408
 
346
409
  # Retrieves a custom entry from the room-specific account data
410
+ #
347
411
  # @param type [String] the data type to retrieve
348
412
  # @return [Hash] the data that was stored under the given type
349
413
  def get_account_data(type)
@@ -351,6 +415,7 @@ module MatrixSdk
351
415
  end
352
416
 
353
417
  # Stores a custom entry into the room-specific account data
418
+ #
354
419
  # @param type [String] the data type to store
355
420
  # @param account_data [Hash] the data to store
356
421
  def set_account_data(type, account_data)
@@ -359,6 +424,7 @@ module MatrixSdk
359
424
  end
360
425
 
361
426
  # Changes the room-specific user profile
427
+ #
362
428
  # @param display_name [String] the new display name to use in the room
363
429
  # @param avatar_url [String,URI] the new avatar URL to use in the room
364
430
  # @note the avatar URL should be a mxc:// URI
@@ -376,6 +442,7 @@ module MatrixSdk
376
442
  end
377
443
 
378
444
  # Returns a list of the room tags
445
+ #
379
446
  # @return [Response] A list of the tags and their data, with add and remove methods implemented
380
447
  # @example Managing tags
381
448
  # room.tags
@@ -403,6 +470,7 @@ module MatrixSdk
403
470
  end
404
471
 
405
472
  # Remove a tag from the room
473
+ #
406
474
  # @param [String] tag The tag to remove
407
475
  def remove_tag(tag)
408
476
  client.api.remove_user_tag(client.mxid, id, tag)
@@ -410,6 +478,7 @@ module MatrixSdk
410
478
  end
411
479
 
412
480
  # Add a tag to the room
481
+ #
413
482
  # @param [String] tag The tag to add
414
483
  # @param [Hash] data The data to assign to the tag
415
484
  def add_tag(tag, **data)
@@ -421,6 +490,7 @@ module MatrixSdk
421
490
  # State updates
422
491
  #
423
492
 
493
+ # Refreshes the room state caches for name, topic, and aliases
424
494
  def reload!
425
495
  reload_name!
426
496
  reload_topic!
@@ -429,12 +499,16 @@ module MatrixSdk
429
499
  end
430
500
  alias refresh! reload!
431
501
 
502
+ # Sets a new name on the room
503
+ #
504
+ # @param name [String] The new name to set
432
505
  def name=(name)
433
506
  client.api.set_room_name(id, name)
434
507
  @name = name
435
508
  end
436
509
 
437
510
  # Reloads the name of the room
511
+ #
438
512
  # @return [Boolean] if the name was changed or not
439
513
  def reload_name!
440
514
  data = begin
@@ -448,12 +522,16 @@ module MatrixSdk
448
522
  end
449
523
  alias refresh_name! reload_name!
450
524
 
525
+ # Sets a new topic on the room
526
+ #
527
+ # @param topic [String] The new topic to set
451
528
  def topic=(topic)
452
529
  client.api.set_room_topic(id, topic)
453
530
  @topic = topic
454
531
  end
455
532
 
456
533
  # Reloads the topic of the room
534
+ #
457
535
  # @return [Boolean] if the topic was changed or not
458
536
  def reload_topic!
459
537
  data = begin
@@ -468,6 +546,7 @@ module MatrixSdk
468
546
  alias refresh_topic! reload_topic!
469
547
 
470
548
  # Add an alias to the room
549
+ #
471
550
  # @return [Boolean] if the addition was successful or not
472
551
  def add_alias(room_alias)
473
552
  client.api.set_room_alias(id, room_alias)
@@ -476,6 +555,7 @@ module MatrixSdk
476
555
  end
477
556
 
478
557
  # Reloads the list of aliases by an API query
558
+ #
479
559
  # @return [Boolean] if the alias list was updated or not
480
560
  # @note The list of aliases is not sorted, ordering changes will result in
481
561
  # alias list updates.
@@ -483,7 +563,7 @@ module MatrixSdk
483
563
  begin
484
564
  new_aliases = client.api.get_room_aliases(id).aliases
485
565
  rescue MatrixNotFoundError
486
- data = client.api.get_room_state(id)
566
+ data = client.api.get_room_state_all(id)
487
567
  new_aliases = data.select { |chunk| chunk[:type] == 'm.room.aliases' && chunk.key?(:content) && chunk[:content].key?(:aliases) }
488
568
  .map { |chunk| chunk[:content][:aliases] }
489
569
  .flatten
@@ -498,26 +578,41 @@ module MatrixSdk
498
578
  end
499
579
  alias refresh_aliases! reload_aliases!
500
580
 
581
+ # Sets if the room should be invite only or not
582
+ #
583
+ # @param invite_only [Boolean] If it should be invite only or not
501
584
  def invite_only=(invite_only)
502
585
  self.join_rule = invite_only ? :invite : :public
503
586
  @join_rule == :invite
504
587
  end
505
588
 
589
+ # Sets the join rule of the room
590
+ #
591
+ # @param join_rule [:invite,:public] The join rule of the room
506
592
  def join_rule=(join_rule)
507
593
  client.api.set_join_rule(id, join_rule)
508
594
  @join_rule = join_rule
509
595
  end
510
596
 
597
+ # Sets if guests are allowed in the room
598
+ #
599
+ # @param allow_guests [Boolean] If guests are allowed to join or not
511
600
  def allow_guests=(allow_guests)
512
601
  self.guest_access = (allow_guests ? :can_join : :forbidden)
513
602
  @guest_access == :can_join
514
603
  end
515
604
 
605
+ # Sets the guest access status for the room
606
+ #
607
+ # @param guest_access [:can_join,:forbidden] The new guest access status of the room
516
608
  def guest_access=(guest_access)
517
609
  client.api.set_guest_access(id, guest_access)
518
610
  @guest_access = guest_access
519
611
  end
520
612
 
613
+ # Sets a new avatar URL for the room
614
+ #
615
+ # @param avatar_url [URI::MATRIX] The mxc:// URL for the new room avatar
521
616
  def avatar_url=(avatar_url)
522
617
  avatar_url = URI(avatar_url) unless avatar_url.is_a? URI
523
618
  raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MATRIX
@@ -527,6 +622,7 @@ module MatrixSdk
527
622
  end
528
623
 
529
624
  # Modifies the power levels of the room
625
+ #
530
626
  # @param users [Hash] the user-specific power levels to set or remove
531
627
  # @param users_default [Hash] the default user power levels to set
532
628
  # @return [Boolean] if the change was successful
@@ -547,6 +643,7 @@ module MatrixSdk
547
643
  end
548
644
 
549
645
  # Modifies the required power levels for actions in the room
646
+ #
550
647
  # @param events [Hash] the event-specific power levels to change
551
648
  # @param params [Hash] other power-level params to change
552
649
  # @return [Boolean] if the change was successful
@@ -7,10 +7,6 @@ module MatrixSdk
7
7
  class User
8
8
  extend MatrixSdk::Extensions
9
9
 
10
- # @!attribute [r] id
11
- # @return [String] the MXID of the user
12
- # @!attribute [r] client
13
- # @return [Client] the client for the user
14
10
  attr_reader :id, :client
15
11
  alias user_id :id
16
12
 
@@ -32,14 +28,14 @@ module MatrixSdk
32
28
  end
33
29
  end
34
30
 
35
- # @!attribute [r] display_name
36
31
  # @return [String] the display name
32
+ # @see MatrixSdk::Protocols::CS#get_display_name
37
33
  def display_name
38
34
  @display_name ||= client.api.get_display_name(id)[:displayname]
39
35
  end
40
36
 
41
- # @!attribute [w] display_name
42
37
  # @param name [String] the display name to set
38
+ # @see MatrixSdk::Protocols::CS#set_display_name
43
39
  def display_name=(name)
44
40
  client.api.set_display_name(id, name)
45
41
  @display_name = name
@@ -51,21 +47,92 @@ module MatrixSdk
51
47
  display_name || id
52
48
  end
53
49
 
54
- # @!attribute [r] avatar_url
50
+ # Gets the avatar for the user
51
+ #
52
+ # @see MatrixSdk::Protocols::CS#get_avatar_url
55
53
  def avatar_url
56
54
  @avatar_url ||= client.api.get_avatar_url(id)[:avatar_url]
57
55
  end
58
56
 
59
- # @!attribute [w] avatar_url
57
+ # Set a new avatar for the user
58
+ #
59
+ # Only works for the current user object, as requested by
60
+ # client.get_user(:self)
61
+ #
62
+ # @param url [String,URI::MATRIX] the new avatar URL
63
+ # @note Requires a mxc:// URL, check example on
64
+ # {MatrixSdk::Protocols::CS#set_avatar_url} for how this can be done
65
+ # @see MatrixSdk::Protocols::CS#set_avatar_url
60
66
  def avatar_url=(url)
61
67
  client.api.set_avatar_url(id, url)
62
68
  @avatar_url = url
63
69
  end
64
70
 
71
+ # Get the user's current presence status
72
+ #
73
+ # @return [Symbol] One of :online, :offline, :unavailable
74
+ # @see MatrixSdk::Protocols::CS#get_presence_status
75
+ # @note This information is not cached in the abstraction layer
76
+ def presence
77
+ raw_presence[:presence].to_sym
78
+ end
79
+
80
+ # Sets the user's current presence status
81
+ # Should be one of :online, :offline, or :unavailable
82
+ #
83
+ # @param new_presence [:online,:offline,:unavailable] The new presence status to set
84
+ # @see MatrixSdk::Protocols::CS#set_presence_status
85
+ def presence=(new_presence)
86
+ raise ArgumentError, 'Presence must be one of :online, :offline, :unavailable' unless %i[online offline unavailable].include?(presence)
87
+
88
+ client.api.set_presence_status(id, new_presence)
89
+ end
90
+
91
+ # @return [Boolean] if the user is currently active
92
+ # @note This information is not cached in the abstraction layer
93
+ def active?
94
+ raw_presence[:currently_active] == true
95
+ end
96
+
97
+ # Gets the user-specified status message - if any
98
+ #
99
+ # @see MatrixSdk::Protocols::CS#get_presence_status
100
+ # @note This information is not cached in the abstraction layer
101
+ def status_msg
102
+ raw_presence[:status_msg]
103
+ end
104
+
105
+ # Sets the user-specified status message
106
+ #
107
+ # @param message [String,nil] The message to set, or nil for no message
108
+ # @see MatrixSdk::Protocols::CS#set_presence_status
109
+ def status_msg=(message)
110
+ client.api.set_presence_status(id, presence, message: message)
111
+ end
112
+
113
+ # Gets the last time the user was active at, from the server's side
114
+ #
115
+ # @return [Time] when the user was last active
116
+ # @see MatrixSdk::Protocols::CS#get_presence_status
117
+ # @note This information is not cached in the abstraction layer
118
+ def last_active
119
+ since = raw_presence[:last_active_ago]
120
+ return unless since
121
+
122
+ Time.now - (since / 1000)
123
+ end
124
+
125
+ # Returns all the current device keys for the user, retrieving them if necessary
65
126
  def device_keys
66
127
  @device_keys ||= client.api.keys_query(device_keys: { id => [] }).yield_self do |resp|
67
128
  resp[:device_keys][id.to_sym]
68
129
  end
69
130
  end
131
+
132
+ private
133
+
134
+ def raw_presence
135
+ client.api.get_presence_status(id).tap { |h| h.delete :user_id }
136
+ end
70
137
  end
71
138
  end