Class: ActiveMatrix::Room

Inherits:
Object
  • Object
show all
Extended by:
Extensions
Includes:
Cacheable, Logging
Defined in:
lib/active_matrix/room.rb

Overview

A class for tracking the information about a room on Matrix

Direct Known Subclasses

ActiveMatrix::Rooms::Space

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Extensions

ignore_inspect

Methods included from Cacheable

#from_cache?, #to_cache

Methods included from Logging

included, #logger, #logger=

Constructor Details

#initialize(client, room_id, data = {}) ⇒ Room

Note:

This method isn’t supposed to be used directly, rather rooms should be retrieved from the Client abstraction.

Create a new room instance

Parameters:

  • client (Client)

    The underlying connection

  • room_id (MXID)

    The room ID

  • data (Hash) (defaults to: {})

    Additional data to assign to the room

Options Hash (data):

  • :name (String)

    The current name of the room

  • :topic (String)

    The current topic of the room

  • :canonical_alias (String, MXID)

    The canonical alias of the room

  • :aliases (Array(String, MXID))

    All non-canonical aliases of the room

  • :join_rule (:invite, :public, :knock)

    The join rule for the room

  • :guest_access (:can_join, :forbidden)

    The guest access setting for the room

  • :world_readable (Boolean)

    If the room is readable by the entire world

  • :members (Array(User))

    The list of joined members

  • :events (Array(Object))

    The list of current events in the room

  • :members_loaded (Boolean)

    If the list of members is already loaded

  • :event_history_limit (Integer) — default: 10

    The limit of events to store for the room

  • :avatar_url (String, URI)

    The avatar URL for the room

  • :prev_batch (String)

    The previous batch token for backfill

Raises:

  • (ArgumentError)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/active_matrix/room.rb', line 52

def initialize(client, room_id, data = {})
  if client.is_a? Room
    copy = client
    client = copy.client
    room_id = copy.id
    # data = copy.attributes
  end

  raise ArgumentError, 'Must be given a Client instance' unless client.is_a? Client

  @client = client
  room_id = MXID.new room_id unless room_id.is_a?(MXID)
  raise ArgumentError, 'room_id must be a valid Room ID' unless room_id.room_id?

  @events = []
  @event_history_limit = 10
  @room_type = nil
  @pre_populated_members = nil # For pre-populated members from tests
  @cached_joined_members = nil # Instance cache for joined members
  @cached_all_members = nil    # Instance cache for all members

  @prev_batch = nil

  %i[name topic canonical_alias avatar_url].each do |type|
    room_state.write("m.room.#{type}", { type => data.delete(type) }) if data.key? type
  end
  room_state.write('m.room.join_rules', { join_rule: data.delete(:join_rule) }) if data.key? :join_rule
  room_state.write('m.room.history_visibility', { history_visibility: data.delete(:world_readable) ? :world_readable : nil }) if data.key? :world_readable

  data.each do |k, v|
    next if %i[client].include? k

    instance_variable_set("@#{k}", v) if instance_variable_defined? "@#{k}"
  end

  @id = room_id.to_s

  logger.debug "Created room #{room_id}"
end

Instance Attribute Details

#clientClient (readonly)

Returns the client for the room.

Returns:

  • (Client)

    the client for the room



21
# File 'lib/active_matrix/room.rb', line 21

attr_reader :id, :client, :events

#event_history_limitFixnum

Returns the limit of events to keep in the event log.

Returns:

  • (Fixnum)

    the limit of events to keep in the event log



12
13
14
# File 'lib/active_matrix/room.rb', line 12

def event_history_limit
  @event_history_limit
end

#eventsObject (readonly)

Returns the value of attribute events.



21
# File 'lib/active_matrix/room.rb', line 21

attr_reader :id, :client, :events

#idString (readonly) Also known as: room_id

Returns the internal ID of the room.

Returns:

  • (String)

    the internal ID of the room



21
22
23
# File 'lib/active_matrix/room.rb', line 21

def id
  @id
end

#on_account_dataObject (readonly)



121
122
123
# File 'lib/active_matrix/room.rb', line 121

def 
  ensure_room_handlers[:account_data]
end

#on_ephemeral_eventObject (readonly)



133
134
135
# File 'lib/active_matrix/room.rb', line 133

def on_ephemeral_event
  ensure_room_handlers[:ephemeral_event]
end

#on_eventObject (readonly)



115
116
117
# File 'lib/active_matrix/room.rb', line 115

def on_event
  ensure_room_handlers[:event]
end

#on_state_eventObject (readonly)



127
128
129
# File 'lib/active_matrix/room.rb', line 127

def on_state_event
  ensure_room_handlers[:state_event]
end

Instance Method Details

#account_dataObject



620
621
622
623
624
# File 'lib/active_matrix/room.rb', line 620

def 
  return ActiveMatrix::AccountDataCache.new client, room: self if client.cache == :none

  @account_data ||= ActiveMatrix::AccountDataCache.new client, room: self
end

#add_alias(room_alias) ⇒ Boolean

Add an alias to the room

Returns:

  • (Boolean)

    if the addition was successful or not



786
787
788
789
790
791
# File 'lib/active_matrix/room.rb', line 786

