diff --git a/app/jobs/xmpp_exchange_contacts_job.rb b/app/jobs/xmpp_exchange_contacts_job.rb
index 50f6fa2..f1b20e0 100644
--- a/app/jobs/xmpp_exchange_contacts_job.rb
+++ b/app/jobs/xmpp_exchange_contacts_job.rb
@@ -1,18 +1,22 @@
class XmppExchangeContactsJob < ApplicationJob
queue_as :default
- def perform(inviter, username, domain)
+ def perform(inviter, invitee)
+ return unless inviter.services_enabled.include?("xmpp") &&
+ invitee.services_enabled.include?("xmpp") &&
+ inviter.preferences[:xmpp_exchange_contacts_with_invitees]
+
ejabberd = EjabberdApiClient.new
ejabberd.add_rosteritem({
- "localuser": username, "localhost": domain,
+ "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": username, "host": domain,
- "nick": username, "group": Setting.ejabberd_buddy_roster, "subs": "both"
+ "user": invitee.cn, "host": invitee.ou,
+ "nick": invitee.cn, "group": Setting.ejabberd_buddy_roster, "subs": "both"
})
end
end
diff --git a/app/jobs/xmpp_set_default_bookmarks_job.rb b/app/jobs/xmpp_set_default_bookmarks_job.rb
new file mode 100644
index 0000000..92cd8a5
--- /dev/null
+++ b/app/jobs/xmpp_set_default_bookmarks_job.rb
@@ -0,0 +1,26 @@
+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
+
+ "#{bookmarks}"
+ end
+
+ def conference_element(jid:, name:, autojoin: false, nick:)
+ "#{nick}"
+ end
+end
diff --git a/app/models/setting.rb b/app/models/setting.rb
index b1364a5..2cbc615 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -17,6 +17,13 @@ class Setting < RailsSettings::Base
account accounts donations mail webmaster support
]
+ #
+ # XMPP
+ #
+
+ field :xmpp_default_rooms, type: :array, default: []
+ field :xmpp_autojoin_default_rooms, type: :boolean, default: false
+
#
# Sentry
#
diff --git a/app/models/user.rb b/app/models/user.rb
index 2901fc9..4945d6e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -61,14 +61,10 @@ class User < ApplicationRecord
enable_service %w[ discourse gitea mediawiki xmpp ]
#TODO enable in development when we have easy setup of ejabberd etc.
- return if Rails.env.development?
+ return if Rails.env.development? || !Setting.ejabberd_enabled?
- if inviter.present?
- if Setting.ejabberd_enabled? &&
- inviter.preferences[:xmpp_exchange_contacts_with_invitees]
- exchange_xmpp_contact_with_inviter
- end
- end
+ XmppExchangeContactsJob.perform_later(inviter, self) if inviter.present?
+ XmppSetDefaultBookmarksJob.perform_later(self)
end
def send_devise_notification(notification, *args)
@@ -139,12 +135,6 @@ class User < ApplicationRecord
ldap.delete_attribute(dn,:service)
end
- def exchange_xmpp_contact_with_inviter
- return unless inviter.services_enabled.include?("xmpp") &&
- services_enabled.include?("xmpp")
- XmppExchangeContactsJob.perform_later(inviter, self.cn, self.ou)
- end
-
private
def ldap
diff --git a/app/services/ejabberd_api_client.rb b/app/services/ejabberd_api_client.rb
index bac501e..a0a8b87 100644
--- a/app/services/ejabberd_api_client.rb
+++ b/app/services/ejabberd_api_client.rb
@@ -10,7 +10,7 @@ class EjabberdApiClient
if res.status != 200
Rails.logger.error "[ejabberd] API request failed:"
Rails.logger.error res.body
- #TODO add some kind of exception tracking/notifications
+ #TODO Send custom event to Sentry
end
end
@@ -21,4 +21,9 @@ class EjabberdApiClient
def send_message(payload)
post "send_message", payload
end
+
+ def private_set(user, content)
+ payload = { user: user.cn, host: user.ou, element: content }
+ post "private_set", payload
+ end
end
diff --git a/app/views/admin/settings/services/_ejabberd.html.erb b/app/views/admin/settings/services/_ejabberd.html.erb
index 46e3ca6..887c1c1 100644
--- a/app/views/admin/settings/services/_ejabberd.html.erb
+++ b/app/views/admin/settings/services/_ejabberd.html.erb
@@ -7,24 +7,43 @@
title: "Enable ejabberd integration",
description: "ejabberd configuration present and features enabled"
) %>
- <% if Setting.ejabberd_enabled? %>
- <%= render FormElements::FieldsetComponent.new(title: "API URL") do %>
- <%= f.text_field :ejabberd_api_url,
- value: Setting.ejabberd_api_url,
- class: "w-full", disabled: true %>
- <% end %>
- <%= render FormElements::FieldsetComponent.new(title: "Admin URL") do %>
- <%= f.text_field :ejabberd_admin_url,
- value: Setting.ejabberd_admin_url,
- class: "w-full", disabled: true %>
- <% end %>
- <%= render FormElements::FieldsetComponent.new(
- title: "Contact roster name",
- description: "Used when exchanging contacts after signup from invitation"
- ) do %>
- <%= f.text_field :ejabberd_buddy_roster,
- value: Setting.ejabberd_buddy_roster,
- class: "w-full" %>
- <% end %>
+<% if Setting.ejabberd_enabled? %>
+ <%= render FormElements::FieldsetComponent.new(title: "API URL") do %>
+ <%= f.text_field :ejabberd_api_url,
+ value: Setting.ejabberd_api_url,
+ class: "w-full", disabled: true %>
+ <% end %>
+ <%= render FormElements::FieldsetComponent.new(title: "Admin URL") do %>
+ <%= f.text_field :ejabberd_admin_url,
+ value: Setting.ejabberd_admin_url,
+ class: "w-full", disabled: true %>
<% end %>
+
User default settings
+
+ <%= render FormElements::FieldsetComponent.new(
+ title: "Default rooms",
+ description: "Add these default rooms to new users' bookmarks"
+ ) do %>
+ <%= f.text_area :xmpp_default_rooms,
+ value: Setting.xmpp_default_rooms.join("\n"),
+ placeholder: "Welcome \nKosmos ",
+ class: "h-24 w-full" %>
+ <% end %>
+ <%= render FormElements::FieldsetToggleComponent.new(
+ form: f,
+ attribute: :xmpp_autojoin_default_rooms,
+ enabled: Setting.xmpp_autojoin_default_rooms?,
+ title: "Auto-join default rooms",
+ description: "Automatically join above default rooms in chat clients"
+ ) %>
+ <%= render FormElements::FieldsetComponent.new(
+ title: "Contact roster name",
+ description: "Used when exchanging contacts after signup from invitation"
+ ) do %>
+ <%= f.text_field :ejabberd_buddy_roster,
+ value: Setting.ejabberd_buddy_roster,
+ class: "w-full" %>
+ <% end %>
+<% end %>
+
diff --git a/spec/jobs/xmpp_exchange_contacts_job_spec.rb b/spec/jobs/xmpp_exchange_contacts_job_spec.rb
index f7732dc..c711e87 100644
--- a/spec/jobs/xmpp_exchange_contacts_job_spec.rb
+++ b/spec/jobs/xmpp_exchange_contacts_job_spec.rb
@@ -2,15 +2,18 @@ require 'rails_helper'
require 'webmock/rspec'
RSpec.describe XmppExchangeContactsJob, type: :job do
- let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
+ let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
+ let(:guest) { create :user, cn: "isaacnewton", ou: "kosmos.org",
+ id: 2, email: "hotapple42@eol.com" }
subject(:job) {
- described_class.perform_later(user, 'isaacnewton', 'kosmos.org')
+ 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(["xmpp"])
end
it "posts add_rosteritem commands to the ejabberd API" do
diff --git a/spec/jobs/xmpp_set_default_bookmarks_job_spec.rb b/spec/jobs/xmpp_set_default_bookmarks_job_spec.rb
new file mode 100644
index 0000000..299cbcc
--- /dev/null
+++ b/spec/jobs/xmpp_set_default_bookmarks_job_spec.rb
@@ -0,0 +1,34 @@
+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 ",
+ "Kosmos Dev "
+ ]
+ 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 "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
+ clear_enqueued_jobs
+ clear_performed_jobs
+ end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index c1105c9..68677b7 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -101,38 +101,23 @@ RSpec.describe User, type: :model do
end
end
- describe "#exchange_xmpp_contact_with_inviter" do
- include ActiveJob::TestHelper
-
- let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
- let(:guest) { create :user, id: 2, cn: "isaacnewton", ou: "kosmos.org", email: "newt@example.com" }
-
- before do
- Invitation.create! user: user, invited_user_id: guest.id, used_at: DateTime.now
- allow_any_instance_of(User).to receive(:services_enabled).and_return(%w[ xmpp ])
- end
-
- it "enqueues a job to exchange XMPP contacts between inviter and invitee" do
- guest.send(:exchange_xmpp_contact_with_inviter)
-
- expect(enqueued_jobs.size).to eq(1)
- args = enqueued_jobs.first['arguments']
- expect(args[0]['_aj_globalid']).to match('gid://akkounts/User')
- expect(args[1]).to eq('isaacnewton')
- expect(args[2]).to eq('kosmos.org')
- end
-
- after do
- clear_enqueued_jobs
- end
- end
-
describe "#devise_after_confirmation" do
+ include ActiveJob::TestHelper
+ after { clear_enqueued_jobs }
+
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
it "enables default services" do
expect(user).to receive(:enable_service).with(%w[ discourse gitea mediawiki xmpp ])
- user.send(:devise_after_confirmation)
+ user.send :devise_after_confirmation
+ end
+
+ it "enqueues a job to set default chatroom bookmarks for XMPP" do
+ allow(user).to receive(:enable_service).and_return(true)
+ user.send :devise_after_confirmation
+
+ job = enqueued_jobs.select{|j| j['job_class'] == "XmppSetDefaultBookmarksJob"}.first
+ expect(job['arguments'][0]['_aj_globalid']).to eq('gid://akkounts/User/1')
end
context "for invited user with xmpp enabled" do
@@ -142,23 +127,15 @@ RSpec.describe User, type: :model do
# TODO remove when defaults are implemented
user.update! preferences: { xmpp_exchange_contacts_with_invitees: true }
Invitation.create! user: user, invited_user_id: guest.id, used_at: DateTime.now
- allow_any_instance_of(User).to receive(:enable_service).and_return(true)
+ allow_any_instance_of(User).to receive(:enable_service)
end
- it "exchanges XMPP contacts with the inviter" do
- expect(guest).to receive(:exchange_xmpp_contact_with_inviter)
- guest.send(:devise_after_confirmation)
- end
+ it "enqueues jobs to exchange XMPP contacts between inviter and invitee" do
+ guest.send :devise_after_confirmation
- context "automatic contact exchange disabled" do
- before do
- user.update! preferences: { xmpp_exchange_contacts_with_invitees: false }
- end
-
- it "does not exchange XMPP contacts with the inviter" do
- expect(guest).to_not receive(:exchange_xmpp_contact_with_inviter)
- guest.send(:devise_after_confirmation)
- end
+ job = enqueued_jobs.select{|j| j['job_class'] == "XmppExchangeContactsJob"}.first
+ expect(job["arguments"][0]['_aj_globalid']).to eq('gid://akkounts/User/1')
+ expect(job["arguments"][1]['_aj_globalid']).to eq('gid://akkounts/User/2')
end
end
end