Refactor ejabberd API integration #226
No files matched your search
@@ -2,21 +2,6 @@ class XmppExchangeContactsJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(inviter, invitee)
|
||||
return unless inviter.service_enabled?(:ejabberd) &&
|
||||
invitee.service_enabled?(:ejabberd) &&
|
||||
inviter.preferences[:xmpp_exchange_contacts_with_invitees]
|
||||
|
||||
ejabberd = EjabberdApiClient.new
|
||||
|
||||
ejabberd.add_rosteritem({
|
||||
"localuser": invitee.cn, "localhost": invitee.ou,
|
||||
"user": inviter.cn, "host": inviter.ou,
|
||||
"nick": inviter.cn, "group": Setting.ejabberd_buddy_roster, "subs": "both"
|
||||
})
|
||||
ejabberd.add_rosteritem({
|
||||
"localuser": inviter.cn, "localhost": inviter.ou,
|
||||
"user": invitee.cn, "host": invitee.ou,
|
||||
"nick": invitee.cn, "group": Setting.ejabberd_buddy_roster, "subs": "both"
|
||||
})
|
||||
EjabberdManager::ExchangeContacts.call(inviter:, invitee:)
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,6 @@ class XmppSendMessageJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(payload)
|
||||
ejabberd = EjabberdApiClient.new
|
||||
ejabberd.send_message payload
|
||||
EjabberdManager::SendMessage.call(payload:)
|
||||
end
|
||||
end
|
||||
@@ -1,97 +1,7 @@
|
||||
require 'digest'
|
||||
require "image_processing/vips"
|
||||
|
||||
class XmppSetAvatarJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(user:, overwrite: false)
|
||||
return if Rails.env.development?
|
||||
@user = user
|
||||
|
||||
unless overwrite
|
||||
current_avatar = get_current_avatar
|
||||
Rails.logger.info { "User #{user.cn} already has an avatar set" }
|
||||
return if current_avatar.present?
|
||||
end
|
||||
|
||||
Rails.logger.debug { "Setting XMPP avatar for user #{user.cn}" }
|
||||
|
||||
stanzas = build_xep0084_stanzas
|
||||
|
||||
stanzas.each do |stanza|
|
||||
payload = { from: @user.address, to: @user.address, stanza: stanza }
|
||||
res = ejabberd.send_stanza payload
|
||||
raise res.inspect if res.status != 200
|
||||
end
|
||||
EjabberdManager::SetAvatar.call(user:, overwrite:)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ejabberd
|
||||
@ejabberd ||= EjabberdApiClient.new
|
||||
end
|
||||
|
||||
def get_current_avatar
|
||||
res = ejabberd.get_vcard2 @user, "PHOTO", "BINVAL"
|
||||
|
||||
if res.status == 200
|
||||
# VCARD PHOTO/BINVAL prop exists
|
||||
res.body
|
||||
elsif res.status == 400
|
||||
# VCARD or PHOTO/BINVAL prop does not exist
|
||||
nil
|
||||
else
|
||||
# Unexpected error, let job fail
|
||||
raise res.inspect
|
||||
end
|
||||
end
|
||||
|
||||
def process_avatar
|
||||
@user.avatar.blob.open do |file|
|
||||
processed = ImageProcessing::Vips
|
||||
.source(file)
|
||||
.resize_to_fill(256, 256)
|
||||
.convert("png")
|
||||
.call
|
||||
processed.read
|
||||
end
|
||||
end
|
||||
|
||||
# See https://xmpp.org/extensions/xep-0084.html
|
||||
def build_xep0084_stanzas
|
||||
img_data = process_avatar
|
||||
sha1_hash = Digest::SHA1.hexdigest(img_data)
|
||||
base64_data = Base64.strict_encode64(img_data)
|
||||
|
||||
[
|
||||
"""
|
||||
<iq type='set' from='#{@user.address}' id='avatar-data-#{rand(101)}'>
|
||||
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
<publish node='urn:xmpp:avatar:data'>
|
||||
<item id='#{sha1_hash}'>
|
||||
<data xmlns='urn:xmpp:avatar:data'>#{base64_data}</data>
|
||||
</item>
|
||||
</publish>
|
||||
</pubsub>
|
||||
</iq>
|
||||
""".strip,
|
||||
"""
|
||||
<iq type='set' from='#{@user.address}' id='avatar-metadata-#{rand(101)}'>
|
||||
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
<publish node='urn:xmpp:avatar:metadata'>
|
||||
<item id='#{sha1_hash}'>
|
||||
<metadata xmlns='urn:xmpp:avatar:metadata'>
|
||||
<info bytes='#{img_data.size}'
|
||||
id='#{sha1_hash}'
|
||||
height='256'
|
||||
type='image/png'
|
||||
width='256'/>
|
||||
</metadata>
|
||||
</item>
|
||||
</publish>
|
||||
</pubsub>
|
||||
</iq>
|
||||
""".strip,
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -2,25 +2,6 @@ class XmppSetDefaultBookmarksJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(user)
|
||||
return unless Setting.xmpp_default_rooms.any?
|
||||
@user = user
|
||||
ejabberd = EjabberdApiClient.new
|
||||
ejabberd.private_set user, storage_content
|
||||
end
|
||||
|
||||
def storage_content
|
||||
bookmarks = ""
|
||||
Setting.xmpp_default_rooms.each do |r|
|
||||
bookmarks << conference_element(
|
||||
jid: r[/<(.+)>/, 1], name: r[/^(.+)\s/, 1], nick: @user.cn,
|
||||
autojoin: Setting.xmpp_autojoin_default_rooms
|
||||
)
|
||||
end
|
||||
|
||||
"<storage xmlns='storage:bookmarks'>#{bookmarks}</storage>"
|
||||
end
|
||||
|
||||
def conference_element(jid:, name:, autojoin: false, nick:)
|
||||
"<conference jid='#{jid}' name='#{name}' autojoin='#{autojoin.to_s}'><nick>#{nick}</nick></conference>"
|
||||
EjabberdManager::SetDefaultBookmarks.call(user:)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
module EjabberdManager
|
||||
class ExchangeContacts < EjabberdManagerService
|
||||
def initialize(inviter:, invitee:)
|
||||
@inviter = inviter
|
||||
@invitee = invitee
|
||||
end
|
||||
|
||||
def call
|
||||
return unless @inviter.service_enabled?(:ejabberd) &&
|
||||
@invitee.service_enabled?(:ejabberd) &&
|
||||
@inviter.preferences[:xmpp_exchange_contacts_with_invitees]
|
||||
|
||||
add_rosteritem({
|
||||
"localuser": @invitee.cn, "localhost": @invitee.ou,
|
||||
"user": @inviter.cn, "host": @inviter.ou,
|
||||
"nick": @inviter.cn, "group": Setting.ejabberd_buddy_roster, "subs": "both"
|
||||
})
|
||||
add_rosteritem({
|
||||
"localuser": @inviter.cn, "localhost": @inviter.ou,
|
||||
"user": @invitee.cn, "host": @invitee.ou,
|
||||
"nick": @invitee.cn, "group": Setting.ejabberd_buddy_roster, "subs": "both"
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
module EjabberdManager
|
||||
class GetAvatar < EjabberdManagerService
|
||||
def initialize(user:)
|
||||
@user = user
|
||||
end
|
||||
|
||||
def call
|
||||
res = get_vcard2 @user, "PHOTO", "BINVAL"
|
||||
|
||||
if res.status == 200
|
||||
# VCARD PHOTO/BINVAL prop exists
|
||||
img_base64 = JSON.parse(res.body)["content"]
|
||||
ct_res = get_vcard2 @user, "PHOTO", "TYPE"
|
||||
content_type = JSON.parse(ct_res.body)["content"]
|
||||
{ content_type:, img_base64: }
|
||||
elsif res.status == 400
|
||||
# VCARD or PHOTO/BINVAL prop does not exist
|
||||
nil
|
||||
else
|
||||
# Unexpected error, let job fail
|
||||
raise res.inspect
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
module EjabberdManager
|
||||
class SendMessage < EjabberdManagerService
|
||||
def initialize(payload:)
|
||||
@payload = payload
|
||||
end
|
||||
|
||||
def call
|
||||
send_message @payload
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,80 @@
|
||||
require 'digest'
|
||||
require "image_processing/vips"
|
||||
|
||||
module EjabberdManager
|
||||
class SetAvatar < EjabberdManagerService
|
||||
def initialize(user:, overwrite: false)
|
||||
@user = user
|
||||
@overwrite = overwrite
|
||||
end
|
||||
|
||||
def call
|
||||
unless @overwrite
|
||||
current_avatar = EjabberdManager::GetAvatar.call(user: @user)
|
||||
Rails.logger.info { "User #{user.cn} already has an avatar set" }
|
||||
return if current_avatar.present?
|
||||
end
|
||||
|
||||
Rails.logger.debug { "Setting XMPP avatar for user #{@user.cn}" }
|
||||
|
||||
stanzas = build_xep0084_stanzas
|
||||
|
||||
stanzas.each do |stanza|
|
||||
payload = { from: @user.address, to: @user.address, stanza: stanza }
|
||||
res = send_stanza payload
|
||||
raise res.inspect if res.status != 200
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_avatar
|
||||
@user.avatar.blob.open do |file|
|
||||
processed = ImageProcessing::Vips
|
||||
.source(file)
|
||||
.resize_to_fill(256, 256)
|
||||
.convert("png")
|
||||
.call
|
||||
processed.read
|
||||
end
|
||||
end
|
||||
|
||||
# See https://xmpp.org/extensions/xep-0084.html
|
||||
def build_xep0084_stanzas
|
||||
img_data = process_avatar
|
||||
sha1_hash = Digest::SHA1.hexdigest(img_data)
|
||||
base64_data = Base64.strict_encode64(img_data)
|
||||
|
||||
[
|
||||
"""
|
||||
<iq type='set' from='#{@user.address}' id='avatar-data-#{rand(101)}'>
|
||||
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
<publish node='urn:xmpp:avatar:data'>
|
||||
<item id='#{sha1_hash}'>
|
||||
<data xmlns='urn:xmpp:avatar:data'>#{base64_data}</data>
|
||||
</item>
|
||||
</publish>
|
||||
</pubsub>
|
||||
</iq>
|
||||
""".strip,
|
||||
"""
|
||||
<iq type='set' from='#{@user.address}' id='avatar-metadata-#{rand(101)}'>
|
||||
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
<publish node='urn:xmpp:avatar:metadata'>
|
||||
<item id='#{sha1_hash}'>
|
||||
<metadata xmlns='urn:xmpp:avatar:metadata'>
|
||||
<info bytes='#{img_data.size}'
|
||||
id='#{sha1_hash}'
|
||||
height='256'
|
||||
type='image/png'
|
||||
width='256'/>
|
||||
</metadata>
|
||||
</item>
|
||||
</publish>
|
||||
</pubsub>
|
||||
</iq>
|
||||
""".strip,
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
module EjabberdManager
|
||||
class SetDefaultBookmarks < EjabberdManagerService
|
||||
def initialize(user:)
|
||||
@user = user
|
||||
end
|
||||
|
||||
def call
|
||||
return unless Setting.xmpp_default_rooms.any?
|
||||
|
||||
private_set @user, storage_content
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def storage_content
|
||||
bookmarks = ""
|
||||
Setting.xmpp_default_rooms.each do |r|
|
||||
bookmarks << conference_element(
|
||||
jid: r[/<(.+)>/, 1], name: r[/^(.+)\s/, 1], nick: @user.cn,
|
||||
autojoin: Setting.xmpp_autojoin_default_rooms
|
||||
)
|
||||
end
|
||||
|
||||
"<storage xmlns='storage:bookmarks'>#{bookmarks}</storage>"
|
||||
end
|
||||
|
||||
def conference_element(jid:, name:, autojoin: false, nick:)
|
||||
"<conference jid='#{jid}' name='#{name}' autojoin='#{autojoin.to_s}'><nick>#{nick}</nick></conference>"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,11 +1,16 @@
|
||||
class EjabberdApiClient
|
||||
def initialize
|
||||
@base_url = Setting.ejabberd_api_url
|
||||
class EjabberdManagerService < RestApiService
|
||||
private
|
||||
|
||||
def base_url
|
||||
@base_url ||= Setting.ejabberd_api_url
|
||||
end
|
||||
|
||||
def post(endpoint, payload)
|
||||
Faraday.post "#{@base_url}/#{endpoint}", payload.to_json,
|
||||
"Content-Type" => "application/json"
|
||||
def headers
|
||||
{ "Content-Type" => "application/json" }
|
||||
end
|
||||
|
||||
def parse_responses?
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
@@ -13,15 +13,17 @@ class RestApiService < ApplicationService
|
||||
"#{base_url}/#{path.gsub(/^\//, '')}"
|
||||
end
|
||||
|
||||
def parse_responses?
|
||||
true
|
||||
end
|
||||
|
||||
def get(path, params = {})
|
||||
res = Faraday.get endpoint_url(path), params, headers
|
||||
# TODO handle unsuccessful responses with no valid JSON body
|
||||
JSON.parse(res.body)
|
||||
parse_responses? ? JSON.parse(res.body) : res
|
||||
end
|
||||
|
||||
def post(path, payload)
|
||||
res = Faraday.post endpoint_url(path), payload.to_json, headers
|
||||
# TODO handle unsuccessful responses with no valid JSON body
|
||||
JSON.parse(res.body)
|
||||
parse_responses? ? JSON.parse(res.body) : res
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,7 @@ module UserManager
|
||||
LdapManager::UpdateAvatar.call(user: @user)
|
||||
|
||||
if Setting.ejabberd_enabled?
|
||||
return if Rails.env.development?
|
||||
XmppSetAvatarJob.perform_later(user: @user)
|
||||
end
|
||||
end
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
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 truncated
|
||||
@@ -1,5 +1,4 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe XmppExchangeContactsJob, type: :job do
|
||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||
@@ -10,19 +9,11 @@ RSpec.describe XmppExchangeContactsJob, type: :job do
|
||||
described_class.perform_later(user, guest)
|
||||
}
|
||||
|
||||
before do
|
||||
stub_request(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||
.to_return(status: 200, body: "", headers: {})
|
||||
allow_any_instance_of(User).to receive(:services_enabled).and_return(["ejabberd"])
|
||||
end
|
||||
it "calls the service for exchanging contacts" do
|
||||
expect(EjabberdManager::ExchangeContacts).to receive(:call)
|
||||
.with(inviter: user, invitee: guest).and_return(true)
|
||||
|
||||
it "posts add_rosteritem commands to the ejabberd API" do
|
||||
perform_enqueued_jobs { job }
|
||||
|
||||
expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||
.with { |req| req.body == '{"localuser":"isaacnewton","localhost":"kosmos.org","user":"willherschel","host":"kosmos.org","nick":"willherschel","group":"Buddies","subs":"both"}' }
|
||||
expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||
.with { |req| req.body == '{"localuser":"willherschel","localhost":"kosmos.org","user":"isaacnewton","host":"kosmos.org","nick":"isaacnewton","group":"Buddies","subs":"both"}' }
|
||||
end
|
||||
|
||||
after do
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe XmppSendMessageJob, type: :job do
|
||||
let(:payload) {{
|
||||
type: "normal",
|
||||
from: "kosmos.org", to: "willherschel@kosmos.org",
|
||||
body: "This is a test message"
|
||||
}}
|
||||
|
||||
subject(:job) {
|
||||
described_class.perform_later(payload)
|
||||
}
|
||||
|
||||
it "calls the service for exchanging contacts" do
|
||||
expect(EjabberdManager::SendMessage).to receive(:call)
|
||||
.with(payload: payload).and_return(true)
|
||||
|
||||
perform_enqueued_jobs { job }
|
||||
end
|
||||
|
||||
after do
|
||||
clear_enqueued_jobs
|
||||
clear_performed_jobs
|
||||
end
|
||||
end
|
||||
@@ -1,30 +1,17 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe XmppSetDefaultBookmarksJob, type: :job do
|
||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||
|
||||
before do
|
||||
Setting.xmpp_default_rooms = [
|
||||
"Welcome <welcome@kosmos.chat>",
|
||||
"Kosmos Dev <kosmos-dev@kosmos.chat>"
|
||||
]
|
||||
end
|
||||
|
||||
subject(:job) {
|
||||
described_class.perform_later(user)
|
||||
}
|
||||
|
||||
before do
|
||||
stub_request(:post, "http://xmpp.example.com/api/private_set")
|
||||
.to_return(status: 200, body: "", headers: {})
|
||||
end
|
||||
it "calls the service for setting default bookmarks" do
|
||||
expect(EjabberdManager::SetDefaultBookmarks).to receive(:call)
|
||||
.with(user: user).and_return(true)
|
||||
|
||||
it "posts a private_set command to the ejabberd API" do
|
||||
perform_enqueued_jobs { job }
|
||||
|
||||
expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/private_set")
|
||||
.with { |req| req.body == '{"user":"willherschel","host":"kosmos.org","element":"\u003cstorage xmlns=\'storage:bookmarks\'\u003e\u003cconference jid=\'welcome@kosmos.chat\' name=\'Welcome\' autojoin=\'false\'\u003e\u003cnick\u003ewillherschel\u003c/nick\u003e\u003c/conference\u003e\u003cconference jid=\'kosmos-dev@kosmos.chat\' name=\'Kosmos Dev\' autojoin=\'false\'\u003e\u003cnick\u003ewillherschel\u003c/nick\u003e\u003c/conference\u003e\u003c/storage\u003e"}' }
|
||||
end
|
||||
|
||||
after do
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe EjabberdManager::ExchangeContacts, type: :model do
|
||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||
let(:guest) { create :user, cn: "isaacnewton", ou: "kosmos.org",
|
||||
id: 2, email: "hotapple42@eol.com" }
|
||||
|
||||
before do
|
||||
stub_request(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||
.to_return(status: 200, body: "", headers: {})
|
||||
allow_any_instance_of(User).to receive(:services_enabled).and_return(["ejabberd"])
|
||||
described_class.call(inviter: user, invitee: guest)
|
||||
end
|
||||
|
||||
it "posts add_rosteritem commands to the ejabberd API" do
|
||||
expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||
.with { |req| req.body == '{"localuser":"isaacnewton","localhost":"kosmos.org","user":"willherschel","host":"kosmos.org","nick":"willherschel","group":"Buddies","subs":"both"}' }
|
||||
expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||
.with { |req| req.body == '{"localuser":"willherschel","localhost":"kosmos.org","user":"isaacnewton","host":"kosmos.org","nick":"isaacnewton","group":"Buddies","subs":"both"}' }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe EjabberdManager::GetAvatar, type: :model do
|
||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||
let(:img_base64) { File.read("#{Rails.root}/spec/fixtures/files/avatar-base64-png.txt").chomp }
|
||||
|
||||
context "when no avatar is set yet" do
|
||||
before do
|
||||
stub_request(:post, "http://xmpp.example.com/api/get_vcard2")
|
||||
.with { |req| req.body == '{"user":"willherschel","host":"kosmos.org","name":"PHOTO","subname":"BINVAL"}' }
|
||||
.to_return(status: 400, body: "", headers: {})
|
||||
end
|
||||
|
||||
it "returns nil" do
|
||||
res = described_class.call(user: user)
|
||||
expect(res).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when avatar exists" do
|
||||
before do
|
||||
stub_request(:post, "http://xmpp.example.com/api/get_vcard2")
|
||||
.with { |req| req.body == '{"user":"willherschel","host":"kosmos.org","name":"PHOTO","subname":"BINVAL"}' }
|
||||
.and_return(status: 200, body: { content: img_base64 }.to_json, headers: {})
|
||||
stub_request(:post, "http://xmpp.example.com/api/get_vcard2")
|
||||
.with { |req| req.body == '{"user":"willherschel","host":"kosmos.org","name":"PHOTO","subname":"TYPE"}' }
|
||||
.and_return(status: 200, body: { content: "image/png" }.to_json, headers: {})
|
||||
end
|
||||
|
||||
it "fetches the avatar and content type" do
|
||||
res = described_class.call(user: user)
|
||||
expect(res[:img_base64]).to eq(img_base64)
|
||||
expect(res[:content_type]).to eq("image/png")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe EjabberdManager::SetDefaultBookmarks, type: :model do
|
||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||
|
||||
before do
|
||||
Setting.xmpp_default_rooms = [
|
||||
"Welcome <welcome@kosmos.chat>",
|
||||
"Kosmos Dev <kosmos-dev@kosmos.chat>"
|
||||
]
|
||||
stub_request(:post, "http://xmpp.example.com/api/private_set")
|
||||
.to_return(status: 200, body: "", headers: {})
|
||||
|
||||
described_class.call(user:)
|
||||
end
|
||||
|
||||
it "posts a private_set command to the ejabberd API" do
|
||||
expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/private_set")
|
||||
.with { |req| req.body == '{"user":"willherschel","host":"kosmos.org","element":"\u003cstorage xmlns=\'storage:bookmarks\'\u003e\u003cconference jid=\'welcome@kosmos.chat\' name=\'Welcome\' autojoin=\'false\'\u003e\u003cnick\u003ewillherschel\u003c/nick\u003e\u003c/conference\u003e\u003cconference jid=\'kosmos-dev@kosmos.chat\' name=\'Kosmos Dev\' autojoin=\'false\'\u003e\u003cnick\u003ewillherschel\u003c/nick\u003e\u003c/conference\u003e\u003c/storage\u003e"}' }
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user