def add_alias(room_alias)
  client.api.set_room_alias(id, room_alias)
  # Clear the cache to force refresh
  cache.delete(cache_key(:aliases))
  true
end

#add_tag(tag, **data) ⇒ Object

Add a tag to the room

Parameters:

  • tag (String)

    The tag to add

  • data (Hash)

    The data to assign to the tag



733
734
735
736
# File 'lib/active_matrix/room.rb', line 733

def add_tag(tag, **data)
  client.api.add_user_tag(client.mxid, id, tag, data)
  true
end

#admin!(user, level: 100) ⇒ Object

Make a user an admin in the room

Parameters:

  • user (User, MXID, String)

    The user to give admin privileges

  • level (Integer) (defaults to: 100)

    The power level to set the user to

Raises:

  • (ArgumentError)

See Also:



904
905
906
907
908
909
910
911
912
# File 'lib/active_matrix/room.rb', line 904

def admin!(user, level: 100)
  return true if admin?(user, target_level: level)

  user = user.id if user.is_a? User
  user = MXID.new(user.to_s) unless user.is_a? MXID
  raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?

  modify_user_power_levels({ user.to_s.to_sym => level })
end

#admin?(user, target_level: 100) ⇒ Boolean

Check if a user is an admin in the room

Parameters:

  • user (User, MXID, String)

    The user to check for admin privileges

  • target_level (Integer) (defaults to: 100)

    The power level that’s to be considered as admin privileges

Returns:

  • (Boolean)

    If the requested user has a power level highe enough to be an admin

See Also:



892
893
894
895
896
897
# File 'lib/active_matrix/room.rb', line 892

def admin?(user, target_level: 100)
  level = user_powerlevel(user, use_default: false)
  return false unless level

  level >= target_level
end

#aliases(canonical_only: true) ⇒ Array[String]

Gets the room aliases

Parameters:

  • canonical_only (Boolean) (defaults to: true)

    Should the list of aliases only contain the canonical ones

Returns:

  • (Array[String])

    The assigned room aliases



365
366
367
368
369
370
371
# File 'lib/active_matrix/room.rb', line 365

def aliases(canonical_only: true)
  return fetch_aliases(canonical_only: canonical_only) if !canonical_only || client.cache == :none

  cache.fetch(cache_key(:aliases), expires_in: 1.hour) do
    fetch_aliases(canonical_only: true)
  end
end

#all_members(**params) ⇒ Array(User)

Note:

This will also count members who’ve knocked, been invited, have left, or have been banned.

Get all members (member events) in the room

Parameters:

  • params (Hash)

    Additional query parameters to pass to the room member listing - e.g. for filtering purposes.

Returns:

  • (Array(User))

    The complete list of members in the room, regardless of membership state



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/active_matrix/room.rb', line 220

def all_members(**params)
  # Return pre-populated members if they exist and no filtering params (for testing)
  return @pre_populated_members if @pre_populated_members && params.empty?

  # Return cached instance if available and no params
  return @cached_all_members if @cached_all_members && params.empty?

  return fetch_all_members(**params) if !params.empty? || client.cache == :none

  # Cache the raw member state keys, not User objects
  members_data = cache.fetch(cache_key(:all_members), expires_in: 1.hour) do
    client.api.get_room_members(id, **params)[:chunk].map { |ch| ch[:state_key] }
  end

  # Reconstruct User objects from cached data and cache at instance level
  @cached_all_members = members_data.map { |state_key| client.get_user(state_key) }
end

#allow_guests=(allow_guests) ⇒ Object

Sets if guests are allowed in the room

Parameters:

  • allow_guests (Boolean)

    If guests are allowed to join or not



823
824
825
826
# File 'lib/active_matrix/room.rb', line 823

def allow_guests=(allow_guests)
  self.guest_access = (allow_guests ? :can_join : :forbidden)
  allow_guests
end

#avatar_urlString?

Gets the avatar url of the room - if any

Returns:

  • (String, nil)

    The avatar URL - if any



284
285
286
287
288
289
# File 'lib/active_matrix/room.rb', line 284

def avatar_url
  get_state('m.room.avatar_url')[:url]
rescue MatrixNotFoundError
  # No avatar has been set
  nil
end

#avatar_url=(avatar_url) ⇒ Object

Sets a new avatar URL for the room

Parameters:

  • avatar_url (URI::MXC)

    The mxc:// URL for the new room avatar

Raises:

  • (ArgumentError)


839
840
841
842
843
844
845
# File 'lib/active_matrix/room.rb', line 839

def avatar_url=(avatar_url)
  avatar_url = URI(avatar_url) unless avatar_url.is_a? URI
  raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MXC

  room_state['m.room.avatar_url'] = { avatar_url: avatar_url }
  avatar_url
end

#backfill_messages(*args, reverse: false, limit: 10) ⇒ Object

Note:

