mirror of
https://github.com/flarum/core.git
synced 2025-08-08 09:26:34 +02:00
Initial commit
This commit is contained in:
4
extensions/subscriptions/.gitignore
vendored
Normal file
4
extensions/subscriptions/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/vendor
|
||||||
|
composer.phar
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
21
extensions/subscriptions/LICENSE.txt
Normal file
21
extensions/subscriptions/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2015 Toby Zerner
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
9
extensions/subscriptions/bootstrap.php
Normal file
9
extensions/subscriptions/bootstrap.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Require the extension's composer autoload file. This will enable all of our
|
||||||
|
// classes in the src directory to be autoloaded.
|
||||||
|
require __DIR__.'/vendor/autoload.php';
|
||||||
|
|
||||||
|
// Register our service provider with the Flarum application. In here we can
|
||||||
|
// register bindings and execute code when the application boots.
|
||||||
|
return $this->app->register('Flarum\Subscriptions\SubscriptionsServiceProvider');
|
7
extensions/subscriptions/composer.json
Normal file
7
extensions/subscriptions/composer.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Flarum\\Subscriptions\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
extensions/subscriptions/flarum.json
Normal file
16
extensions/subscriptions/flarum.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "flarum-subscriptions",
|
||||||
|
"title": "Subscriptions",
|
||||||
|
"description": "Allow users to follow discussions and receive notifications for new posts.",
|
||||||
|
"tags": [],
|
||||||
|
"version": "0.1.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Toby Zerner",
|
||||||
|
"email": "toby@flarum.org"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.4.0",
|
||||||
|
"flarum": ">0.1.0"
|
||||||
|
}
|
||||||
|
}
|
3
extensions/subscriptions/js/.gitignore
vendored
Normal file
3
extensions/subscriptions/js/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
bower_components
|
||||||
|
node_modules
|
||||||
|
dist
|
5
extensions/subscriptions/js/Gulpfile.js
Normal file
5
extensions/subscriptions/js/Gulpfile.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
var gulp = require('flarum-gulp');
|
||||||
|
|
||||||
|
gulp({
|
||||||
|
modulePrefix: 'flarum-subscriptions'
|
||||||
|
});
|
93
extensions/subscriptions/js/bootstrap.js
vendored
Normal file
93
extensions/subscriptions/js/bootstrap.js
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import { extend, override } from 'flarum/extension-utils';
|
||||||
|
import app from 'flarum/app';
|
||||||
|
import Model from 'flarum/model';
|
||||||
|
import Component from 'flarum/component';
|
||||||
|
import Discussion from 'flarum/models/discussion';
|
||||||
|
import Badge from 'flarum/components/badge';
|
||||||
|
import ActionButton from 'flarum/components/action-button';
|
||||||
|
import SettingsPage from 'flarum/components/settings-page';
|
||||||
|
import DiscussionPage from 'flarum/components/discussion-page';
|
||||||
|
import IndexPage from 'flarum/components/index-page';
|
||||||
|
import IndexNavItem from 'flarum/components/index-nav-item';
|
||||||
|
import DiscussionList from 'flarum/components/discussion-list';
|
||||||
|
import icon from 'flarum/helpers/icon';
|
||||||
|
|
||||||
|
import SubscriptionMenu from 'flarum-subscriptions/components/subscription-menu';
|
||||||
|
import NewPostNotification from 'flarum-subscriptions/components/new-post-notification';
|
||||||
|
|
||||||
|
app.initializers.add('flarum-subscriptions', function() {
|
||||||
|
|
||||||
|
app.notificationComponentRegistry['newPost'] = NewPostNotification;
|
||||||
|
|
||||||
|
Discussion.prototype.subscription = Model.prop('subscription');
|
||||||
|
|
||||||
|
// Add subscription badges to discussions.
|
||||||
|
extend(Discussion.prototype, 'badges', function(badges) {
|
||||||
|
var badge;
|
||||||
|
|
||||||
|
switch (this.subscription()) {
|
||||||
|
case 'follow':
|
||||||
|
badge = Badge.component({ label: 'Following', icon: 'star', className: 'badge-follow' });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ignore':
|
||||||
|
badge = Badge.component({ label: 'Ignoring', icon: 'eye-slash', className: 'badge-ignore' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (badge) {
|
||||||
|
badges.add('subscription', badge);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
extend(Discussion.prototype, 'userControls', function(items, context) {
|
||||||
|
if (app.session.user() && !(context instanceof DiscussionPage)) {
|
||||||
|
var states = {
|
||||||
|
none: {label: 'Follow', icon: 'star', save: 'follow'},
|
||||||
|
follow: {label: 'Unfollow', icon: 'star-o', save: false},
|
||||||
|
ignore: {label: 'Unignore', icon: 'eye', save: false}
|
||||||
|
};
|
||||||
|
var subscription = this.subscription() || 'none';
|
||||||
|
|
||||||
|
items.add('subscription', ActionButton.component({
|
||||||
|
label: states[subscription].label,
|
||||||
|
icon: states[subscription].icon,
|
||||||
|
onclick: this.save.bind(this, {subscription: states[subscription].save})
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
extend(DiscussionPage.prototype, 'sidebarItems', function(items) {
|
||||||
|
if (app.session.user()) {
|
||||||
|
var discussion = this.discussion();
|
||||||
|
items.add('subscription', SubscriptionMenu.component({discussion}), {after: 'controls'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
extend(IndexPage.prototype, 'navItems', function(items) {
|
||||||
|
if (app.session.user()) {
|
||||||
|
var params = this.stickyParams();
|
||||||
|
params.filter = 'following';
|
||||||
|
|
||||||
|
items.add('following', IndexNavItem.component({
|
||||||
|
href: app.route('index.filter', params),
|
||||||
|
label: 'Following',
|
||||||
|
icon: 'star'
|
||||||
|
}), {after: 'allDiscussions'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
extend(DiscussionList.prototype, 'params', function(params) {
|
||||||
|
if (params.filter === 'following') {
|
||||||
|
params.q = (params.q || '')+' is:following';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a notification preference.
|
||||||
|
extend(SettingsPage.prototype, 'notificationTypes', function(items) {
|
||||||
|
items.add('newPost', {
|
||||||
|
name: 'newPost',
|
||||||
|
label: [icon('star'), " Someone posts in a discussion I'm following"]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
7
extensions/subscriptions/js/package.json
Normal file
7
extensions/subscriptions/js/package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "^3.8.11",
|
||||||
|
"flarum-gulp": "git+https://github.com/flarum/gulp.git"
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
import Notification from 'flarum/components/notification';
|
||||||
|
import username from 'flarum/helpers/username';
|
||||||
|
|
||||||
|
export default class NewPostNotification extends Notification {
|
||||||
|
view() {
|
||||||
|
var notification = this.props.notification;
|
||||||
|
var discussion = notification.subject();
|
||||||
|
var content = notification.content() || {};
|
||||||
|
|
||||||
|
return super.view({
|
||||||
|
href: app.route.discussion(discussion, content.postNumber),
|
||||||
|
icon: 'star',
|
||||||
|
content: [username(notification.sender()), ' posted']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,17 @@
|
|||||||
|
import Component from 'flarum/component';
|
||||||
|
import icon from 'flarum/helpers/icon';
|
||||||
|
|
||||||
|
export default class SubscriptionMenuItem extends Component {
|
||||||
|
view() {
|
||||||
|
return m('a.subscription-menu-item.has-icon[href=javascript:;]', {
|
||||||
|
onclick: this.props.onclick
|
||||||
|
}, [
|
||||||
|
this.props.active ? icon('check icon') : '',
|
||||||
|
m('span.label',
|
||||||
|
icon(this.props.icon+' icon'),
|
||||||
|
m('strong', this.props.label),
|
||||||
|
m('span.description', this.props.description)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,54 @@
|
|||||||
|
import Component from 'flarum/component';
|
||||||
|
import ActionButton from 'flarum/components/action-button';
|
||||||
|
import icon from 'flarum/helpers/icon';
|
||||||
|
|
||||||
|
import SubscriptionMenuItem from 'flarum-subscriptions/components/subscription-menu-item';
|
||||||
|
|
||||||
|
export default class SubscriptionMenu extends Component {
|
||||||
|
view() {
|
||||||
|
var discussion = this.props.discussion;
|
||||||
|
var subscription = discussion.subscription();
|
||||||
|
|
||||||
|
var buttonLabel = 'Follow';
|
||||||
|
var buttonIcon = 'star-o';
|
||||||
|
var buttonClass = 'btn-subscription-'+subscription;
|
||||||
|
|
||||||
|
switch (subscription) {
|
||||||
|
case 'follow':
|
||||||
|
buttonLabel = 'Following';
|
||||||
|
buttonIcon = 'star';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ignore':
|
||||||
|
buttonLabel = 'Ignoring';
|
||||||
|
buttonIcon = 'eye-slash';
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = [
|
||||||
|
{subscription: false, icon: 'star-o', label: 'Not Following', description: 'Be notified when @mentioned.'},
|
||||||
|
{subscription: 'follow', icon: 'star', label: 'Following', description: 'Be notified of all replies.'},
|
||||||
|
{subscription: 'ignore', icon: 'eye-slash', label: 'Ignoring', description: 'Never be notified. Hide from the discussion list.'}
|
||||||
|
];
|
||||||
|
|
||||||
|
return m('div.dropdown.btn-group.subscription-menu', [
|
||||||
|
ActionButton.component({
|
||||||
|
className: 'btn btn-default '+buttonClass,
|
||||||
|
icon: buttonIcon,
|
||||||
|
label: buttonLabel,
|
||||||
|
onclick: this.saveSubscription.bind(this, discussion, ['follow', 'ignore'].indexOf(subscription) !== -1 ? false : 'follow')
|
||||||
|
}),
|
||||||
|
|
||||||
|
m('a.dropdown-toggle.btn.btn-default.btn-icon[href=javascript:;][data-toggle=dropdown]', {className: buttonClass}, icon('caret-down icon-caret')),
|
||||||
|
|
||||||
|
m('ul.dropdown-menu.pull-right', options.map(props => {
|
||||||
|
props.onclick = this.saveSubscription.bind(this, discussion, props.subscription);
|
||||||
|
props.active = subscription === props.subscription;
|
||||||
|
return m('li', SubscriptionMenuItem.component(props));
|
||||||
|
}))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSubscription(discussion, subscription) {
|
||||||
|
discussion.save({subscription});
|
||||||
|
}
|
||||||
|
}
|
29
extensions/subscriptions/less/extension.less
Normal file
29
extensions/subscriptions/less/extension.less
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.badge-follow {
|
||||||
|
background: #fc0;
|
||||||
|
}
|
||||||
|
.badge-ignore {
|
||||||
|
background: #aaa;
|
||||||
|
}
|
||||||
|
.btn-subscription-follow {
|
||||||
|
.button-variant(#de8e00, #fff2ae, #fff2ae);
|
||||||
|
}
|
||||||
|
.subscription-menu .dropdown-menu {
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
.subscription-menu-item {
|
||||||
|
& .label {
|
||||||
|
padding-left: 25px;
|
||||||
|
display: block;
|
||||||
|
white-space: normal;
|
||||||
|
|
||||||
|
& strong {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
& .description {
|
||||||
|
display: block;
|
||||||
|
color: @fl-body-muted-color;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
extensions/subscriptions/locale/en.yml
Normal file
2
extensions/subscriptions/locale/en.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
flarum-subscriptions:
|
||||||
|
# hello_world: Hello, world!
|
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddSubscriptionToUsersDiscussionsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
app('db')->getSchemaBuilder()->table('users_discussions', function (Blueprint $table) {
|
||||||
|
$table->enum('subscription', ['follow', 'ignore'])->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
app('db')->getSchemaBuilder()->table('users_discussions', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('subscription');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
72
extensions/subscriptions/src/Handlers/NewPostNotifier.php
Executable file
72
extensions/subscriptions/src/Handlers/NewPostNotifier.php
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php namespace Flarum\Subscriptions\Handlers;
|
||||||
|
|
||||||
|
use Flarum\Subscriptions\NewPostNotification;
|
||||||
|
use Flarum\Core\Events\PostWasPosted;
|
||||||
|
use Flarum\Core\Events\PostWasHidden;
|
||||||
|
use Flarum\Core\Events\PostWasRestored;
|
||||||
|
use Flarum\Core\Events\PostWasDeleted;
|
||||||
|
use Flarum\Core\Notifications\NotificationSyncer;
|
||||||
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
|
|
||||||
|
class NewPostNotifier
|
||||||
|
{
|
||||||
|
protected $notifications;
|
||||||
|
|
||||||
|
public function __construct(NotificationSyncer $notifications)
|
||||||
|
{
|
||||||
|
$this->notifications = $notifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the listeners for the subscriber.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Contracts\Events\Dispatcher $events
|
||||||
|
*/
|
||||||
|
public function subscribe(Dispatcher $events)
|
||||||
|
{
|
||||||
|
// Register with '1' as priority so this runs before discussion metadata
|
||||||
|
// is updated, as we need to compare the user's last read number to that
|
||||||
|
// of the previous post.
|
||||||
|
$events->listen('Flarum\Core\Events\PostWasPosted', __CLASS__.'@whenPostWasPosted', 1);
|
||||||
|
$events->listen('Flarum\Core\Events\PostWasHidden', __CLASS__.'@whenPostWasHidden');
|
||||||
|
$events->listen('Flarum\Core\Events\PostWasRestored', __CLASS__.'@whenPostWasRestored');
|
||||||
|
$events->listen('Flarum\Core\Events\PostWasDeleted', __CLASS__.'@whenPostWasDeleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function whenPostWasPosted(PostWasPosted $event)
|
||||||
|
{
|
||||||
|
$post = $event->post;
|
||||||
|
$discussion = $post->discussion;
|
||||||
|
|
||||||
|
$notify = $discussion->readers()
|
||||||
|
->where('users.id', '!=', $post->user_id)
|
||||||
|
->where('users_discussions.subscription', 'follow')
|
||||||
|
->where('users_discussions.read_number', $discussion->last_post_number)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$this->notifications->sync(
|
||||||
|
$this->getNotification($event->post),
|
||||||
|
$notify->all()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function whenPostWasHidden(PostWasHidden $event)
|
||||||
|
{
|
||||||
|
$this->notifications->delete($this->getNotification($event->post));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function whenPostWasRestored(PostWasRestored $event)
|
||||||
|
{
|
||||||
|
$this->notifications->restore($this->getNotification($event->post));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function whenPostWasDeleted(PostWasDeleted $event)
|
||||||
|
{
|
||||||
|
$this->notifications->delete($this->getNotification($event->post));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getNotification($post)
|
||||||
|
{
|
||||||
|
return new NewPostNotification($post);
|
||||||
|
}
|
||||||
|
}
|
31
extensions/subscriptions/src/Handlers/SubscriptionSaver.php
Executable file
31
extensions/subscriptions/src/Handlers/SubscriptionSaver.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php namespace Flarum\Subscriptions\Handlers;
|
||||||
|
|
||||||
|
use Flarum\Core\Events\DiscussionWillBeSaved;
|
||||||
|
|
||||||
|
class SubscriptionSaver
|
||||||
|
{
|
||||||
|
public function subscribe($events)
|
||||||
|
{
|
||||||
|
$events->listen('Flarum\Core\Events\DiscussionWillBeSaved', __CLASS__.'@whenDiscussionWillBeSaved');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function whenDiscussionWillBeSaved(DiscussionWillBeSaved $event)
|
||||||
|
{
|
||||||
|
$discussion = $event->discussion;
|
||||||
|
$data = $event->command->data;
|
||||||
|
|
||||||
|
if (isset($data['subscription'])) {
|
||||||
|
$user = $event->command->user;
|
||||||
|
$subscription = $data['subscription'];
|
||||||
|
|
||||||
|
$state = $discussion->stateFor($user);
|
||||||
|
|
||||||
|
if (! in_array($subscription, ['follow', 'ignore'])) {
|
||||||
|
$subscription = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$state->subscription = $subscription;
|
||||||
|
$state->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
extensions/subscriptions/src/Handlers/SubscriptionSearchModifier.php
Executable file
26
extensions/subscriptions/src/Handlers/SubscriptionSearchModifier.php
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php namespace Flarum\Subscriptions\Handlers;
|
||||||
|
|
||||||
|
use Flarum\Core\Events\DiscussionSearchWillBePerformed;
|
||||||
|
|
||||||
|
class SubscriptionSearchModifier
|
||||||
|
{
|
||||||
|
public function subscribe($events)
|
||||||
|
{
|
||||||
|
$events->listen('Flarum\Core\Events\DiscussionSearchWillBePerformed', __CLASS__.'@filterIgnored');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filterIgnored(DiscussionSearchWillBePerformed $event)
|
||||||
|
{
|
||||||
|
if (! $event->criteria->query) {
|
||||||
|
// might be better as `id IN (subquery)`?
|
||||||
|
$user = $event->criteria->user;
|
||||||
|
$event->searcher->getQuery()->whereNotExists(function ($query) use ($user) {
|
||||||
|
$query->select(app('db')->raw(1))
|
||||||
|
->from('users_discussions')
|
||||||
|
->whereRaw('discussion_id = discussions.id')
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->where('subscription', 'ignore');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
extensions/subscriptions/src/NewPostNotification.php
Normal file
55
extensions/subscriptions/src/NewPostNotification.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php namespace Flarum\Subscriptions;
|
||||||
|
|
||||||
|
use Flarum\Core\Models\Post;
|
||||||
|
use Flarum\Core\Models\User;
|
||||||
|
use Flarum\Core\Notifications\NotificationAbstract;
|
||||||
|
|
||||||
|
class NewPostNotification extends NotificationAbstract
|
||||||
|
{
|
||||||
|
public $post;
|
||||||
|
|
||||||
|
public function __construct(Post $post)
|
||||||
|
{
|
||||||
|
$this->post = $post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubject()
|
||||||
|
{
|
||||||
|
return $this->post->discussion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSender()
|
||||||
|
{
|
||||||
|
return $this->post->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return ['postNumber' => (int) $this->post->number];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmailView()
|
||||||
|
{
|
||||||
|
return ['text' => 'flarum-subscriptions::emails.newPost'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmailSubject()
|
||||||
|
{
|
||||||
|
return '[New Post] '.$this->post->discussion->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getType()
|
||||||
|
{
|
||||||
|
return 'newPost';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubjectModel()
|
||||||
|
{
|
||||||
|
return 'Flarum\Core\Models\Discussion';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isEmailable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
37
extensions/subscriptions/src/SubscriptionGambit.php
Normal file
37
extensions/subscriptions/src/SubscriptionGambit.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php namespace Flarum\Subscriptions;
|
||||||
|
|
||||||
|
use Flarum\Core\Search\SearcherInterface;
|
||||||
|
use Flarum\Core\Search\GambitAbstract;
|
||||||
|
|
||||||
|
class SubscriptionGambit extends GambitAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The gambit's regex pattern.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $pattern = 'is:(follow|ignor)(?:ing|ed)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply conditions to the searcher, given matches from the gambit's
|
||||||
|
* regex.
|
||||||
|
*
|
||||||
|
* @param array $matches The matches from the gambit's regex.
|
||||||
|
* @param \Flarum\Core\Search\SearcherInterface $searcher
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function conditions(SearcherInterface $searcher, array $matches, $negate)
|
||||||
|
{
|
||||||
|
$user = $searcher->getUser();
|
||||||
|
|
||||||
|
// might be better as `id IN (subquery)`?
|
||||||
|
$method = $negate ? 'whereNotExists' : 'whereExists';
|
||||||
|
$searcher->getQuery()->$method(function ($query) use ($user, $matches) {
|
||||||
|
$query->select(app('db')->raw(1))
|
||||||
|
->from('users_discussions')
|
||||||
|
->whereRaw('discussion_id = discussions.id')
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->where('subscription', $matches[1] === 'follow' ? 'follow' : 'ignore');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,59 @@
|
|||||||
|
<?php namespace Flarum\Subscriptions;
|
||||||
|
|
||||||
|
use Flarum\Support\ServiceProvider;
|
||||||
|
use Flarum\Extend;
|
||||||
|
|
||||||
|
class SubscriptionsServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap the application events.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
$this->loadViewsFrom(__DIR__.'/../views', 'flarum-subscriptions');
|
||||||
|
|
||||||
|
$this->extend([
|
||||||
|
(new Extend\Locale('en'))->translations(__DIR__.'/../locale/en.yml'),
|
||||||
|
|
||||||
|
(new Extend\ForumClient())
|
||||||
|
->assets([
|
||||||
|
__DIR__.'/../js/dist/extension.js',
|
||||||
|
__DIR__.'/../less/extension.less'
|
||||||
|
])
|
||||||
|
->translations([
|
||||||
|
// Add the keys of translations you would like to be available
|
||||||
|
// for use by the JS client application.
|
||||||
|
])
|
||||||
|
->route('get', '/following', 'flarum.forum.following'),
|
||||||
|
|
||||||
|
(new Extend\ApiSerializer('Flarum\Api\Serializers\DiscussionSerializer'))
|
||||||
|
->attributes(function (&$attributes, $discussion, $user) {
|
||||||
|
if ($state = $discussion->stateFor($user)) {
|
||||||
|
$attributes['subscription'] = $state->subscription ?: false;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
new Extend\EventSubscriber('Flarum\Subscriptions\Handlers\SubscriptionSaver'),
|
||||||
|
new Extend\EventSubscriber('Flarum\Subscriptions\Handlers\SubscriptionSearchModifier'),
|
||||||
|
new Extend\EventSubscriber('Flarum\Subscriptions\Handlers\NewPostNotifier'),
|
||||||
|
|
||||||
|
new Extend\DiscussionGambit('Flarum\Subscriptions\SubscriptionGambit'),
|
||||||
|
|
||||||
|
(new Extend\NotificationType('Flarum\Subscriptions\NewPostNotification', 'Flarum\Api\Serializers\DiscussionBasicSerializer'))
|
||||||
|
->enableByDefault('alert')
|
||||||
|
->enableByDefault('email')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the service provider.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
14
extensions/subscriptions/views/emails/newPost.blade.php
Normal file
14
extensions/subscriptions/views/emails/newPost.blade.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Hey {{ $user->username }}!
|
||||||
|
|
||||||
|
{{ $notification->post->user->username }} made a post in a discussion you're following: {{ $notification->post->discussion->title }}
|
||||||
|
|
||||||
|
To view the new activity, check out the following link:
|
||||||
|
{{ \Flarum\Core::config('base_url') }}/d/{{ $notification->post->discussion_id }}/-/{{ $notification->post->number }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{ strip_tags($notification->post->contentHtml) }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
You won't receive any more notifications about this discussion until you're up-to-date.
|
Reference in New Issue
Block a user