matrix_sdk 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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