Add configurable default chatroom bookmarks for new users #116
@ -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
|
||||
|
26
app/jobs/xmpp_set_default_bookmarks_job.rb
Normal file
26
app/jobs/xmpp_set_default_bookmarks_job.rb
Normal file
@ -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
|
||||
|
||||
"<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
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 %>
|
||||
</ul>
|
||||
<h3 class="mt-8">User default settings</h3>
|
||||
<ul role="list">
|
||||
<%= 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 <welcome@kosmos.chat>\nKosmos <kosmos@kosmos.chat>",
|
||||
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 %>
|
||||
</ul>
|
||||
|
@ -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
|
||||
|
34
spec/jobs/xmpp_set_default_bookmarks_job_spec.rb
Normal file
34
spec/jobs/xmpp_set_default_bookmarks_job_spec.rb
Normal file
@ -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 <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 "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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user