FEATURE: backend support for pushing notifications to clients

This commit is contained in:
Sam 2016-08-26 12:47:10 +10:00
parent 2b15919aee
commit 4fe52c8cbe
5 changed files with 108 additions and 0 deletions

View file

@ -0,0 +1,28 @@
module Jobs
class PushNotification < Jobs::Base
def execute(args)
notification = args["payload"]
notification["url"] = UrlHelper.absolute(notification["post_url"])
notification.delete("post_url")
payload = {
secret_key: SiteSetting.push_api_secret_key,
url: Discourse.base_url,
title: SiteSetting.title,
description: SiteSetting.site_description,
}
clients = args["clients"]
clients.group_by{|r| r[1]}.each do |push_url, group|
notifications = group.map do |client_id, _|
notification.merge({
client_id: client_id
})
end
RestClient.send :post, push_url, payload.merge({notifications: notifications})
end
end
end
end

View file

@ -388,12 +388,26 @@ class PostAlerter
}
MessageBus.publish("/notification-alert/#{user.id}", payload, user_ids: [user.id])
push_notification(user, payload)
DiscourseEvent.trigger(:post_notification_alert, user, payload)
end
end
end
def push_notification(user, payload)
if SiteSetting.allow_push_user_api_keys && SiteSetting.allowed_user_api_push_urls.present?
clients = user.user_api_keys
.where('push AND push_url IS NOT NULL AND position(push_url in ?) > 0 AND revoked_at IS NULL',
SiteSetting.allowed_user_api_push_urls)
.pluck(:client_id, :push_url)
if clients.length > 0
Jobs.enqueue(:push_notification, clients: clients, payload: payload, user_id: user.id)
end
end
end
def expand_group_mentions(groups, post)
return unless post.user && groups

View file

@ -7,6 +7,11 @@ reload_settings = lambda {
RailsMultisite::ConnectionManagement.each_connection do
begin
SiteSetting.refresh!
unless String === SiteSetting.push_api_secret_key && SiteSetting.push_api_secret_key.length == 32
SiteSetting.push_api_secret_key = SecureRandom.hex
end
rescue ActiveRecord::StatementInvalid
# This will happen when migrating a new database
rescue => e

View file

@ -1270,11 +1270,14 @@ user_api:
default: true
max_api_keys_per_user:
default: 10
push_api_secret_key:
hidden: true
min_trust_level_for_user_api_key:
default: 1
allowed_user_api_push_urls:
default: ''
type: list
shadowed_by_global: true
allowed_user_api_auth_redirects:
default: 'https://api.discourse.org/api/auth_redirect|discourse://auth_redirect'
type: list

View file

@ -326,6 +326,64 @@ describe PostAlerter do
end
end
describe "push_notification" do
let(:mention_post) { create_post_with_alerts(user: user, raw: 'Hello @eviltrout')}
let(:topic) { mention_post.topic }
it "correctly pushes notifications if configured correctly" do
SiteSetting.allowed_user_api_push_urls = "https://site.com/push|https://site2.com/push"
2.times do |i|
UserApiKey.create!(user_id: evil_trout.id,
client_id: "xxx#{i}",
key: "yyy#{i}",
application_name: "iPhone#{i}",
read: true,
write: true,
push: true,
push_url: "https://site2.com/push")
end
# I want to test payload ... but we have chicked egg problem
# if I test it then it makes the req and the the expects is not correct ...
# need to track all reqs in rest client and check after the fact
# payload = {
# secret_key: SiteSetting.push_api_secret_key,
# url: Discourse.base_url,
# title: SiteSetting.title,
# description: SiteSetting.site_description,
# notifications: [
# {
# 'notification_type' => 1,
# 'post_number' => 1,
# 'topic_title' => topic.title,
# 'topic_id' => topic.id,
# 'excerpt' => 'Hello @eviltrout',
# 'username' => user.username,
# 'url' => UrlHelper.absolute(mention_post.url),
# 'client_id' => 'xxx0'
# },
# {
# 'notification_type' => 1,
# 'post_number' => 1,
# 'topic_title' => topic.title,
# 'topic_id' => topic.id,
# 'excerpt' => 'Hello @eviltrout',
# 'username' => user.username,
# 'url' => UrlHelper.absolute(mention_post.url),
# 'client_id' => 'xxx1'
# }
# ]
# }
# should only happen once even though we are using 2 keys
RestClient.expects(:post).returns("OK")
mention_post
end
end
describe "watching_first_post" do
let(:group) { Fabricate(:group) }
let(:user) { Fabricate(:user) }