diff --git a/extensions/sticky/.gitignore b/extensions/sticky/.gitignore index a4f3b125e..4181b9dca 100644 --- a/extensions/sticky/.gitignore +++ b/extensions/sticky/.gitignore @@ -2,3 +2,5 @@ composer.phar .DS_Store Thumbs.db +node_modules +bower_components \ No newline at end of file diff --git a/extensions/sticky/bootstrap.php b/extensions/sticky/bootstrap.php index bc8469b1e..19076c02e 100644 --- a/extensions/sticky/bootstrap.php +++ b/extensions/sticky/bootstrap.php @@ -9,6 +9,13 @@ * file that was distributed with this source code. */ -require __DIR__.'/vendor/autoload.php'; +use Flarum\Sticky\Listener; +use Illuminate\Contracts\Events\Dispatcher; -return 'Flarum\Sticky\Extension'; +return function (Dispatcher $events) { + $events->subscribe(Listener\AddApiAttributes::class); + $events->subscribe(Listener\AddClientAssets::class); + $events->subscribe(Listener\CreatePostWhenDiscussionIsStickied::class); + $events->subscribe(Listener\PinStickiedDiscussionsToTop::class); + $events->subscribe(Listener\SaveStickyToDatabase::class); +}; diff --git a/extensions/sticky/composer.json b/extensions/sticky/composer.json index 71d98ca20..866ef4545 100644 --- a/extensions/sticky/composer.json +++ b/extensions/sticky/composer.json @@ -1,10 +1,34 @@ { + "name": "flarum/sticky", + "description": "Pin discussions to the top of the list.", + "type": "flarum-extension", + "license": "MIT", + "authors": [ + { + "name": "Toby Zerner", + "email": "toby.zerner@gmail.com" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/sticky" + }, + "require": { + "flarum/core": "^0.1.0-beta.3" + }, "autoload": { "psr-4": { "Flarum\\Sticky\\": "src/" } }, - "scripts": { - "style": "phpcs --standard=PSR2 -np src" + "extra": { + "flarum-extension": { + "title": "Sticky", + "icon": { + "name": "thumb-tack", + "backgroundColor": "#D13E32", + "color": "#fff" + } + } } } diff --git a/extensions/sticky/flarum.json b/extensions/sticky/flarum.json deleted file mode 100644 index a63475675..000000000 --- a/extensions/sticky/flarum.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "sticky", - "title": "Sticky", - "description": "Pin discussions to the top of the list.", - "keywords": ["moderation"], - "version": "0.1.0-beta.2", - "author": { - "name": "Toby Zerner", - "email": "toby@flarum.org", - "homepage": "http://tobyzerner.com" - }, - "license": "MIT", - "require": { - "flarum": ">=0.1.0-beta.2" - }, - "support": { - "source": "https://github.com/flarum/sticky", - "issues": "https://github.com/flarum/core/issues" - }, - "icon": { - "name": "thumb-tack", - "backgroundColor": "#D13E32", - "color": "#fff" - } -} diff --git a/extensions/sticky/js/.gitignore b/extensions/sticky/js/.gitignore deleted file mode 100644 index bae304483..000000000 --- a/extensions/sticky/js/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -bower_components -node_modules -mithril.js -dist diff --git a/extensions/sticky/js/admin/Gulpfile.js b/extensions/sticky/js/admin/Gulpfile.js index 2cf16b3ea..c2cebeaf6 100644 --- a/extensions/sticky/js/admin/Gulpfile.js +++ b/extensions/sticky/js/admin/Gulpfile.js @@ -2,6 +2,6 @@ var gulp = require('flarum-gulp'); gulp({ modules: { - 'sticky': 'src/**/*.js' + 'flarum/sticky': 'src/**/*.js' } }); diff --git a/extensions/sticky/js/admin/dist/extension.js b/extensions/sticky/js/admin/dist/extension.js new file mode 100644 index 000000000..ec8f3ac3b --- /dev/null +++ b/extensions/sticky/js/admin/dist/extension.js @@ -0,0 +1,26 @@ +System.register('flarum/sticky/main', ['flarum/extend', 'flarum/app', 'flarum/components/PermissionGrid'], function (_export) { + 'use strict'; + + var extend, app, PermissionGrid; + return { + setters: [function (_flarumExtend) { + extend = _flarumExtend.extend; + }, function (_flarumApp) { + app = _flarumApp['default']; + }, function (_flarumComponentsPermissionGrid) { + PermissionGrid = _flarumComponentsPermissionGrid['default']; + }], + execute: function () { + + app.initializers.add('sticky', function () { + extend(PermissionGrid.prototype, 'moderateItems', function (items) { + items.add('sticky', { + icon: 'thumb-tack', + label: 'Sticky discussions', + permission: 'discussion.sticky' + }, 95); + }); + }); + } + }; +}); \ No newline at end of file diff --git a/extensions/sticky/js/forum/Gulpfile.js b/extensions/sticky/js/forum/Gulpfile.js index 2cf16b3ea..c2cebeaf6 100644 --- a/extensions/sticky/js/forum/Gulpfile.js +++ b/extensions/sticky/js/forum/Gulpfile.js @@ -2,6 +2,6 @@ var gulp = require('flarum-gulp'); gulp({ modules: { - 'sticky': 'src/**/*.js' + 'flarum/sticky': 'src/**/*.js' } }); diff --git a/extensions/sticky/js/forum/dist/extension.js b/extensions/sticky/js/forum/dist/extension.js new file mode 100644 index 000000000..33fd2484a --- /dev/null +++ b/extensions/sticky/js/forum/dist/extension.js @@ -0,0 +1,224 @@ +System.register('flarum/sticky/addStickyBadge', ['flarum/extend', 'flarum/models/Discussion', 'flarum/components/Badge'], function (_export) { + 'use strict'; + + var extend, Discussion, Badge; + + _export('default', addStickyBadge); + + function addStickyBadge() { + extend(Discussion.prototype, 'badges', function (badges) { + if (this.isSticky()) { + badges.add('sticky', Badge.component({ + type: 'sticky', + label: app.trans('flarum-sticky.forum.stickied'), + icon: 'thumb-tack' + }), 10); + } + }); + } + + return { + setters: [function (_flarumExtend) { + extend = _flarumExtend.extend; + }, function (_flarumModelsDiscussion) { + Discussion = _flarumModelsDiscussion['default']; + }, function (_flarumComponentsBadge) { + Badge = _flarumComponentsBadge['default']; + }], + execute: function () {} + }; +});;System.register('flarum/sticky/addStickyControl', ['flarum/extend', 'flarum/utils/DiscussionControls', 'flarum/components/DiscussionPage', 'flarum/components/Button'], function (_export) { + 'use strict'; + + var extend, DiscussionControls, DiscussionPage, Button; + + _export('default', addStickyControl); + + function addStickyControl() { + extend(DiscussionControls, 'moderationControls', function (items, discussion) { + if (discussion.canSticky()) { + items.add('sticky', Button.component({ + children: app.trans(discussion.isSticky() ? 'flarum-sticky.forum.unsticky' : 'flarum-sticky.forum.sticky'), + icon: 'thumb-tack', + onclick: this.stickyAction.bind(discussion) + })); + } + }); + + DiscussionControls.stickyAction = function () { + this.save({ isSticky: !this.isSticky() }).then(function () { + if (app.current instanceof DiscussionPage) { + app.current.stream.update(); + } + + m.redraw(); + }); + }; + } + + return { + setters: [function (_flarumExtend) { + extend = _flarumExtend.extend; + }, function (_flarumUtilsDiscussionControls) { + DiscussionControls = _flarumUtilsDiscussionControls['default']; + }, function (_flarumComponentsDiscussionPage) { + DiscussionPage = _flarumComponentsDiscussionPage['default']; + }, function (_flarumComponentsButton) { + Button = _flarumComponentsButton['default']; + }], + execute: function () {} + }; +});;System.register('flarum/sticky/addStickyExcerpt', ['flarum/extend', 'flarum/components/DiscussionList', 'flarum/components/DiscussionListItem', 'flarum/utils/string'], function (_export) { + 'use strict'; + + var extend, DiscussionList, DiscussionListItem, truncate; + + _export('default', addStickyControl); + + function addStickyControl() { + extend(DiscussionList.prototype, 'requestParams', function (params) { + params.include.push('startPost'); + }); + + extend(DiscussionListItem.prototype, 'infoItems', function (items) { + var discussion = this.props.discussion; + + if (discussion.isSticky()) { + var startPost = discussion.startPost(); + + if (startPost) { + var excerpt = m( + 'span', + null, + truncate(startPost.contentPlain(), 200) + ); + + items.add('excerpt', excerpt, -100); + } + } + }); + } + + return { + setters: [function (_flarumExtend) { + extend = _flarumExtend.extend; + }, function (_flarumComponentsDiscussionList) { + DiscussionList = _flarumComponentsDiscussionList['default']; + }, function (_flarumComponentsDiscussionListItem) { + DiscussionListItem = _flarumComponentsDiscussionListItem['default']; + }, function (_flarumUtilsString) { + truncate = _flarumUtilsString.truncate; + }], + execute: function () {} + }; +});;System.register('flarum/sticky/main', ['flarum/extend', 'flarum/app', 'flarum/Model', 'flarum/models/Discussion', 'flarum/sticky/components/DiscussionStickiedPost', 'flarum/sticky/addStickyBadge', 'flarum/sticky/addStickyControl', 'flarum/sticky/addStickyExcerpt'], function (_export) { + 'use strict'; + + var extend, notificationType, app, Model, Discussion, DiscussionStickiedPost, addStickyBadge, addStickyControl, addStickyExcerpt; + return { + setters: [function (_flarumExtend) { + extend = _flarumExtend.extend; + notificationType = _flarumExtend.notificationType; + }, function (_flarumApp) { + app = _flarumApp['default']; + }, function (_flarumModel) { + Model = _flarumModel['default']; + }, function (_flarumModelsDiscussion) { + Discussion = _flarumModelsDiscussion['default']; + }, function (_flarumStickyComponentsDiscussionStickiedPost) { + DiscussionStickiedPost = _flarumStickyComponentsDiscussionStickiedPost['default']; + }, function (_flarumStickyAddStickyBadge) { + addStickyBadge = _flarumStickyAddStickyBadge['default']; + }, function (_flarumStickyAddStickyControl) { + addStickyControl = _flarumStickyAddStickyControl['default']; + }, function (_flarumStickyAddStickyExcerpt) { + addStickyExcerpt = _flarumStickyAddStickyExcerpt['default']; + }], + execute: function () { + + app.postComponents.discussionStickied = DiscussionStickiedPost; + + Discussion.prototype.isSticky = Model.attribute('isSticky'); + Discussion.prototype.canSticky = Model.attribute('canSticky'); + + addStickyBadge(); + addStickyControl(); + addStickyExcerpt(); + } + }; +});;System.register('flarum/sticky/components/DiscussionStickiedNotification', ['flarum/components/Notification'], function (_export) { + 'use strict'; + + var Notification, DiscussionStickiedNotification; + return { + setters: [function (_flarumComponentsNotification) { + Notification = _flarumComponentsNotification['default']; + }], + execute: function () { + DiscussionStickiedNotification = (function (_Notification) { + babelHelpers.inherits(DiscussionStickiedNotification, _Notification); + + function DiscussionStickiedNotification() { + babelHelpers.classCallCheck(this, DiscussionStickiedNotification); + babelHelpers.get(Object.getPrototypeOf(DiscussionStickiedNotification.prototype), 'constructor', this).apply(this, arguments); + } + + babelHelpers.createClass(DiscussionStickiedNotification, [{ + key: 'icon', + value: function icon() { + return 'thumb-tack'; + } + }, { + key: 'href', + value: function href() { + var notification = this.props.notification; + + return app.route.discussion(notification.subject(), notification.content().postNumber); + } + }, { + key: 'content', + value: function content() { + return app.trans('flarum-sticky.forum.discussion_stickied_notification', { user: this.props.notification.sender() }); + } + }]); + return DiscussionStickiedNotification; + })(Notification); + + _export('default', DiscussionStickiedNotification); + } + }; +});;System.register('flarum/sticky/components/DiscussionStickiedPost', ['flarum/components/EventPost'], function (_export) { + 'use strict'; + + var EventPost, DiscussionStickiedPost; + return { + setters: [function (_flarumComponentsEventPost) { + EventPost = _flarumComponentsEventPost['default']; + }], + execute: function () { + DiscussionStickiedPost = (function (_EventPost) { + babelHelpers.inherits(DiscussionStickiedPost, _EventPost); + + function DiscussionStickiedPost() { + babelHelpers.classCallCheck(this, DiscussionStickiedPost); + babelHelpers.get(Object.getPrototypeOf(DiscussionStickiedPost.prototype), 'constructor', this).apply(this, arguments); + } + + babelHelpers.createClass(DiscussionStickiedPost, [{ + key: 'icon', + value: function icon() { + return 'thumb-tack'; + } + }, { + key: 'descriptionKey', + value: function descriptionKey() { + return this.props.post.content().sticky ? 'flarum-sticky.forum.discussion_stickied_post' : 'flarum-sticky.forum.discussion_unstickied_post'; + } + }]); + return DiscussionStickiedPost; + })(EventPost); + + _export('default', DiscussionStickiedPost); + } + }; +}); \ No newline at end of file diff --git a/extensions/sticky/js/forum/src/addStickyBadge.js b/extensions/sticky/js/forum/src/addStickyBadge.js index 1566c3434..4c1bbd5bb 100644 --- a/extensions/sticky/js/forum/src/addStickyBadge.js +++ b/extensions/sticky/js/forum/src/addStickyBadge.js @@ -7,7 +7,7 @@ export default function addStickyBadge() { if (this.isSticky()) { badges.add('sticky', Badge.component({ type: 'sticky', - label: app.trans('sticky.stickied'), + label: app.trans('flarum-sticky.forum.stickied'), icon: 'thumb-tack' }), 10); } diff --git a/extensions/sticky/js/forum/src/addStickyControl.js b/extensions/sticky/js/forum/src/addStickyControl.js index e7651fd23..25f55921c 100644 --- a/extensions/sticky/js/forum/src/addStickyControl.js +++ b/extensions/sticky/js/forum/src/addStickyControl.js @@ -7,7 +7,7 @@ export default function addStickyControl() { extend(DiscussionControls, 'moderationControls', function(items, discussion) { if (discussion.canSticky()) { items.add('sticky', Button.component({ - children: app.trans(discussion.isSticky() ? 'sticky.unsticky' : 'sticky.sticky'), + children: app.trans(discussion.isSticky() ? 'flarum-sticky.forum.unsticky' : 'flarum-sticky.forum.sticky'), icon: 'thumb-tack', onclick: this.stickyAction.bind(discussion) })); diff --git a/extensions/sticky/js/forum/src/components/DiscussionStickiedNotification.js b/extensions/sticky/js/forum/src/components/DiscussionStickiedNotification.js index cc99d9a35..b69eef231 100644 --- a/extensions/sticky/js/forum/src/components/DiscussionStickiedNotification.js +++ b/extensions/sticky/js/forum/src/components/DiscussionStickiedNotification.js @@ -12,6 +12,6 @@ export default class DiscussionStickiedNotification extends Notification { } content() { - return app.trans('sticky.discussion_stickied_notification', {user: this.props.notification.sender()}); + return app.trans('flarum-sticky.forum.discussion_stickied_notification', {user: this.props.notification.sender()}); } } diff --git a/extensions/sticky/js/forum/src/components/DiscussionStickiedPost.js b/extensions/sticky/js/forum/src/components/DiscussionStickiedPost.js index 5b3408e69..613c46683 100644 --- a/extensions/sticky/js/forum/src/components/DiscussionStickiedPost.js +++ b/extensions/sticky/js/forum/src/components/DiscussionStickiedPost.js @@ -7,7 +7,7 @@ export default class DiscussionStickiedPost extends EventPost { descriptionKey() { return this.props.post.content().sticky - ? 'sticky.discussion_stickied_post' - : 'sticky.discussion_unstickied_post'; + ? 'flarum-sticky.forum.discussion_stickied_post' + : 'flarum-sticky.forum.discussion_unstickied_post'; } } diff --git a/extensions/sticky/js/forum/src/main.js b/extensions/sticky/js/forum/src/main.js index 655a9b09d..3b3a1b493 100644 --- a/extensions/sticky/js/forum/src/main.js +++ b/extensions/sticky/js/forum/src/main.js @@ -2,28 +2,17 @@ import { extend, notificationType } from 'flarum/extend'; import app from 'flarum/app'; import Model from 'flarum/Model'; import Discussion from 'flarum/models/Discussion'; -import NotificationGrid from 'flarum/components/NotificationGrid'; -import DiscussionStickiedPost from 'sticky/components/DiscussionStickiedPost'; -import DiscussionStickiedNotification from 'sticky/components/DiscussionStickiedNotification'; -import addStickyBadge from 'sticky/addStickyBadge'; -import addStickyControl from 'sticky/addStickyControl'; -import addStickyExcerpt from 'sticky/addStickyExcerpt'; +import DiscussionStickiedPost from 'flarum/sticky/components/DiscussionStickiedPost'; +import addStickyBadge from 'flarum/sticky/addStickyBadge'; +import addStickyControl from 'flarum/sticky/addStickyControl'; +import addStickyExcerpt from 'flarum/sticky/addStickyExcerpt'; app.postComponents.discussionStickied = DiscussionStickiedPost; -app.notificationComponents.discussionStickied = DiscussionStickiedNotification; Discussion.prototype.isSticky = Model.attribute('isSticky'); Discussion.prototype.canSticky = Model.attribute('canSticky'); addStickyBadge(); addStickyControl(); -addStickyExcerpt(); - -extend(NotificationGrid.prototype, 'notificationTypes', function(items) { - items.add('discussionStickied', { - name: 'discussionStickied', - icon: 'thumb-tack', - label: app.trans('sticky.notify_discussion_stickied') - }); -}); +addStickyExcerpt(); \ No newline at end of file diff --git a/extensions/sticky/locale/en.yml b/extensions/sticky/locale/en.yml deleted file mode 100644 index b871de0d5..000000000 --- a/extensions/sticky/locale/en.yml +++ /dev/null @@ -1,8 +0,0 @@ -sticky: - discussion_stickied_notification: "{username} stickied" - discussion_stickied_post: "{username} stickied the discussion." - discussion_unstickied_post: "{username} unstickied the discussion." - notify_discussion_stickied: Someone stickies a discussion I started - stickied: Sticky - sticky: Sticky - unsticky: Unsticky diff --git a/extensions/sticky/migrations/2015_02_24_000000_add_sticky_to_discussions.php b/extensions/sticky/migrations/2015_02_24_000000_add_sticky_to_discussions.php index a603891cc..aded7e5c9 100644 --- a/extensions/sticky/migrations/2015_02_24_000000_add_sticky_to_discussions.php +++ b/extensions/sticky/migrations/2015_02_24_000000_add_sticky_to_discussions.php @@ -8,18 +8,13 @@ * file that was distributed with this source code. */ -namespace Flarum\Migrations\Sticky; +namespace Flarum\Sticky\Migration; +use Flarum\Database\AbstractMigration; use Illuminate\Database\Schema\Blueprint; -use Flarum\Migrations\Migration; -class AddStickyToDiscussions extends Migration +class AddStickyToDiscussions extends AbstractMigration { - /** - * Run the migrations. - * - * @return void - */ public function up() { $this->schema->table('discussions', function (Blueprint $table) { @@ -27,11 +22,6 @@ class AddStickyToDiscussions extends Migration }); } - /** - * Reverse the migrations. - * - * @return void - */ public function down() { $this->schema->table('discussions', function (Blueprint $table) { diff --git a/extensions/sticky/scripts/compile.sh b/extensions/sticky/scripts/compile.sh new file mode 100755 index 000000000..b0d8e8bd3 --- /dev/null +++ b/extensions/sticky/scripts/compile.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# This script compiles the extension so that it can be used in a Flarum +# installation. It should be run from the root directory of the extension. + +base=$PWD + +cd "${base}/js" + +if [ -f bower.json ]; then + bower install +fi + +for app in forum admin; do + cd "${base}/js" + + if [ -d $app ]; then + cd $app + + if [ -f bower.json ]; then + bower install + fi + + npm install + gulp --production + fi +done diff --git a/extensions/sticky/src/Events/DiscussionWasStickied.php b/extensions/sticky/src/Event/DiscussionWasStickied.php similarity index 85% rename from extensions/sticky/src/Events/DiscussionWasStickied.php rename to extensions/sticky/src/Event/DiscussionWasStickied.php index da2ed195d..cef0dc958 100644 --- a/extensions/sticky/src/Events/DiscussionWasStickied.php +++ b/extensions/sticky/src/Event/DiscussionWasStickied.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Flarum\Sticky\Events; +namespace Flarum\Sticky\Event; -use Flarum\Core\Discussions\Discussion; -use Flarum\Core\Users\User; +use Flarum\Core\Discussion; +use Flarum\Core\User; class DiscussionWasStickied { diff --git a/extensions/sticky/src/Events/DiscussionWasUnstickied.php b/extensions/sticky/src/Event/DiscussionWasUnstickied.php similarity index 85% rename from extensions/sticky/src/Events/DiscussionWasUnstickied.php rename to extensions/sticky/src/Event/DiscussionWasUnstickied.php index 06b07799d..5a39c71f6 100644 --- a/extensions/sticky/src/Events/DiscussionWasUnstickied.php +++ b/extensions/sticky/src/Event/DiscussionWasUnstickied.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Flarum\Sticky\Events; +namespace Flarum\Sticky\Event; -use Flarum\Core\Discussions\Discussion; -use Flarum\Core\Users\User; +use Flarum\Core\Discussion; +use Flarum\Core\User; class DiscussionWasUnstickied { diff --git a/extensions/sticky/src/Extension.php b/extensions/sticky/src/Extension.php deleted file mode 100644 index 96373f954..000000000 --- a/extensions/sticky/src/Extension.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky; - -use Flarum\Support\Extension as BaseExtension; -use Illuminate\Events\Dispatcher; - -class Extension extends BaseExtension -{ - public function listen(Dispatcher $events) - { - $events->subscribe('Flarum\Sticky\Listeners\AddClientAssets'); - $events->subscribe('Flarum\Sticky\Listeners\AddApiAttributes'); - $events->subscribe('Flarum\Sticky\Listeners\PersistData'); - $events->subscribe('Flarum\Sticky\Listeners\PinStickiedDiscussionsToTop'); - $events->subscribe('Flarum\Sticky\Listeners\NotifyDiscussionStickied'); - } -} diff --git a/extensions/sticky/src/Gambit/StickyGambit.php b/extensions/sticky/src/Gambit/StickyGambit.php new file mode 100644 index 000000000..d21021a4e --- /dev/null +++ b/extensions/sticky/src/Gambit/StickyGambit.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Sticky\Gambit; + +use Flarum\Core\Search\AbstractSearch; +use Flarum\Core\Search\AbstractRegexGambit; + +class StickyGambit extends AbstractRegexGambit +{ + /** + * {@inheritdoc} + */ + protected $pattern = 'is:sticky'; + + /** + * {@inheritdoc} + */ + protected function conditions(AbstractSearch $search, array $matches, $negate) + { + $search->getQuery()->where('is_sticky', ! $negate); + } +} diff --git a/extensions/sticky/src/Gambits/StickyGambit.php b/extensions/sticky/src/Gambits/StickyGambit.php deleted file mode 100644 index a8639b72b..000000000 --- a/extensions/sticky/src/Gambits/StickyGambit.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky\Gambits; - -use Flarum\Core\Search\Search; -use Flarum\Core\Search\RegexGambit; - -class StickyGambit extends RegexGambit -{ - /** - * The gambit's regex pattern. - * - * @var string - */ - protected $pattern = 'is:sticky'; - - /** - * 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(Search $search, array $matches, $negate) - { - $search->getQuery()->where('is_sticky', ! $negate); - } -} diff --git a/extensions/sticky/src/Listener/AddApiAttributes.php b/extensions/sticky/src/Listener/AddApiAttributes.php new file mode 100755 index 000000000..d82c98f3e --- /dev/null +++ b/extensions/sticky/src/Listener/AddApiAttributes.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Sticky\Listener; + +use Flarum\Api\Controller\ListDiscussionsController; +use Flarum\Api\Serializer\DiscussionSerializer; +use Flarum\Event\ConfigureApiController; +use Flarum\Event\PrepareApiAttributes; +use Illuminate\Contracts\Events\Dispatcher; + +class AddApiAttributes +{ + /** + * @param Dispatcher $events + */ + public function subscribe(Dispatcher $events) + { + $events->listen(PrepareApiAttributes::class, [$this, 'prepareApiAttributes']); + $events->listen(ConfigureApiController::class, [$this, 'includeStartPost']); + } + + /** + * @param PrepareApiAttributes $event + */ + public function prepareApiAttributes(PrepareApiAttributes $event) + { + if ($event->isSerializer(DiscussionSerializer::class)) { + $event->attributes['isSticky'] = (bool) $event->model->is_sticky; + $event->attributes['canSticky'] = (bool) $event->actor->can('sticky', $event->model); + } + } + + /** + * @param ConfigureApiController $event + */ + public function includeStartPost(ConfigureApiController $event) + { + if ($event->isController(ListDiscussionsController::class)) { + $event->addInclude('startPost'); + } + } +} diff --git a/extensions/sticky/src/Listener/AddClientAssets.php b/extensions/sticky/src/Listener/AddClientAssets.php new file mode 100755 index 000000000..26fb77f1d --- /dev/null +++ b/extensions/sticky/src/Listener/AddClientAssets.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Sticky\Listener; + +use Flarum\Event\ConfigureClientView; +use Illuminate\Contracts\Events\Dispatcher; + +class AddClientAssets +{ + /** + * @param Dispatcher $events + */ + public function subscribe(Dispatcher $events) + { + $events->listen(ConfigureClientView::class, [$this, 'addAssets']); + } + + /** + * @param ConfigureClientView $event + */ + public function addAssets(ConfigureClientView $event) + { + if ($event->isForum()) { + $event->addAssets([ + __DIR__.'/../../js/forum/dist/extension.js', + __DIR__.'/../../less/forum/extension.less' + ]); + $event->addBootstrapper('flarum/sticky/main'); + $event->addTranslations('flarum-sticky.forum'); + } + + if ($event->isAdmin()) { + $event->addAssets([ + __DIR__.'/../../js/admin/dist/extension.js' + ]); + $event->addBootstrapper('flarum/sticky/main'); + } + } +} diff --git a/extensions/sticky/src/Listener/CreatePostWhenDiscussionIsStickied.php b/extensions/sticky/src/Listener/CreatePostWhenDiscussionIsStickied.php new file mode 100755 index 000000000..242411eaf --- /dev/null +++ b/extensions/sticky/src/Listener/CreatePostWhenDiscussionIsStickied.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Sticky\Listener; + +use Flarum\Core\Discussion; +use Flarum\Core\User; +use Flarum\Event\ConfigurePostTypes; +use Flarum\Sticky\Event\DiscussionWasStickied; +use Flarum\Sticky\Event\DiscussionWasUnstickied; +use Flarum\Sticky\Post\DiscussionStickiedPost; +use Illuminate\Contracts\Events\Dispatcher; + +class CreatePostWhenDiscussionIsStickied +{ + /** + * @param Dispatcher $events + */ + public function subscribe(Dispatcher $events) + { + $events->listen(ConfigurePostTypes::class, [$this, 'configurePostTypes']); + $events->listen(DiscussionWasStickied::class, [$this, 'whenDiscussionWasStickied']); + $events->listen(DiscussionWasUnstickied::class, [$this, 'whenDiscussionWasUnstickied']); + } + + /** + * @param ConfigurePostTypes $event + */ + public function configurePostTypes(ConfigurePostTypes $event) + { + $event->add(DiscussionStickiedPost::class); + } + + /** + * @param DiscussionWasStickied $event + */ + public function whenDiscussionWasStickied(DiscussionWasStickied $event) + { + $this->stickyChanged($event->discussion, $event->user, true); + } + + /** + * @param DiscussionWasUnstickied $event + */ + public function whenDiscussionWasUnstickied(DiscussionWasUnstickied $event) + { + $this->stickyChanged($event->discussion, $event->user, false); + } + + /** + * @param Discussion $discussion + * @param User $user + * @param bool $isSticky + */ + protected function stickyChanged(Discussion $discussion, User $user, $isSticky) + { + $post = DiscussionStickiedPost::reply( + $discussion->id, + $user->id, + $isSticky + ); + + $discussion->mergePost($post); + } +} diff --git a/extensions/sticky/src/Listener/PinStickiedDiscussionsToTop.php b/extensions/sticky/src/Listener/PinStickiedDiscussionsToTop.php new file mode 100755 index 000000000..960ebf27d --- /dev/null +++ b/extensions/sticky/src/Listener/PinStickiedDiscussionsToTop.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Sticky\Listener; + +use Flarum\Event\ConfigureDiscussionGambits; +use Flarum\Event\DiscussionSearchWillBePerformed; +use Flarum\Sticky\Gambit\StickyGambit; +use Flarum\Tags\Gambit\TagGambit; +use Illuminate\Contracts\Events\Dispatcher; + +class PinStickiedDiscussionsToTop +{ + /** + * @param Dispatcher $events + */ + public function subscribe(Dispatcher $events) + { + $events->listen(ConfigureDiscussionGambits::class, [$this, 'addStickyGambit']); + $events->listen(DiscussionSearchWillBePerformed::class, [$this, 'reorderSearch']); + } + + /** + * @param ConfigureDiscussionGambits $event + */ + public function addStickyGambit(ConfigureDiscussionGambits $event) + { + $event->gambits->add(StickyGambit::class); + } + + /** + * @param DiscussionSearchWillBePerformed $event + */ + public function reorderSearch(DiscussionSearchWillBePerformed $event) + { + if ($event->criteria->sort === null) { + $search = $event->search; + $query = $search->getQuery(); + + if (! is_array($query->orders)) { + $query->orders = []; + } + + foreach ($search->getActiveGambits() as $gambit) { + if ($gambit instanceof TagGambit) { + array_unshift($query->orders, ['column' => 'is_sticky', 'direction' => 'desc']); + return; + } + } + + $query->leftJoin('users_discussions', function ($join) use ($search) { + $join->on('users_discussions.discussion_id', '=', 'discussions.id') + ->where('discussions.is_sticky', '=', true) + ->where('users_discussions.user_id', '=', $search->getActor()->id); + }); + + // TODO: Might be quicker to do a subquery in the order clause than a join? + $grammar = $query->getGrammar(); + $readNumber = $grammar->wrap('users_discussions.read_number'); + $lastPostNumber = $grammar->wrap('discussions.last_post_number'); + + array_unshift($query->orders, [ + 'type' => 'raw', + 'sql' => "(is_sticky AND ($readNumber IS NULL OR $lastPostNumber > $readNumber)) desc" + ]); + } + } +} diff --git a/extensions/sticky/src/Listeners/PersistData.php b/extensions/sticky/src/Listener/SaveStickyToDatabase.php similarity index 65% rename from extensions/sticky/src/Listeners/PersistData.php rename to extensions/sticky/src/Listener/SaveStickyToDatabase.php index 13b9a3879..3209a39db 100755 --- a/extensions/sticky/src/Listeners/PersistData.php +++ b/extensions/sticky/src/Listener/SaveStickyToDatabase.php @@ -8,19 +8,29 @@ * file that was distributed with this source code. */ -namespace Flarum\Sticky\Listeners; +namespace Flarum\Sticky\Listener; -use Flarum\Sticky\Events\DiscussionWasStickied; -use Flarum\Sticky\Events\DiscussionWasUnstickied; -use Flarum\Events\DiscussionWillBeSaved; +use Flarum\Core\Access\AssertPermissionTrait; +use Flarum\Sticky\Event\DiscussionWasStickied; +use Flarum\Sticky\Event\DiscussionWasUnstickied; +use Flarum\Event\DiscussionWillBeSaved; +use Illuminate\Contracts\Events\Dispatcher; -class PersistData +class SaveStickyToDatabase { - public function subscribe($events) + use AssertPermissionTrait; + + /** + * @param Dispatcher $events + */ + public function subscribe(Dispatcher $events) { $events->listen(DiscussionWillBeSaved::class, [$this, 'whenDiscussionWillBeSaved']); } + /** + * @param DiscussionWillBeSaved $event + */ public function whenDiscussionWillBeSaved(DiscussionWillBeSaved $event) { if (isset($event->data['attributes']['isSticky'])) { @@ -28,7 +38,7 @@ class PersistData $discussion = $event->discussion; $actor = $event->actor; - $discussion->assertCan($actor, 'sticky'); + $this->assertCan($actor, 'sticky', $discussion); if ((bool) $discussion->is_sticky === $isSticky) { return; diff --git a/extensions/sticky/src/Listeners/AddApiAttributes.php b/extensions/sticky/src/Listeners/AddApiAttributes.php deleted file mode 100755 index d230e623a..000000000 --- a/extensions/sticky/src/Listeners/AddApiAttributes.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky\Listeners; - -use Flarum\Events\ApiAttributes; -use Flarum\Events\BuildApiAction; -use Illuminate\Contracts\Events\Dispatcher; -use Flarum\Api\Serializers\DiscussionSerializer; -use Flarum\Api\Actions\Discussions\IndexAction as DiscussionsIndexAction; - -class AddApiAttributes -{ - public function subscribe(Dispatcher $events) - { - $events->listen(ApiAttributes::class, [$this, 'addAttributes']); - $events->listen(BuildApiAction::class, [$this, 'includeStartPost']); - } - - public function addAttributes(ApiAttributes $event) - { - if ($event->serializer instanceof DiscussionSerializer) { - $event->attributes['isSticky'] = (bool) $event->model->is_sticky; - $event->attributes['canSticky'] = (bool) $event->model->can($event->actor, 'sticky'); - } - } - - public function includeStartPost(BuildApiAction $event) - { - if ($event->action instanceof DiscussionsIndexAction) { - $event->addInclude('startPost'); - } - } -} diff --git a/extensions/sticky/src/Listeners/AddClientAssets.php b/extensions/sticky/src/Listeners/AddClientAssets.php deleted file mode 100755 index a92fa6366..000000000 --- a/extensions/sticky/src/Listeners/AddClientAssets.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky\Listeners; - -use Flarum\Events\RegisterLocales; -use Flarum\Events\BuildClientView; -use Illuminate\Contracts\Events\Dispatcher; - -class AddClientAssets -{ - public function subscribe(Dispatcher $events) - { - $events->listen(RegisterLocales::class, [$this, 'addLocale']); - $events->listen(BuildClientView::class, [$this, 'addAssets']); - } - - public function addLocale(RegisterLocales $event) - { - $event->addTranslations('en', __DIR__.'/../../locale/en.yml'); - } - - public function addAssets(BuildClientView $event) - { - $event->forumAssets([ - __DIR__.'/../../js/forum/dist/extension.js', - __DIR__.'/../../less/forum/extension.less' - ]); - - $event->forumBootstrapper('sticky/main'); - - $event->forumTranslations([ - 'sticky.discussion_stickied_notification', - 'sticky.discussion_stickied_post', - 'sticky.discussion_unstickied_post', - 'sticky.notify_discussion_stickied', - 'sticky.stickied', - 'sticky.sticky', - 'sticky.unsticky' - ]); - - $event->adminAssets([ - __DIR__.'/../../js/admin/dist/extension.js' - ]); - - $event->adminBootstrapper('sticky/main'); - } -} diff --git a/extensions/sticky/src/Listeners/NotifyDiscussionStickied.php b/extensions/sticky/src/Listeners/NotifyDiscussionStickied.php deleted file mode 100755 index 0bcccfc44..000000000 --- a/extensions/sticky/src/Listeners/NotifyDiscussionStickied.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky\Listeners; - -use Flarum\Events\RegisterPostTypes; -use Flarum\Events\RegisterNotificationTypes; -use Flarum\Sticky\Posts\DiscussionStickiedPost; -use Flarum\Sticky\Notifications\DiscussionStickiedBlueprint; -use Flarum\Sticky\Events\DiscussionWasStickied; -use Flarum\Sticky\Events\DiscussionWasUnstickied; -use Flarum\Core\Notifications\NotificationSyncer; -use Flarum\Core\Discussions\Discussion; -use Flarum\Core\Users\User; -use Illuminate\Contracts\Events\Dispatcher; - -class NotifyDiscussionStickied -{ - protected $notifications; - - public function __construct(NotificationSyncer $notifications) - { - $this->notifications = $notifications; - } - - public function subscribe(Dispatcher $events) - { - $events->listen(RegisterPostTypes::class, [$this, 'registerPostType']); - $events->listen(RegisterNotificationTypes::class, [$this, 'registerNotificationType']); - $events->listen(DiscussionWasStickied::class, [$this, 'whenDiscussionWasStickied']); - $events->listen(DiscussionWasUnstickied::class, [$this, 'whenDiscussionWasUnstickied']); - } - - public function registerPostType(RegisterPostTypes $event) - { - $event->register('Flarum\Sticky\Posts\DiscussionStickiedPost'); - } - - public function registerNotificationType(RegisterNotificationTypes $event) - { - $event->register( - 'Flarum\Sticky\Notifications\DiscussionStickiedBlueprint', - 'Flarum\Api\Serializers\DiscussionBasicSerializer', - ['alert'] - ); - } - - public function whenDiscussionWasStickied(DiscussionWasStickied $event) - { - $this->stickyChanged($event->discussion, $event->user, true); - } - - public function whenDiscussionWasUnstickied(DiscussionWasUnstickied $event) - { - $this->stickyChanged($event->discussion, $event->user, false); - } - - protected function stickyChanged(Discussion $discussion, User $user, $isSticky) - { - $post = DiscussionStickiedPost::reply( - $discussion->id, - $user->id, - $isSticky - ); - - $post = $discussion->mergePost($post); - - if ($discussion->start_user_id !== $user->id) { - $notification = new DiscussionStickiedBlueprint($post); - - $this->notifications->sync($notification, $post->exists ? [$discussion->startUser] : []); - } - } -} diff --git a/extensions/sticky/src/Listeners/PinStickiedDiscussionsToTop.php b/extensions/sticky/src/Listeners/PinStickiedDiscussionsToTop.php deleted file mode 100755 index 8fd1dd913..000000000 --- a/extensions/sticky/src/Listeners/PinStickiedDiscussionsToTop.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky\Listeners; - -use Flarum\Events\RegisterDiscussionGambits; -use Flarum\Events\DiscussionSearchWillBePerformed; -use Flarum\Tags\Gambits\TagGambit; -use Illuminate\Contracts\Events\Dispatcher; - -class PinStickiedDiscussionsToTop -{ - public function subscribe(Dispatcher $events) - { - $events->listen(RegisterDiscussionGambits::class, [$this, 'registerStickyGambit']); - $events->listen(DiscussionSearchWillBePerformed::class, [$this, 'reorderSearch']); - } - - public function registerStickyGambit(RegisterDiscussionGambits $event) - { - $event->gambits->add('Flarum\Sticky\Gambits\StickyGambit'); - } - - public function reorderSearch(DiscussionSearchWillBePerformed $event) - { - if ($event->criteria->sort === null) { - $query = $event->search->getQuery(); - - if (! is_array($query->orders)) { - $query->orders = []; - } - - foreach ($event->search->getActiveGambits() as $gambit) { - if ($gambit instanceof TagGambit) { - array_unshift($query->orders, ['column' => 'is_sticky', 'direction' => 'desc']); - return; - } - } - - $query->leftJoin('users_discussions', function ($join) use ($event) { - $join->on('users_discussions.discussion_id', '=', 'discussions.id') - ->where('discussions.is_sticky', '=', true) - ->where('users_discussions.user_id', '=', $event->search->getActor()->id); - }); - - // might be quicker to do a subquery in the order clause than a join? - $prefix = app('Illuminate\Database\ConnectionInterface')->getTablePrefix(); - array_unshift( - $query->orders, - [ - 'type' => 'raw', - 'sql' => "(is_sticky AND ({$prefix}users_discussions.read_number IS NULL OR {$prefix}discussions.last_post_number > {$prefix}users_discussions.read_number)) desc" - ] - ); - } - } -} diff --git a/extensions/sticky/src/Notifications/DiscussionStickiedBlueprint.php b/extensions/sticky/src/Notifications/DiscussionStickiedBlueprint.php deleted file mode 100644 index c12299d66..000000000 --- a/extensions/sticky/src/Notifications/DiscussionStickiedBlueprint.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Sticky\Notifications; - -use Flarum\Sticky\Posts\DiscussionStickiedPost; -use Flarum\Core\Notifications\Blueprint; - -class DiscussionStickiedBlueprint implements Blueprint -{ - protected $post; - - public function __construct(DiscussionStickiedPost $post) - { - $this->post = $post; - } - - public function getSender() - { - return $this->post->user; - } - - public function getSubject() - { - return $this->post->discussion; - } - - public function getData() - { - return ['postNumber' => (int) $this->post->number]; - } - - public static function getType() - { - return 'discussionStickied'; - } - - public static function getSubjectModel() - { - return 'Flarum\Core\Discussions\Discussion'; - } -} diff --git a/extensions/sticky/src/Posts/DiscussionStickiedPost.php b/extensions/sticky/src/Post/DiscussionStickiedPost.php similarity index 86% rename from extensions/sticky/src/Posts/DiscussionStickiedPost.php rename to extensions/sticky/src/Post/DiscussionStickiedPost.php index df05739a1..2c9ff3c55 100755 --- a/extensions/sticky/src/Posts/DiscussionStickiedPost.php +++ b/extensions/sticky/src/Post/DiscussionStickiedPost.php @@ -8,16 +8,22 @@ * file that was distributed with this source code. */ -namespace Flarum\Sticky\Posts; +namespace Flarum\Sticky\Post; -use Flarum\Core\Posts\Post; -use Flarum\Core\Posts\EventPost; -use Flarum\Core\Posts\MergeablePost; +use Flarum\Core\Post; +use Flarum\Core\Post\AbstractEventPost; +use Flarum\Core\Post\MergeableInterface; -class DiscussionStickiedPost extends EventPost implements MergeablePost +class DiscussionStickiedPost extends AbstractEventPost implements MergeableInterface { + /** + * {@inheritdoc} + */ public static $type = 'discussionStickied'; + /** + * {@inheritdoc} + */ public function saveAfter(Post $previous) { // If the previous post is another 'discussion stickied' post, and it's