This will trigger the ‘on_event` events as messages are added

Backfills messages into the room history

Parameters:

  • reverse (Boolean) (defaults to: false)

    whether to fill messages in reverse or not

  • limit (Integer) (defaults to: 10)

    the maximum number of messages to backfill



548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
# File 'lib/active_matrix/room.rb', line 548

def backfill_messages(*args, reverse: false, limit: 10)
  # To be backwards-compatible
  if args.length == 2
    reverse = args.first
    limit = args.last
  end

  data = client.api.get_room_messages(id, @prev_batch, direction: :b, limit: limit)

  events = data[:chunk]
  events.reverse! unless reverse
  events.each do |ev|
    put_event(ev)
  end
  true
end

#ban_user(user_id, reason = '') ⇒ Boolean

Bans a user from the room

Parameters:

  • user_id (String, User)

    the MXID of the user

  • reason (String) (defaults to: '')

    the reason for the ban

Returns:

  • (Boolean)

    wether the action succeeded



595
596
597
598
599
# File 'lib/active_matrix/room.rb', line 595

def ban_user(user_id, reason = '')
  user_id = user_id.id if user_id.is_a? ActiveMatrix::User
  client.api.ban_user(id, user_id, reason: reason)
  true
end

#canonical_aliasString?

Returns the canonical alias of the room.

Returns:

  • (String, nil)

    the canonical alias of the room



166
167
168
169
170
# File 'lib/active_matrix/room.rb', line 166

def canonical_alias
  get_state('m.room.canonical_alias')[:alias]
rescue ActiveMatrix::MatrixNotFoundError
  nil
end

#creation_infoResponse

Gets the room creation information

Returns:

  • (Response)

    The content of the m.room.create event



664
665
666
# File 'lib/active_matrix/room.rb', line 664

def creation_info
  room_state['m.room.create']
end

#display_nameString

Note:

This method will populate the #members list if it has to fall back to the member name generation.

Gets a human-readable name for the room

This will return #name or #canonical_alias if they’ve been set, otherwise it will query the API for members and generate a string from a subset of their names.

Returns:

  • (String)

    a human-readable name for the room



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/active_matrix/room.rb', line 150

def display_name
  return name if name
  return canonical_alias if canonical_alias

  members = joined_members
            .reject { |m| m.user_id == client.mxid }
            .map(&:display_name)

  return members.first if members.one?
  return "#{members.first} and #{members.last}" if members.count == 2
  return "#{members.first} and #{members.count - 1} others" if members.count > 2

  'Empty Room'
end

#dm=(direct) ⇒ Object

Mark a room as a direct (1:1) message Room



266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/active_matrix/room.rb', line 266

def dm=(direct)
  rooms = client.direct_rooms
  dirty = false
  list_for_room = (rooms[id.to_s] ||= [])
  if direct && list_for_room.exclude?(id.to_s)
    list_for_room << id.to_s
    dirty = true
  elsif !direct && list_for_room.include?(id.to_s)
    list_for_room.delete id.to_s
    rooms.delete id.to_s if list_for_room.empty?
    dirty = true
  end
  client.['m.direct'] = rooms if dirty
end

#dm?(members_only: false) ⇒ Boolean

Checks if the room is a direct message / 1:1 room

Parameters:

  • members_only (Boolean) (defaults to: false)

    Should directness only care about member count?

Returns:

  • (Boolean)


259
260
261
262
263
# File 'lib/active_matrix/room.rb', line 259

def dm?(members_only: false)
  return true if !members_only && client.direct_rooms.any? { |_uid, rooms| rooms.include? id.to_s }

  joined_members.count <= 2
end

#fetch_aliases(canonical_only: true) ⇒ Object



373
374
375
376
377
378
379
380
381
382
383
# File 'lib/active_matrix/room.rb', line 373

def fetch_aliases(canonical_only: true)
  canonical = get_state('m.room.canonical_alias') rescue {}
  # Handle both hash-like and Response objects
  alias_value = canonical.respond_to?(:alias) ? canonical.alias : canonical[:alias]
  alt_aliases = canonical.respond_to?(:alt_aliases) ? canonical.alt_aliases : canonical[:alt_aliases]

  aliases = ([alias_value].compact + (alt_aliases || [])).uniq.sort
  return aliases if canonical_only

  (aliases + client.api.get_room_aliases(id).aliases).uniq.sort
end

#fetch_all_members(**params) ⇒ Object



238
239
240
# File 'lib/active_matrix/room.rb', line 238

def fetch_all_members(**params)
  client.api.get_room_members(id, **params)[:chunk].map { |ch| client.get_user(ch[:state_key]) }
end

#fetch_joined_membersObject



203
204
205
206
207
208
209
# File 'lib/active_matrix/room.rb', line 203

def fetch_joined_members
  client.api.get_room_joined_members(id)[:joined].map do |mxid, data|
    User.new(client, mxid.to_s,
             display_name: data.fetch(:display_name, nil),
             avatar_url: data.fetch(:avatar_url, nil))
  end
end

#get_account_data(type) ⇒ Hash

Retrieves a custom entry from the room-specific account data

Parameters:

  • type (String)

    the data type to retrieve

Returns:

  • (Hash)

    the data that was stored under the given type



630
631
632
# File 'lib/active_matrix/room.rb', line 630

def (type)
  [type]
end

#get_state(type, state_key: nil) ⇒ Object

Gets a state object in the room



337
338
339
# File 'lib/active_matrix/room.rb', line 337

def get_state(type, state_key: nil)
  room_state[type, state_key]
end

#guest_access:can_join, :forbidden

Gets the guest access rights for the room

Returns:

  • (:can_join, :forbidden)

    The current guest access right



304
305
306
# File 'lib/active_matrix/room.rb', line 304

def guest_access
  get_state('m.room.guest_access')[:guest_access]&.to_sym
end

#guest_access=(guest_access) ⇒ Object

Sets the guest access status for the room

Parameters:

  • guest_access (:can_join, :forbidden)

    The new guest access status of the room



831
832
833
834
# File 'lib/active_matrix/room.rb', line 831

def guest_access=(guest_access)
  room_state['m.room.guest_access'] = { guest_access: guest_access }
  guest_access
end

#guest_access?Boolean

Checks if guest_access is set to :can_join

Returns:

  • (Boolean)


316
317
318
# File 'lib/active_matrix/room.rb', line 316

def guest_access?
  guest_access == :can_join
end

#history_visibility:invited, ...

Gets the history visibility of the room

Returns:

  • (:invited, :joined, :shared, :world_readable)

    The current history visibility for the room



349
350
351
# File 'lib/active_matrix/room.rb', line 349

def history_visibility
  get_state('m.room.history_visibility')[:history_visibility]&.to_sym
end

#inspectString

An inspect method that skips a handful of instance variables to avoid flooding the terminal with debug data.

Returns:

  • (String)

    a regular inspect string without the data for some variables



27
# File 'lib/active_matrix/room.rb', line 27

ignore_inspect :client, :events, :prev_batch, :logger

#invite_only=(invite_only) ⇒ Object

Sets if the room should be invite only or not

Parameters:

  • invite_only (Boolean)

    If it should be invite only or not



807
808
809
810
# File 'lib/active_matrix/room.rb', line 807

def invite_only=(invite_only)
  self.join_rule = invite_only ? :invite : :public
  invite_only
end

#invite_only?Boolean

Checks if join_rule is set to :invite

Returns:

  • (Boolean)


321
322
323
# File 'lib/active_matrix/room.rb', line 321

def invite_only?
  join_rule == :invite
end

#invite_user(user_id) ⇒ Boolean

Invites a user into the room

Parameters:

  • user_id (String, User)

    the MXID of the user

Returns:

  • (Boolean)

    wether the action succeeded



573
574
575
576
577
# File 'lib/active_matrix/room.rb', line 573

def invite_user(user_id)
  user_id = user_id.id if user_id.is_a? ActiveMatrix::User
  client.api.invite_user(id, user_id)
  true
end

#join_rule:public, ...

Gets the join rule for the room

Returns:

  • (:public, :knock, :invite, :private)

    The current join rule



311
312
313
# File 'lib/active_matrix/room.rb', line 311

def join_rule
  get_state('m.room.join_rules')[:join_rule]&.to_sym
end

#join_rule=(join_rule) ⇒ Object

Sets the join rule of the room

Parameters:

  • join_rule (:invite, :public)

    The join rule of the room



815
816
817
818
# File 'lib/active_matrix/room.rb', line 815

def join_rule=(join_rule)
  room_state['m.room.join_rules'] = { join_rule: join_rule }
  join_rule
end

#joined_membersArray(User) Also known as: members

Populates and returns the #members array

Returns:

  • (Array(User))

    The list of members in the room



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/active_matrix/room.rb', line 175

def joined_members
  # Return pre-populated members if they exist (for testing)
  return @pre_populated_members if @pre_populated_members

  # Return cached instance if available
  return @cached_joined_members if @cached_joined_members

  # Cache the raw data that can be used to reconstruct User objects
  members_data = cache.fetch(cache_key(:joined_members), expires_in: 1.hour) do
    # Convert API response to cacheable format
    api_response = client.api.get_room_joined_members(id)[:joined]
    api_response.map do |mxid, data|
      {
        mxid: mxid.to_s,
        display_name: data[:display_name],
        avatar_url: data[:avatar_url]
      }
    end
  end

  # Reconstruct User objects from cached data and cache at instance level
  @cached_joined_members = members_data.map do |member|
    User.new(client, member[:mxid],
             display_name: member[:display_name],
             avatar_url: member[:avatar_url])
  end
end

#kick_user(user_id, reason = '') ⇒ Boolean

Kicks a user from the room

Parameters:

  • user_id (String, User)

    the MXID of the user

  • reason (String) (defaults to: '')

    the reason for the kick

Returns:

  • (Boolean)

    wether the action succeeded



584
585
586
587
588
# File 'lib/active_matrix/room.rb', line 584

def kick_user(user_id, reason = '')
  user_id = user_id.id if user_id.is_a? ActiveMatrix::User
  client.api.kick_user(id, user_id, reason: reason)
  true
end

#knock_only?Boolean

Checks if join_rule is set to :knock

Returns:

  • (Boolean)


326
327
328
# File 'lib/active_matrix/room.rb', line 326

def knock_only?
  join_rule == :knock
end

#leaveBoolean

Requests to be removed from the room

Returns:

  • (Boolean)

    wether the request succeeded



614
615
616
617
618
# File 'lib/active_matrix/room.rb', line 614

def leave
  client.api.leave_room(id)
  client.instance_variable_get(:@rooms).delete id
  true
end

#moderator!(user, level: 50) ⇒ Object

Make a user a moderator in the room

Parameters:

  • user (User, MXID, String)

    The user to give moderator privileges

  • level (Integer) (defaults to: 50)

    The power level to set the user to

Raises:

  • (ArgumentError)

See Also:



932
933
934
935
936
937
938
939
940
# File 'lib/active_matrix/room.rb', line 932

def moderator!(user, level: 50)
  return true if moderator?(user, target_level: level)

  user = user.id if user.is_a? User
  user = MXID.new(user.to_s) unless user.is_a? MXID
  raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?

  modify_user_power_levels({ user.to_s.to_sym => level })
end

#moderator?(user, target_level: 50) ⇒ Boolean

Check if a user is a moderator in the room

Parameters:

  • user (User, MXID, String)

    The user to check for admin privileges

  • target_level (Integer) (defaults to: 50)

    The power level that’s to be considered as admin privileges

Returns:

  • (Boolean)

    If the requested user has a power level highe enough to be an admin

See Also:



920
921
922
923
924
925
# File 'lib/active_matrix/room.rb', line 920

def moderator?(user, target_level: 50)
  level = user_powerlevel(user, use_default: false)
  return false unless level

  level >= target_level
end

#modify_required_power_levels(events = nil, params = {}) ⇒ Boolean

Modifies the required power levels for actions in the room

Parameters:

  • events (Hash) (defaults to: nil)

    the event-specific power levels to change

  • params (Hash) (defaults to: {})

    other power-level params to change

Returns:

  • (Boolean)

    if the change was successful



979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
# File 'lib/active_matrix/room.rb', line 979

def modify_required_power_levels(events = nil, params = {})
  return false if events.nil? && params.blank?

  room_state.expire 'm.room.power_levels'

  data = power_levels
  data.merge!(params)
  data.delete_if { |_k, v| v.nil? }

  if events
    data[:events] = {} unless data.key? :events
    data[:events].merge!(events)
    data[:events].delete_if { |_k, v| v.nil? }
  end

  room_state['m.room.power_levels'] = data
  true
end

#modify_user_power_levels(users = nil, users_default = nil) ⇒ Boolean

Modifies the power levels of the room

Parameters:

  • users (Hash) (defaults to: nil)

    the user-specific power levels to set or remove

  • users_default (Hash) (defaults to: nil)

    the default user power levels to set

Returns:

  • (Boolean)

    if the change was successful



947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
# File 'lib/active_matrix/room.rb', line 947

def modify_user_power_levels(users = nil, users_default = nil)
  return false if users.nil? && users_default.nil?

  room_state.expire 'm.room.power_levels'

  data = power_levels
  data[:users_default] = users_default unless users_default.nil?

  if users
    data[:users] = {} unless data.key? :users
    users.each do |user, level|
      user = user.id if user.is_a? User
      user = MXID.new(user.to_s) unless user.is_a? MXID
      raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?

      if level.nil?
        data[:users].delete(user.to_s.to_sym)
      else
        data[:users][user.to_s.to_sym] = level
      end
    end
  end

  room_state['m.room.power_levels'] = data
  true
end

#nameString?

Note:

Will cache the current name for 15 minutes

Gets the current name of the room, querying the API if necessary

Returns:

  • (String, nil)

    The room name - if any



247
248
249
250
251
252
253
# File 'lib/active_matrix/room.rb', line 247

def name
  state = get_state('m.room.name')
  state&.dig(:name)
rescue MatrixNotFoundError
  # No room name has been specified
  nil
end

#name=(name) ⇒ Object

Sets a new name on the room

Parameters:

  • name (String)

    The new name to set



754
755
756
757
# File 'lib/active_matrix/room.rb', line 754

def name=(name)
  room_state['m.room.name'] = { name: name }
  name
end

#power_levelsHash

Note:

The returned power levels are cached for a minute

Get the power levels of the room

Returns:

  • (Hash)

    The current power levels as set for the room

See Also:



852
853
854
# File 'lib/active_matrix/room.rb', line 852

def power_levels
  get_state('m.room.power_levels')
end

#redact_message(event_id, reason = nil) ⇒ Object

Redacts a message from the room

Parameters:

  • event_id (String)

    the ID of the event to redact

  • reason (String, nil) (defaults to: nil)

    the reason for the redaction



528
529
530
531
# File 'lib/active_matrix/room.rb', line 528

def redact_message(event_id, reason = nil)
  client.api.redact_event(id, event_id, reason: reason)
  true
end

#reload!Object Also known as: refresh!

Refreshes the room state caches for name, topic, and aliases



743
744
745
746
747
748
# File 'lib/active_matrix/room.rb', line 743

def reload!
  reload_name!
  reload_topic!
  reload_aliases!
  true
end

#reload_aliases!Boolean Also known as: refresh_aliases!

Note:

The list of aliases is not sorted, ordering changes will result in alias list updates.

Reloads the list of aliases by an API query

Returns:

  • (Boolean)

    if the alias list was updated or not



798
799
800
801
# File 'lib/active_matrix/room.rb', line 798

def reload_aliases!
  room_state.expire('m.room.canonical_alias')
  cache.delete(cache_key(:aliases))
end

#reload_name!Boolean Also known as: refresh_name!

Reloads the name of the room

Returns:

  • (Boolean)

    if the name was changed or not



762
763
764
# File 'lib/active_matrix/room.rb', line 762

def reload_name!
  room_state.expire('m.room.name')
end

#reload_topic!Boolean Also known as: refresh_topic!

Reloads the topic of the room

Returns:

  • (Boolean)

    if the topic was changed or not



778
779
780
# File 'lib/active_matrix/room.rb', line 778

def reload_topic!
  room_state.expire('m.room.topic')
end

#remove_tag(tag) ⇒ Object

Remove a tag from the room

Parameters:

  • tag (String)

    The tag to remove



724
725
726
727
# File 'lib/active_matrix/room.rb', line 724

def remove_tag(tag)
  client.api.remove_user_tag(client.mxid, id, tag)
  true
end

#report_message(event_id, reason:, score: -100)) ⇒ Object

Reports a message in the room

Parameters:

  • event_id (MXID, String)

    The ID of the event to redact

  • reason (String)

    The reason for the report

  • score (Integer) (defaults to: -100))

    The severity of the report in the range of -100 - 0



538
539
540
541
# File 'lib/active_matrix/room.rb', line 538

def report_message(event_id, reason:, score: -100)
  client.api.report_event(id, event_id, reason: reason, score: score)
  true
end

#room_stateObject



330
331
332
333
334
# File 'lib/active_matrix/room.rb', line 330

def room_state
  return ActiveMatrix::StateEventCache.new self if client.cache == :none

  @room_state ||= ActiveMatrix::StateEventCache.new self
end

#room_type'm.space', ...

Retrieves the type of the room

Returns:

  • ('m.space', String, nil)

    The type of the room



671
672
673
674
# File 'lib/active_matrix/room.rb', line 671

def room_type
  # Can't change, so a permanent cache is ok
  @room_type ||= creation_info[:type]
end

#room_versionString

Retrieves the room version

Returns:

  • (String)

    The version of the room



679
680
681
682
# File 'lib/active_matrix/room.rb', line 679

def room_version
  # Can't change, so a permanent cache is ok
  @room_version ||= creation_info[:room_version]
end

#send_audio(url, name, audio_info = {}) ⇒ Object

Note:

The URLs should all be of the ‘mxc://’ schema

Sends a link to an audio clip to the room

Parameters:

  • url (String, URI)

    the URL to the audio clip

  • name (String)

    the name of the audio clip

  • audio_info (Hash) (defaults to: {})

    extra information about the audio clip

Options Hash (audio_info):

  • :duration (Integer)

    the duration of the audio clip in milliseconds

  • :mimetype (String)

    the MIME type of the audio clip

  • :size (Integer)

    the size of the audio clip in bytes



497
498
499
# File 'lib/active_matrix/room.rb', line 497

def send_audio(url, name, audio_info = {})
  client.api.send_content(id, url, name, 'm.audio', extra_information: audio_info)
end

#send_custom_message(body, content = {}, msgtype: nil) ⇒ Object

Sends a customized message to the Room

Parameters:

  • body (String)

    The clear-text body of the message

  • content (Hash) (defaults to: {})

    The custom content of the message

  • msgtype (String) (defaults to: nil)

    The type of the message, should be one of the known types (m.text, m.notice, m.emote, etc)



506
507
508
509
510
511
# File 'lib/active_matrix/room.rb', line 506

def send_custom_message(body, content = {}, msgtype: nil)
  content[:body] = body
  content[:msgtype] = msgtype || 'm.text'

  client.api.send_message_event(id, 'm.room.message', content)
end

#send_emote(text) ⇒ Object

Sends an emote (/me) message to the room

Parameters:

  • text (String)

    the emote to send



419
420
421
# File 'lib/active_matrix/room.rb', line 419

def send_emote(text)
  client.api.send_emote(id, text)
end

#send_event(type, content = {}) ⇒ Object

Sends a custom timeline event to the Room

Parameters:

  • type (String, Symbol)

    The type of the Event. For custom events, this should be written in reverse DNS format (e.g. com.example.event)

  • content (Hash) (defaults to: {})

    The contents of the message, this will be the :content key of the resulting event object

See Also:



520
521
522
# File 'lib/active_matrix/room.rb', line 520

def send_event(type, content = {})
  client.api.send_message_event(id, type, content)
end

#send_file(url, name, file_info = {}) ⇒ Object

Note:

The URLs should all be of the ‘mxc://’ schema

Sends a link to a generic file to the room

Parameters:

  • url (String, URI)

    the URL to the file

  • name (String)

    the name of the file

  • file_info (Hash) (defaults to: {})

    extra information about the file

Options Hash (file_info):

  • :mimetype (String)

    the MIME type of the file

  • :size (Integer)

    the size of the file in bytes

  • :thumbnail_url (String, URI)

    the URL to a thumbnail of the file

  • :thumbnail_info (Hash)

    ThumbnailInfo about the thumbnail file



433
434
435
# File 'lib/active_matrix/room.rb', line 433

def send_file(url, name, file_info = {})
  client.api.send_content(id, url, name, 'm.file', extra_information: file_info)
end

#send_html(html, body = nil, msgtype: nil, format: nil) ⇒ Object

Sends a custom HTML message to the room

Parameters:

  • html (String)

    the HTML message to send

  • body (String, nil) (defaults to: nil)

    a plain-text representation of the object (Will default to the HTML with all tags stripped away)

  • msgtype (String) (defaults to: nil)

    (‘m.text’) The message type for the message

  • format (String) (defaults to: nil)

    (‘org.matrix.custom.html’) The message format

See Also:



405
406
407
408
409
410
411
412
413
414
# File 'lib/active_matrix/room.rb', line 405

def send_html(html, body = nil, msgtype: nil, format: nil)
  content = {
    body: body || html.gsub(/<\/?[^>]*>/, ''),
    msgtype: msgtype || 'm.text',
    format: format || 'org.matrix.custom.html',
    formatted_body: html
  }

  client.api.send_message_event(id, 'm.room.message', content)
end

#send_image(url, name, image_info = {}) ⇒ Object

Note:

The URLs should all be of the ‘mxc://’ schema

Sends a link to an image to the room

Parameters:

  • url (String, URI)

    the URL to the image

  • name (String)

    the name of the image

  • image_info (Hash) (defaults to: {})

    extra information about the image

Options Hash (image_info):

  • :h (Integer)

    the height of the image in pixels

  • :w (Integer)

    the width of the image in pixels

  • :mimetype (String)

    the MIME type of the image

  • :size (Integer)

    the size of the image in bytes

  • :thumbnail_url (String, URI)

    the URL to a thumbnail of the image

  • :thumbnail_info (Hash)

    ThumbnailInfo about the thumbnail image



456
457
458
# File 'lib/active_matrix/room.rb', line 456

def send_image(url, name, image_info = {})
  client.api.send_content(id, url, name, 'm.image', extra_information: image_info)
end

#send_location(geo_uri, name, thumbnail_url = nil, thumbnail_info = {}) ⇒ Object

Note:

The thumbnail URL should be of the ‘mxc://’ schema

Sends a location object to the room

Parameters:

  • geo_uri (String, URI)

    the geo-URL (e.g. geo:<coords>) of the location

  • name (String)

    the name of the location

  • thumbnail_url (String, URI) (defaults to: nil)

    the URL to a thumbnail image of the location

  • thumbnail_info (Hash) (defaults to: {})

    a ThumbnailInfo for the location thumbnail



467
468
469
# File 'lib/active_matrix/room.rb', line 467

def send_location(geo_uri, name, thumbnail_url = nil, thumbnail_info = {})
  client.api.send_location(id, geo_uri, name, thumbnail_url: thumbnail_url, thumbnail_info: thumbnail_info)
end

#send_notice(text) ⇒ Object

Sends a notice (bot) message to the room

Parameters:

  • text (String)

    the notice to send



440
441
442
# File 'lib/active_matrix/room.rb', line 440

def send_notice(text)
  client.api.send_notice(id, text)
end

#send_text(text) ⇒ Object

Sends a plain-text message to the room

Parameters:

  • text (String)

    the message to send



392
393
394
# File 'lib/active_matrix/room.rb', line 392

def send_text(text)
  client.api.send_message(id, text)
end

#send_video(url, name, video_info = {}) ⇒ Object

Note:

The URLs should all be of the ‘mxc://’ schema

Sends a link to a video to the room

Parameters:

  • url (String, URI)

    the URL to the video

  • name (String)

    the name of the video

  • video_info (Hash) (defaults to: {})

    extra information about the video

Options Hash (video_info):

  • :duration (Integer)

    the duration of the video in milliseconds

  • :h (Integer)

    the height of the video in pixels

  • :w (Integer)

    the width of the video in pixels

  • :mimetype (String)

    the MIME type of the video

  • :size (Integer)

    the size of the video in bytes

  • :thumbnail_url (String, URI)

    the URL to a thumbnail of the video

  • :thumbnail_info (Hash)

    ThumbnailInfo about the thumbnail of the video



484
485
486
# File 'lib/active_matrix/room.rb', line 484

def send_video(url, name, video_info = {})
  client.api.send_content(id, url, name, 'm.video', extra_information: video_info)
end

#set_account_data(type, account_data) ⇒ Object

Stores a custom entry into the room-specific account data

Parameters:

  • type (String)

    the data type to store

  • account_data (Hash)

    the data to store



638
639
640
641
# File 'lib/active_matrix/room.rb', line 638

def (type, )
  self.[type] = 
  true
end

#set_state(type, data, state_key: nil) ⇒ Object

Sets a state object in the room



342
343
344
# File 'lib/active_matrix/room.rb', line 342

def set_state(type, data, state_key: nil)
  room_state[type, state_key] = data
end

#set_user_profile(display_name: nil, avatar_url: nil, reason: nil) ⇒ Object

Note:

the avatar URL should be a mxc:// URI

Changes the room-specific user profile

Parameters:

  • display_name (String) (defaults to: nil)

    the new display name to use in the room

  • avatar_url (String, URI) (defaults to: nil)

    the new avatar URL to use in the room



648
649
650
651
652
653
654
655
656
657
658
659
# File 'lib/active_matrix/room.rb', line 648

def (display_name: nil, avatar_url: nil, reason: nil)
  return nil unless display_name || avatar_url

  data = client.api.get_membership(id, client.mxid)
  raise "Can't set profile if you haven't joined the room" unless data[:membership] == 'join'

  data[:displayname] = display_name unless display_name.nil?
  data[:avatar_url] = avatar_url unless avatar_url.nil?

  client.api.set_membership(id, client.mxid, 'join', reason || 'Updating room profile information', data)
  true
end

#space?Boolean?

Checks if the room is a Matrix Space

Returns:

  • (Boolean, nil)

    True if the room is a space



687
688
689
690
691
# File 'lib/active_matrix/room.rb', line 687

def space?
  room_type == 'm.space'
rescue ActiveMatrix::MatrixForbiddenError, ActiveMatrix::MatrixNotFoundError
  nil
end

#tagsResponse

Returns a list of the room tags

Examples:

Managing tags

room.tags
# => { :room_tag => { data: false } }
room.tags.add('some_tag', data: true)
# => { :some_tag => { data: true }, :room_tag => { data: false} }
room.tags.remove('room_tag')
# => { :some_tag => { data: true} }

Returns:

  • (Response)

    A list of the tags and their data, with add and remove methods implemented



703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'lib/active_matrix/room.rb', line 703

def tags
  client.api.get_user_tags(client.mxid, id)[:tags].tap do |tag_obj|
    tag_obj.instance_variable_set(:@room, self)
    tag_obj.define_singleton_method(:room) do
      @room
    end
    tag_obj.define_singleton_method(:add) do |tag, **data|
      @room.add_tag(tag.to_s.to_sym, **data)
      self[tag.to_s.to_sym] = data
      self
    end
    tag_obj.define_singleton_method(:remove) do |tag|
      @room.remove_tag(tag.to_s.to_sym)
      delete tag.to_s.to_sym
    end
  end
end

#to_sObject



102
103
104
105
106
107
# File 'lib/active_matrix/room.rb', line 102

def to_s
  prefix = canonical_alias || id
  return "#{prefix} | #{name}" unless name.nil?

  prefix
end

#to_spaceObject

Casting operators



96
97
98
99
100
# File 'lib/active_matrix/room.rb', line 96

def to_space
  return nil unless space?

  Rooms::Space.new self, nil
end

#topicString?

Gets the room topic - if any

Returns:

  • (String, nil)

    The topic of the room



294
295
296
297
298
299
# File 'lib/active_matrix/room.rb', line 294

def topic
  get_state('m.room.topic')[:topic]
rescue MatrixNotFoundError
  # No room name has been specified
  nil
end

#topic=(topic) ⇒ Object

Sets a new topic on the room

Parameters:

  • topic (String)

    The new topic to set



770
771
772
773
# File 'lib/active_matrix/room.rb', line 770

def topic=(topic)
  room_state['m.room.topic'] = { topic: topic }
  topic
end

#unban_user(user_id) ⇒ Boolean

Unbans a user from the room

Parameters:

  • user_id (String, User)

    the MXID of the user

Returns:

  • (Boolean)

    wether the action succeeded



605
606
607
608
609
# File 'lib/active_matrix/room.rb', line 605

def unban_user(user_id)
  user_id = user_id.id if user_id.is_a? ActiveMatrix::User
  client.api.unban_user(id, user_id)
  true
end

#user_can_send?(user, event, state: false) ⇒ Boolean

Checks if a user can send a given event type in the room

Parameters:

  • user (User, MXID, String)

    The user to check

  • event (String, Symbol)

    The event type to check

  • state (Boolean) (defaults to: false)

    If the given event is a state event or a message event

Returns:

  • (Boolean)

    If the given user is allowed to send an event of the given type



878
879
880
881
882
883
884
# File 'lib/active_matrix/room.rb', line 878

def user_can_send?(user, event, state: false)
  user_pl = user_powerlevel(user)
  event_pl = power_levels.dig(:events, event.to_s.to_sym)
  event_pl ||= state ? (power_levels[:state_default] || 50) : (power_levels[:events_default] || 0)

  user_pl >= event_pl
end

#user_powerlevel(user, use_default: true) ⇒ Integer?

Gets the power level of a user in the room

Parameters:

  • user (User, MXID, String)

    The user to check the power level for

  • use_default (Boolean) (defaults to: true)

    Should the user default level be checked if no user-specific one exists

Returns:

  • (Integer, nil)

    The current power level for the requested user, nil if there’s no user specific level and use_default is false

Raises:

  • (ArgumentError)


862
863
864
865
866
867
868
869
870
# File 'lib/active_matrix/room.rb', line 862

def user_powerlevel(user, use_default: true)
  user = user.id if user.is_a? User
  user = MXID.new(user.to_s) unless user.is_a? MXID
  raise ArgumentError, 'Must provide a valid User or MXID' unless user.user?

  level = power_levels.dig(:users, user.to_s.to_sym)
  level ||= power_levels[:users_default] || 0 if use_default
  level
end

#world_readable?Boolean Also known as: world_readable

Checks if the room history is world readable

Returns:

  • (Boolean)

    If the history is world readable



356
357
358
# File 'lib/active_matrix/room.rb', line 356

def world_readable?
  history_visibility == :world_readable
end