diff --git a/extensions/pusher/js/forum/src/main.js b/extensions/pusher/js/forum/src/main.js index d3495dd2f..9de46dc24 100644 --- a/extensions/pusher/js/forum/src/main.js +++ b/extensions/pusher/js/forum/src/main.js @@ -11,7 +11,19 @@ app.initializers.add('pusher', () => { const loadPusher = m.deferred(); $.getScript('//js.pusher.com/3.0/pusher.min.js', () => { - loadPusher.resolve(new Pusher(app.forum.attribute('pusherKey')).subscribe('public')); + const socket = new Pusher(app.forum.attribute('pusherKey'), { + authEndpoint: app.forum.attribute('apiUrl') + '/pusher/auth', + auth: { + headers: { + 'Authorization': 'Token ' + app.session.token + } + } + }); + + loadPusher.resolve({ + main: socket.subscribe('public'), + user: app.session.user ? socket.subscribe('private-user' + app.session.user.id()) : null + }); }); app.pusher = loadPusher.promise; @@ -20,8 +32,8 @@ app.initializers.add('pusher', () => { extend(DiscussionList.prototype, 'config', function(x, isInitialized, context) { if (isInitialized) return; - app.pusher.then(channel => { - channel.bind('newPost', data => { + app.pusher.then(channels => { + channels.main.bind('newPost', data => { const params = this.props.params; if (!params.q && !params.sort) { @@ -43,7 +55,7 @@ app.initializers.add('pusher', () => { } }); - context.onunload = () => channel.unbind(); + context.onunload = () => channels.main.unbind(); }); }); @@ -75,8 +87,8 @@ app.initializers.add('pusher', () => { extend(DiscussionPage.prototype, 'config', function(x, isInitialized, context) { if (isInitialized) return; - app.pusher.then(channel => { - channel.bind('newPost', data => { + app.pusher.then(channels => { + channels.main.bind('newPost', data => { if (this.discussion && this.discussion.id() === data.discussionId && this.stream) { const oldCount = this.discussion.commentsCount(); @@ -92,11 +104,23 @@ app.initializers.add('pusher', () => { } }); - context.onunload = () => channel.unbind(); + context.onunload = () => channels.main.unbind(); }); }); extend(IndexPage.prototype, 'actionItems', items => { delete items.refresh; }); + + app.pusher.then(channels => { + if (channels.user) { + channels.user.bind('notification', () => { + app.session.user.pushAttributes({ + unreadNotificationsCount: app.session.user.unreadNotificationsCount() + 1 + }); + delete app.cache.notifications; + m.redraw(); + }); + } + }); }); diff --git a/extensions/pusher/src/Api/AuthAction.php b/extensions/pusher/src/Api/AuthAction.php new file mode 100644 index 000000000..0f5b78e9d --- /dev/null +++ b/extensions/pusher/src/Api/AuthAction.php @@ -0,0 +1,37 @@ +settings = $settings; + } + + protected function respond(Request $request) + { + $userChannel = 'private-user' . $request->actor->id; + + if ($request->get('channel_name') === $userChannel) { + $pusher = new Pusher( + $this->settings->get('pusher.app_key'), + $this->settings->get('pusher.app_secret'), + $this->settings->get('pusher.app_id') + ); + + $payload = json_decode($pusher->socket_auth($userChannel, $request->get('socket_id')), true); + + return new JsonResponse($payload); + } + + return new EmptyResponse(403); + } +} diff --git a/extensions/pusher/src/Listeners/AddApiAttributes.php b/extensions/pusher/src/Listeners/AddApiAttributes.php index e756170ba..c34af0d15 100755 --- a/extensions/pusher/src/Listeners/AddApiAttributes.php +++ b/extensions/pusher/src/Listeners/AddApiAttributes.php @@ -1,6 +1,7 @@ listen(ApiAttributes::class, [$this, 'addAttributes']); + $events->listen(RegisterApiRoutes::class, [$this, 'addRoutes']); } public function addAttributes(ApiAttributes $event) @@ -17,4 +19,9 @@ class AddApiAttributes $event->attributes['pusherKey'] = app('Flarum\Core\Settings\SettingsRepository')->get('pusher.app_key'); } } + + public function addRoutes(RegisterApiRoutes $event) + { + $event->post('/pusher/auth', 'pusher.auth', 'Flarum\Pusher\Api\AuthAction'); + } } diff --git a/extensions/pusher/src/Listeners/PushNewPosts.php b/extensions/pusher/src/Listeners/PushNewPosts.php index 21ec26358..b48e6101c 100644 --- a/extensions/pusher/src/Listeners/PushNewPosts.php +++ b/extensions/pusher/src/Listeners/PushNewPosts.php @@ -1,6 +1,7 @@ listen(PostWasPosted::class, [$this, 'pushNewPost']); + $events->listen(NotificationWillBeSent::class, [$this, 'pushNotification']); } public function pushNewPost(PostWasPosted $event) { if ($event->post->isVisibleTo(new Guest)) { - $pusher = new Pusher( - $this->settings->get('pusher.app_key'), - $this->settings->get('pusher.app_secret'), - $this->settings->get('pusher.app_id') - ); + $pusher = $this->getPusher(); $pusher->trigger('public', 'newPost', [ 'postId' => $event->post->id, @@ -37,4 +35,25 @@ class PushNewPosts ]); } } + + public function pushNotification(NotificationWillBeSent $event) + { + $pusher = $this->getPusher(); + $blueprint = $event->blueprint; + + foreach ($event->users as $user) { + if ($user->shouldAlert($blueprint::getType())) { + $pusher->trigger('private-user' . $user->id, 'notification', null); + } + } + } + + protected function getPusher() + { + return new Pusher( + $this->settings->get('pusher.app_key'), + $this->settings->get('pusher.app_secret'), + $this->settings->get('pusher.app_id') + ); + } }