diff --git a/extensions/flags/.gitignore b/extensions/flags/.gitignore
index a4f3b125e..43eeee7fe 100644
--- a/extensions/flags/.gitignore
+++ b/extensions/flags/.gitignore
@@ -2,3 +2,5 @@
composer.phar
.DS_Store
Thumbs.db
+bower_components
+node_modules
\ No newline at end of file
diff --git a/extensions/flags/bootstrap.php b/extensions/flags/bootstrap.php
index 94022d5ec..dca06e83e 100644
--- a/extensions/flags/bootstrap.php
+++ b/extensions/flags/bootstrap.php
@@ -9,6 +9,11 @@
* file that was distributed with this source code.
*/
-require __DIR__.'/vendor/autoload.php';
+use Flarum\Flags\Listener;
+use Illuminate\Contracts\Events\Dispatcher;
-return 'Flarum\Flags\Extension';
+return function (Dispatcher $events) {
+ $events->subscribe(Listener\AddClientAssets::class);
+ $events->subscribe(Listener\AddFlagsApi::class);
+ $events->subscribe(Listener\AddPostFlagsRelationship::class);
+};
diff --git a/extensions/flags/composer.json b/extensions/flags/composer.json
index e0f25d883..db6a9ae41 100644
--- a/extensions/flags/composer.json
+++ b/extensions/flags/composer.json
@@ -1,10 +1,34 @@
{
+ "name": "flarum/flags",
+ "description": "Allow users to flag posts for moderator review.",
+ "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/flags"
+ },
+ "require": {
+ "flarum/core": "^0.1.0-beta.3"
+ },
"autoload": {
"psr-4": {
"Flarum\\Flags\\": "src/"
}
},
- "scripts": {
- "style": "phpcs --standard=PSR2 -np src"
+ "extra": {
+ "flarum-extension": {
+ "title": "Flags",
+ "icon": {
+ "name": "flag",
+ "backgroundColor": "#e92693",
+ "color": "#fff"
+ }
+ }
}
}
diff --git a/extensions/flags/flarum.json b/extensions/flags/flarum.json
deleted file mode 100644
index 2b789d6bb..000000000
--- a/extensions/flags/flarum.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "flags",
- "title": "Flags",
- "description": "Allow users to flag posts for moderator review.",
- "keywords": [],
- "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/flags",
- "issues": "https://github.com/flarum/core/issues"
- },
- "icon": {
- "name": "flag",
- "backgroundColor": "#e92693",
- "color": "#fff"
- }
-}
diff --git a/extensions/flags/js/.gitignore b/extensions/flags/js/.gitignore
deleted file mode 100644
index 372e20a51..000000000
--- a/extensions/flags/js/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-bower_components
-node_modules
-dist
diff --git a/extensions/flags/js/admin/Gulpfile.js b/extensions/flags/js/admin/Gulpfile.js
index bde8f8aef..af6b1bff2 100644
--- a/extensions/flags/js/admin/Gulpfile.js
+++ b/extensions/flags/js/admin/Gulpfile.js
@@ -2,6 +2,6 @@ var gulp = require('flarum-gulp');
gulp({
modules: {
- 'flags': 'src/**/*.js'
+ 'flarum/flags': 'src/**/*.js'
}
});
diff --git a/extensions/flags/js/admin/dist/extension.js b/extensions/flags/js/admin/dist/extension.js
new file mode 100644
index 000000000..92af984f1
--- /dev/null
+++ b/extensions/flags/js/admin/dist/extension.js
@@ -0,0 +1,34 @@
+System.register('flarum/flags/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('flarum-flags', function () {
+ extend(PermissionGrid.prototype, 'moderateItems', function (items) {
+ items.add('viewFlags', {
+ icon: 'flag',
+ label: 'View flagged posts',
+ permission: 'discussion.viewFlags'
+ }, 65);
+ });
+
+ extend(PermissionGrid.prototype, 'replyItems', function (items) {
+ items.add('flagPosts', {
+ icon: 'flag',
+ label: 'Flag posts',
+ permission: 'discussion.flagPosts'
+ }, 70);
+ });
+ });
+ }
+ };
+});
\ No newline at end of file
diff --git a/extensions/flags/js/admin/src/main.js b/extensions/flags/js/admin/src/main.js
index ab8dc655e..85c43d47e 100644
--- a/extensions/flags/js/admin/src/main.js
+++ b/extensions/flags/js/admin/src/main.js
@@ -2,7 +2,7 @@ import { extend } from 'flarum/extend';
import app from 'flarum/app';
import PermissionGrid from 'flarum/components/PermissionGrid';
-app.initializers.add('flags', () => {
+app.initializers.add('flarum-flags', () => {
extend(PermissionGrid.prototype, 'moderateItems', items => {
items.add('viewFlags', {
icon: 'flag',
diff --git a/extensions/flags/js/forum/Gulpfile.js b/extensions/flags/js/forum/Gulpfile.js
index bde8f8aef..af6b1bff2 100644
--- a/extensions/flags/js/forum/Gulpfile.js
+++ b/extensions/flags/js/forum/Gulpfile.js
@@ -2,6 +2,6 @@ var gulp = require('flarum-gulp');
gulp({
modules: {
- 'flags': 'src/**/*.js'
+ 'flarum/flags': 'src/**/*.js'
}
});
diff --git a/extensions/flags/js/forum/dist/extension.js b/extensions/flags/js/forum/dist/extension.js
new file mode 100644
index 000000000..05e8eda08
--- /dev/null
+++ b/extensions/flags/js/forum/dist/extension.js
@@ -0,0 +1,646 @@
+System.register('flarum/flags/addFlagControl', ['flarum/extend', 'flarum/app', 'flarum/utils/PostControls', 'flarum/components/Button', 'flarum/flags/components/FlagPostModal'], function (_export) {
+ 'use strict';
+
+ var extend, app, PostControls, Button, FlagPostModal;
+ return {
+ setters: [function (_flarumExtend) {
+ extend = _flarumExtend.extend;
+ }, function (_flarumApp) {
+ app = _flarumApp['default'];
+ }, function (_flarumUtilsPostControls) {
+ PostControls = _flarumUtilsPostControls['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumFlagsComponentsFlagPostModal) {
+ FlagPostModal = _flarumFlagsComponentsFlagPostModal['default'];
+ }],
+ execute: function () {
+ _export('default', function () {
+ extend(PostControls, 'userControls', function (items, post) {
+ if (post.isHidden() || post.contentType() !== 'comment' || !post.canFlag() || post.user() === app.session.user) return;
+
+ items.add('flag', m(
+ Button,
+ { icon: 'flag', onclick: function () {
+ return app.modal.show(new FlagPostModal({ post: post }));
+ } },
+ 'Flag'
+ ));
+ });
+ });
+ }
+ };
+});;System.register('flarum/flags/addFlagsDropdown', ['flarum/extend', 'flarum/app', 'flarum/components/HeaderSecondary', 'flarum/flags/components/FlagsDropdown'], function (_export) {
+ 'use strict';
+
+ var extend, app, HeaderSecondary, FlagsDropdown;
+ return {
+ setters: [function (_flarumExtend) {
+ extend = _flarumExtend.extend;
+ }, function (_flarumApp) {
+ app = _flarumApp['default'];
+ }, function (_flarumComponentsHeaderSecondary) {
+ HeaderSecondary = _flarumComponentsHeaderSecondary['default'];
+ }, function (_flarumFlagsComponentsFlagsDropdown) {
+ FlagsDropdown = _flarumFlagsComponentsFlagsDropdown['default'];
+ }],
+ execute: function () {
+ _export('default', function () {
+ extend(HeaderSecondary.prototype, 'items', function (items) {
+ if (app.forum.attribute('canViewFlags')) {
+ items.add('flags', m(FlagsDropdown, null), 15);
+ }
+ });
+ });
+ }
+ };
+});;System.register('flarum/flags/addFlagsToPosts', ['flarum/extend', 'flarum/app', 'flarum/components/CommentPost', 'flarum/components/Button', 'flarum/helpers/punctuate', 'flarum/helpers/username', 'flarum/utils/ItemList', 'flarum/utils/PostControls'], function (_export) {
+ 'use strict';
+
+ var extend, app, CommentPost, Button, punctuate, username, ItemList, PostControls;
+ return {
+ setters: [function (_flarumExtend) {
+ extend = _flarumExtend.extend;
+ }, function (_flarumApp) {
+ app = _flarumApp['default'];
+ }, function (_flarumComponentsCommentPost) {
+ CommentPost = _flarumComponentsCommentPost['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumHelpersPunctuate) {
+ punctuate = _flarumHelpersPunctuate['default'];
+ }, function (_flarumHelpersUsername) {
+ username = _flarumHelpersUsername['default'];
+ }, function (_flarumUtilsItemList) {
+ ItemList = _flarumUtilsItemList['default'];
+ }, function (_flarumUtilsPostControls) {
+ PostControls = _flarumUtilsPostControls['default'];
+ }],
+ execute: function () {
+ _export('default', function () {
+ extend(CommentPost.prototype, 'attrs', function (attrs) {
+ if (this.props.post.flags().length) {
+ attrs.className += ' Post--flagged';
+ }
+ });
+
+ CommentPost.prototype.dismissFlag = function (data) {
+ var post = this.props.post;
+
+ delete post.data.relationships.flags;
+
+ this.subtree.invalidate();
+
+ if (app.cache.flags) {
+ app.cache.flags.some(function (flag, i) {
+ if (flag.post() === post) {
+ app.cache.flags.splice(i, 1);
+
+ if (app.cache.flagIndex === post) {
+ var next = app.cache.flags[i];
+
+ if (!next) next = app.cache.flags[0];
+
+ if (next) {
+ var nextPost = next.post();
+ app.cache.flagIndex = nextPost;
+ m.route(app.route.post(nextPost));
+ }
+ }
+
+ return true;
+ }
+ });
+ }
+
+ return app.request({
+ url: app.forum.attribute('apiUrl') + post.apiEndpoint() + '/flags',
+ method: 'DELETE',
+ data: data
+ });
+ };
+
+ CommentPost.prototype.flagActionItems = function () {
+ var _this = this;
+
+ var items = new ItemList();
+
+ var controls = PostControls.destructiveControls(this.props.post);
+
+ Object.keys(controls).forEach(function (k) {
+ var props = controls[k].content.props;
+
+ props.className = 'Button';
+
+ extend(props, 'onclick', function () {
+ return _this.dismissFlag();
+ });
+ });
+
+ items.merge(controls);
+
+ items.add('dismiss', m(Button, { className: 'Button Button--icon Button--link', icon: 'times', onclick: this.dismissFlag.bind(this), title: 'Dismiss Flag' }), -100);
+
+ return items;
+ };
+
+ extend(CommentPost.prototype, 'content', function (vdom) {
+ var _this2 = this;
+
+ var post = this.props.post;
+ var flags = post.flags();
+
+ if (!flags.length) return;
+
+ if (post.isHidden()) this.revealContent = true;
+
+ vdom.unshift(m(
+ 'div',
+ { className: 'Post-flagged' },
+ m(
+ 'div',
+ { className: 'Post-flagged-flags' },
+ flags.map(function (flag) {
+ return m(
+ 'div',
+ { className: 'Post-flagged-flag' },
+ _this2.flagReason(flag)
+ );
+ })
+ ),
+ m(
+ 'div',
+ { className: 'Post-flagged-actions' },
+ this.flagActionItems().toArray()
+ )
+ ));
+ });
+
+ CommentPost.prototype.flagReason = function (flag) {
+ if (flag.type() === 'user') {
+ var user = flag.user();
+ var reason = flag.reason();
+ var detail = flag.reasonDetail();
+
+ return [app.trans(reason ? 'flarum-flags.forum.flagged_by_with_reason' : 'flarum-flags.forum.flagged_by', { user: user, reason: reason }), detail ? m(
+ 'span',
+ { className: 'Post-flagged-detail' },
+ detail
+ ) : ''];
+ }
+ };
+ });
+ }
+ };
+});;System.register('flarum/flags/main', ['flarum/app', 'flarum/Model', 'flarum/flags/models/Flag', 'flarum/flags/components/FlagsPage', 'flarum/flags/addFlagControl', 'flarum/flags/addFlagsDropdown', 'flarum/flags/addFlagsToPosts'], function (_export) {
+ 'use strict';
+
+ var app, Model, Flag, FlagsPage, addFlagControl, addFlagsDropdown, addFlagsToPosts;
+ return {
+ setters: [function (_flarumApp) {
+ app = _flarumApp['default'];
+ }, function (_flarumModel) {
+ Model = _flarumModel['default'];
+ }, function (_flarumFlagsModelsFlag) {
+ Flag = _flarumFlagsModelsFlag['default'];
+ }, function (_flarumFlagsComponentsFlagsPage) {
+ FlagsPage = _flarumFlagsComponentsFlagsPage['default'];
+ }, function (_flarumFlagsAddFlagControl) {
+ addFlagControl = _flarumFlagsAddFlagControl['default'];
+ }, function (_flarumFlagsAddFlagsDropdown) {
+ addFlagsDropdown = _flarumFlagsAddFlagsDropdown['default'];
+ }, function (_flarumFlagsAddFlagsToPosts) {
+ addFlagsToPosts = _flarumFlagsAddFlagsToPosts['default'];
+ }],
+ execute: function () {
+
+ app.initializers.add('flarum-flags', function () {
+ app.store.models.posts.prototype.flags = Model.hasMany('flags');
+ app.store.models.posts.prototype.canFlag = Model.attribute('canFlag');
+
+ app.store.models.flags = Flag;
+
+ app.routes.flags = { path: '/flags', component: m(FlagsPage, null) };
+
+ addFlagControl();
+ addFlagsDropdown();
+ addFlagsToPosts();
+ });
+ }
+ };
+});;System.register('flarum/flags/components/FlagList', ['flarum/Component', 'flarum/components/LoadingIndicator', 'flarum/helpers/avatar', 'flarum/helpers/username', 'flarum/helpers/icon', 'flarum/helpers/humanTime'], function (_export) {
+ 'use strict';
+
+ var Component, LoadingIndicator, avatar, username, icon, humanTime, FlagList;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsLoadingIndicator) {
+ LoadingIndicator = _flarumComponentsLoadingIndicator['default'];
+ }, function (_flarumHelpersAvatar) {
+ avatar = _flarumHelpersAvatar['default'];
+ }, function (_flarumHelpersUsername) {
+ username = _flarumHelpersUsername['default'];
+ }, function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }, function (_flarumHelpersHumanTime) {
+ humanTime = _flarumHelpersHumanTime['default'];
+ }],
+ execute: function () {
+ FlagList = (function (_Component) {
+ babelHelpers.inherits(FlagList, _Component);
+
+ function FlagList() {
+ babelHelpers.classCallCheck(this, FlagList);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ babelHelpers.get(Object.getPrototypeOf(FlagList.prototype), 'constructor', this).apply(this, args);
+
+ /**
+ * Whether or not the notifications are loading.
+ *
+ * @type {Boolean}
+ */
+ this.loading = false;
+ }
+
+ babelHelpers.createClass(FlagList, [{
+ key: 'view',
+ value: function view() {
+ var flags = app.cache.flags || [];
+
+ return m(
+ 'div',
+ { className: 'NotificationList FlagList' },
+ m(
+ 'div',
+ { className: 'NotificationList-header' },
+ m(
+ 'h4',
+ { className: 'App-titleControl App-titleControl--text' },
+ 'Flagged Posts'
+ )
+ ),
+ m(
+ 'div',
+ { className: 'NotificationList-content' },
+ m(
+ 'ul',
+ { className: 'NotificationGroup-content' },
+ flags.length ? flags.map(function (flag) {
+ var post = flag.post();
+
+ return m(
+ 'li',
+ null,
+ m(
+ 'a',
+ { href: app.route.post(post), className: 'Notification Flag', config: function (element, isInitialized) {
+ m.route.apply(this, arguments);
+
+ if (!isInitialized) $(element).on('click', function () {
+ return app.cache.flagIndex = post;
+ });
+ } },
+ avatar(post.user()),
+ icon('flag', { className: 'Notification-icon' }),
+ m(
+ 'span',
+ { className: 'Notification-content' },
+ username(post.user()),
+ ' in ',
+ m(
+ 'em',
+ null,
+ post.discussion().title()
+ )
+ ),
+ humanTime(flag.time()),
+ m(
+ 'div',
+ { className: 'Notification-excerpt' },
+ post.contentPlain()
+ )
+ )
+ );
+ }) : !this.loading ? m(
+ 'div',
+ { className: 'NotificationList-empty' },
+ app.trans('flarum-flags.forum.no_flags')
+ ) : LoadingIndicator.component({ className: 'LoadingIndicator--block' })
+ )
+ )
+ );
+ }
+
+ /**
+ * Load flags into the application's cache if they haven't already
+ * been loaded.
+ */
+ }, {
+ key: 'load',
+ value: function load() {
+ var _this = this;
+
+ if (app.cache.flags && !app.forum.attribute('unreadFlagsCount')) {
+ return;
+ }
+
+ this.loading = true;
+ m.redraw();
+
+ app.store.find('flags').then(function (flags) {
+ app.forum.pushAttributes({ unreadFlagsCount: 0 });
+ app.cache.flags = flags.sort(function (a, b) {
+ return b.time() - a.time();
+ });
+
+ _this.loading = false;
+ m.redraw();
+ });
+ }
+ }]);
+ return FlagList;
+ })(Component);
+
+ _export('default', FlagList);
+ }
+ };
+});;System.register('flarum/flags/components/FlagPostModal', ['flarum/components/Modal', 'flarum/components/Button'], function (_export) {
+ 'use strict';
+
+ var Modal, Button, FlagPostModal;
+ return {
+ setters: [function (_flarumComponentsModal) {
+ Modal = _flarumComponentsModal['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }],
+ execute: function () {
+ FlagPostModal = (function (_Modal) {
+ babelHelpers.inherits(FlagPostModal, _Modal);
+
+ function FlagPostModal() {
+ babelHelpers.classCallCheck(this, FlagPostModal);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ babelHelpers.get(Object.getPrototypeOf(FlagPostModal.prototype), 'constructor', this).apply(this, args);
+
+ this.reason = m.prop('');
+ this.reasonDetail = m.prop('');
+ }
+
+ babelHelpers.createClass(FlagPostModal, [{
+ key: 'className',
+ value: function className() {
+ return 'FlagPostModal Modal--small';
+ }
+ }, {
+ key: 'title',
+ value: function title() {
+ return 'Flag Post';
+ }
+ }, {
+ key: 'content',
+ value: function content() {
+ return m(
+ 'div',
+ { className: 'Modal-body' },
+ m(
+ 'div',
+ { className: 'Form' },
+ m(
+ 'div',
+ { className: 'Form-group' },
+ m(
+ 'label',
+ null,
+ 'Choose a Reason'
+ ),
+ m(
+ 'div',
+ null,
+ m(
+ 'label',
+ { className: 'checkbox' },
+ m('input', { type: 'radio', name: 'reason', checked: this.reason() === 'off_topic', value: 'off_topic', onclick: m.withAttr('value', this.reason) }),
+ 'Off-topic'
+ ),
+ m(
+ 'label',
+ { className: 'checkbox' },
+ m('input', { type: 'radio', name: 'reason', checked: this.reason() === 'inappropriate', value: 'inappropriate', onclick: m.withAttr('value', this.reason) }),
+ 'Inappropriate'
+ ),
+ m(
+ 'label',
+ { className: 'checkbox' },
+ m('input', { type: 'radio', name: 'reason', checked: this.reason() === 'spam', value: 'spam', onclick: m.withAttr('value', this.reason) }),
+ 'Spam'
+ ),
+ m(
+ 'label',
+ { className: 'checkbox' },
+ m('input', { type: 'radio', name: 'reason', checked: this.reason() === 'other', value: 'other', onclick: m.withAttr('value', this.reason) }),
+ 'Other',
+ this.reason() === 'other' ? m('textarea', { className: 'FormControl', value: this.reasonDetail(), oninput: m.withAttr('value', this.reasonDetail) }) : ''
+ )
+ )
+ ),
+ m(
+ 'div',
+ { className: 'Form-group' },
+ m(
+ Button,
+ {
+ className: 'Button Button--primary',
+ type: 'submit',
+ loading: this.loading,
+ disabled: !this.reason() },
+ 'Flag Post'
+ )
+ )
+ )
+ );
+ }
+ }, {
+ key: 'onsubmit',
+ value: function onsubmit(e) {
+ var _this = this;
+
+ e.preventDefault();
+
+ this.loading = true;
+
+ app.store.createRecord('flags').save({
+ reason: this.reason() === 'other' ? null : this.reason(),
+ reasonDetail: this.reasonDetail(),
+ relationships: {
+ user: app.session.user,
+ post: this.props.post
+ }
+ }).then(function () {
+ return _this.hide();
+ }, function () {
+ _this.loading = false;
+ m.redraw();
+ });
+ }
+ }]);
+ return FlagPostModal;
+ })(Modal);
+
+ _export('default', FlagPostModal);
+ }
+ };
+});;System.register('flarum/flags/components/FlagsDropdown', ['flarum/components/NotificationsDropdown', 'flarum/flags/components/FlagList'], function (_export) {
+ 'use strict';
+
+ var NotificationsDropdown, FlagList, FlagsDropdown;
+ return {
+ setters: [function (_flarumComponentsNotificationsDropdown) {
+ NotificationsDropdown = _flarumComponentsNotificationsDropdown['default'];
+ }, function (_flarumFlagsComponentsFlagList) {
+ FlagList = _flarumFlagsComponentsFlagList['default'];
+ }],
+ execute: function () {
+ FlagsDropdown = (function (_NotificationsDropdown) {
+ babelHelpers.inherits(FlagsDropdown, _NotificationsDropdown);
+ babelHelpers.createClass(FlagsDropdown, null, [{
+ key: 'initProps',
+ value: function initProps(props) {
+ props.label = props.label || 'Flagged Posts';
+ props.icon = props.icon || 'flag';
+
+ babelHelpers.get(Object.getPrototypeOf(FlagsDropdown), 'initProps', this).call(this, props);
+ }
+ }]);
+
+ function FlagsDropdown() {
+ babelHelpers.classCallCheck(this, FlagsDropdown);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ babelHelpers.get(Object.getPrototypeOf(FlagsDropdown.prototype), 'constructor', this).apply(this, args);
+
+ this.list = new FlagList();
+ }
+
+ babelHelpers.createClass(FlagsDropdown, [{
+ key: 'goToRoute',
+ value: function goToRoute() {
+ m.route(app.route('flags'));
+ }
+ }, {
+ key: 'getUnreadCount',
+ value: function getUnreadCount() {
+ return app.forum.attribute('unreadFlagsCount');
+ }
+ }, {
+ key: 'getNewCount',
+ value: function getNewCount() {
+ return app.forum.attribute('newFlagsCount');
+ }
+ }]);
+ return FlagsDropdown;
+ })(NotificationsDropdown);
+
+ _export('default', FlagsDropdown);
+ }
+ };
+});;System.register('flarum/flags/components/FlagsPage', ['flarum/components/Page', 'flarum/flags/components/FlagList'], function (_export) {
+
+ /**
+ * The `FlagsPage` component shows the flags list. It is only
+ * used on mobile devices where the flags dropdown is within the drawer.
+ */
+ 'use strict';
+
+ var Page, FlagList, FlagsPage;
+ return {
+ setters: [function (_flarumComponentsPage) {
+ Page = _flarumComponentsPage['default'];
+ }, function (_flarumFlagsComponentsFlagList) {
+ FlagList = _flarumFlagsComponentsFlagList['default'];
+ }],
+ execute: function () {
+ FlagsPage = (function (_Page) {
+ babelHelpers.inherits(FlagsPage, _Page);
+
+ function FlagsPage() {
+ babelHelpers.classCallCheck(this, FlagsPage);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ babelHelpers.get(Object.getPrototypeOf(FlagsPage.prototype), 'constructor', this).apply(this, args);
+
+ app.history.push('flags');
+
+ this.list = new FlagList();
+ this.list.load();
+
+ this.bodyClass = 'App--flags';
+ }
+
+ babelHelpers.createClass(FlagsPage, [{
+ key: 'view',
+ value: function view() {
+ return m(
+ 'div',
+ { className: 'FlagsPage' },
+ this.list.render()
+ );
+ }
+ }]);
+ return FlagsPage;
+ })(Page);
+
+ _export('default', FlagsPage);
+ }
+ };
+});;System.register('flarum/flags/models/Flag', ['flarum/Model', 'flarum/utils/mixin'], function (_export) {
+ 'use strict';
+
+ var Model, mixin, Flag;
+ return {
+ setters: [function (_flarumModel) {
+ Model = _flarumModel['default'];
+ }, function (_flarumUtilsMixin) {
+ mixin = _flarumUtilsMixin['default'];
+ }],
+ execute: function () {
+ Flag = (function (_Model) {
+ babelHelpers.inherits(Flag, _Model);
+
+ function Flag() {
+ babelHelpers.classCallCheck(this, Flag);
+ babelHelpers.get(Object.getPrototypeOf(Flag.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ return Flag;
+ })(Model);
+
+ babelHelpers._extends(Flag.prototype, {
+ type: Model.attribute('type'),
+ reason: Model.attribute('reason'),
+ reasonDetail: Model.attribute('reasonDetail'),
+ time: Model.attribute('time', Model.transformDate),
+
+ post: Model.hasOne('post'),
+ user: Model.hasOne('user')
+ });
+
+ _export('default', Flag);
+ }
+ };
+});
\ No newline at end of file
diff --git a/extensions/flags/js/forum/src/addFlagControl.js b/extensions/flags/js/forum/src/addFlagControl.js
index 98672af61..2e8640ce9 100644
--- a/extensions/flags/js/forum/src/addFlagControl.js
+++ b/extensions/flags/js/forum/src/addFlagControl.js
@@ -3,7 +3,7 @@ import app from 'flarum/app';
import PostControls from 'flarum/utils/PostControls';
import Button from 'flarum/components/Button';
-import FlagPostModal from 'flags/components/FlagPostModal';
+import FlagPostModal from 'flarum/flags/components/FlagPostModal';
export default function() {
extend(PostControls, 'userControls', function(items, post) {
diff --git a/extensions/flags/js/forum/src/addFlagsDropdown.js b/extensions/flags/js/forum/src/addFlagsDropdown.js
index af0520e7a..30912e413 100644
--- a/extensions/flags/js/forum/src/addFlagsDropdown.js
+++ b/extensions/flags/js/forum/src/addFlagsDropdown.js
@@ -1,7 +1,7 @@
import { extend } from 'flarum/extend';
import app from 'flarum/app';
import HeaderSecondary from 'flarum/components/HeaderSecondary';
-import FlagsDropdown from 'flags/components/FlagsDropdown';
+import FlagsDropdown from 'flarum/flags/components/FlagsDropdown';
export default function() {
extend(HeaderSecondary.prototype, 'items', function(items) {
diff --git a/extensions/flags/js/forum/src/addFlagsToPosts.js b/extensions/flags/js/forum/src/addFlagsToPosts.js
index 98f5f7b61..2c5290fe8 100644
--- a/extensions/flags/js/forum/src/addFlagsToPosts.js
+++ b/extensions/flags/js/forum/src/addFlagsToPosts.js
@@ -101,7 +101,7 @@ export default function() {
const detail = flag.reasonDetail();
return [
- app.trans(reason ? 'flags.flagged_by_with_reason' : 'flags.flagged_by', {user, reason}),
+ app.trans(reason ? 'flarum-flags.forum.flagged_by_with_reason' : 'flarum-flags.forum.flagged_by', {user, reason}),
detail ? {detail} : ''
];
}
diff --git a/extensions/flags/js/forum/src/components/FlagList.js b/extensions/flags/js/forum/src/components/FlagList.js
index 6ced95ef0..e2061e700 100644
--- a/extensions/flags/js/forum/src/components/FlagList.js
+++ b/extensions/flags/js/forum/src/components/FlagList.js
@@ -52,7 +52,7 @@ export default class FlagList extends Component {
);
})
: !this.loading
- ?
{app.trans('flags.no_flags')}
+ ? {app.trans('flarum-flags.forum.no_flags')}
: LoadingIndicator.component({className: 'LoadingIndicator--block'})}
diff --git a/extensions/flags/js/forum/src/components/FlagsDropdown.js b/extensions/flags/js/forum/src/components/FlagsDropdown.js
index 5f0ae934d..a597d4036 100644
--- a/extensions/flags/js/forum/src/components/FlagsDropdown.js
+++ b/extensions/flags/js/forum/src/components/FlagsDropdown.js
@@ -1,6 +1,6 @@
import NotificationsDropdown from 'flarum/components/NotificationsDropdown';
-import FlagList from 'flags/components/FlagList';
+import FlagList from 'flarum/flags/components/FlagList';
export default class FlagsDropdown extends NotificationsDropdown {
static initProps(props) {
@@ -23,4 +23,8 @@ export default class FlagsDropdown extends NotificationsDropdown {
getUnreadCount() {
return app.forum.attribute('unreadFlagsCount');
}
+
+ getNewCount() {
+ return app.forum.attribute('newFlagsCount');
+ }
}
diff --git a/extensions/flags/js/forum/src/components/FlagsPage.js b/extensions/flags/js/forum/src/components/FlagsPage.js
index a3ed2a747..908caf191 100644
--- a/extensions/flags/js/forum/src/components/FlagsPage.js
+++ b/extensions/flags/js/forum/src/components/FlagsPage.js
@@ -1,6 +1,6 @@
import Page from 'flarum/components/Page';
-import FlagList from 'flags/components/FlagList';
+import FlagList from 'flarum/flags/components/FlagList';
/**
* The `FlagsPage` component shows the flags list. It is only
diff --git a/extensions/flags/js/forum/src/main.js b/extensions/flags/js/forum/src/main.js
index d07832d2d..a990edae6 100644
--- a/extensions/flags/js/forum/src/main.js
+++ b/extensions/flags/js/forum/src/main.js
@@ -1,13 +1,13 @@
import app from 'flarum/app';
import Model from 'flarum/Model';
-import Flag from 'flags/models/Flag';
-import FlagsPage from 'flags/components/FlagsPage';
-import addFlagControl from 'flags/addFlagControl';
-import addFlagsDropdown from 'flags/addFlagsDropdown';
-import addFlagsToPosts from 'flags/addFlagsToPosts';
+import Flag from 'flarum/flags/models/Flag';
+import FlagsPage from 'flarum/flags/components/FlagsPage';
+import addFlagControl from 'flarum/flags/addFlagControl';
+import addFlagsDropdown from 'flarum/flags/addFlagsDropdown';
+import addFlagsToPosts from 'flarum/flags/addFlagsToPosts';
-app.initializers.add('flags', () => {
+app.initializers.add('flarum-flags', () => {
app.store.models.posts.prototype.flags = Model.hasMany('flags');
app.store.models.posts.prototype.canFlag = Model.attribute('canFlag');
diff --git a/extensions/flags/js/forum/src/models/Flag.js b/extensions/flags/js/forum/src/models/Flag.js
index 7a92014bc..32e9d4724 100644
--- a/extensions/flags/js/forum/src/models/Flag.js
+++ b/extensions/flags/js/forum/src/models/Flag.js
@@ -1,7 +1,9 @@
import Model from 'flarum/Model';
import mixin from 'flarum/utils/mixin';
-export default class Flag extends mixin(Model, {
+class Flag extends Model {}
+
+Object.assign(Flag.prototype, {
type: Model.attribute('type'),
reason: Model.attribute('reason'),
reasonDetail: Model.attribute('reasonDetail'),
@@ -9,4 +11,6 @@ export default class Flag extends mixin(Model, {
post: Model.hasOne('post'),
user: Model.hasOne('user')
-}) {}
+});
+
+export default Flag;
\ No newline at end of file
diff --git a/extensions/flags/less/admin/extension.less b/extensions/flags/less/admin/extension.less
deleted file mode 100644
index e69de29bb..000000000
diff --git a/extensions/flags/locale/en.yml b/extensions/flags/locale/en.yml
deleted file mode 100644
index 339682422..000000000
--- a/extensions/flags/locale/en.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-flags:
- reason_off_topic: Off-topic
- reason_spam: Spam
- reason_inappropriate: Inappropriate
- reason_other: Other
- flagged_by: "{username} flagged"
- flagged_by_with_reason: "{username} flagged as {reason}"
- no_flags: No Flags
diff --git a/extensions/flags/migrations/2015_09_02_000000_add_flags_read_time_to_users_table.php b/extensions/flags/migrations/2015_09_02_000000_add_flags_read_time_to_users_table.php
index a3161daeb..5f470ff4f 100644
--- a/extensions/flags/migrations/2015_09_02_000000_add_flags_read_time_to_users_table.php
+++ b/extensions/flags/migrations/2015_09_02_000000_add_flags_read_time_to_users_table.php
@@ -8,12 +8,12 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Migrations\Flags;
+namespace Flarum\Flags\Migration;
+use Flarum\Database\AbstractMigration;
use Illuminate\Database\Schema\Blueprint;
-use Flarum\Migrations\Migration;
-class AddFlagsReadTimeToUsersTable extends Migration
+class AddFlagsReadTimeToUsersTable extends AbstractMigration
{
public function up()
{
diff --git a/extensions/flags/migrations/2015_09_02_000000_create_flags_table.php b/extensions/flags/migrations/2015_09_02_000000_create_flags_table.php
index 7c23f9a20..caa81b043 100644
--- a/extensions/flags/migrations/2015_09_02_000000_create_flags_table.php
+++ b/extensions/flags/migrations/2015_09_02_000000_create_flags_table.php
@@ -8,12 +8,12 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Migrations\Flags;
+namespace Flarum\Flags\Migration;
+use Flarum\Database\AbstractMigration;
use Illuminate\Database\Schema\Blueprint;
-use Flarum\Migrations\Migration;
-class CreateFlagsTable extends Migration
+class CreateFlagsTable extends AbstractMigration
{
public function up()
{
diff --git a/extensions/flags/scripts/compile.sh b/extensions/flags/scripts/compile.sh
new file mode 100755
index 000000000..b0d8e8bd3
--- /dev/null
+++ b/extensions/flags/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/flags/src/Api/Controller/CreateFlagController.php b/extensions/flags/src/Api/Controller/CreateFlagController.php
new file mode 100644
index 000000000..f9799d971
--- /dev/null
+++ b/extensions/flags/src/Api/Controller/CreateFlagController.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Flarum\Flags\Api\Controller;
+
+use Flarum\Api\Controller\AbstractCreateController;
+use Flarum\Flags\Api\Serializer\FlagSerializer;
+use Flarum\Flags\Command\CreateFlag;
+use Illuminate\Contracts\Bus\Dispatcher;
+use Psr\Http\Message\ServerRequestInterface;
+use Tobscure\JsonApi\Document;
+
+class CreateFlagController extends AbstractCreateController
+{
+ /**
+ * {@inheritdoc}
+ */
+ public $serializer = FlagSerializer::class;
+
+ /**
+ * {@inheritdoc}
+ */
+ public $include = [
+ 'post',
+ 'post.flags'
+ ];
+
+ /**
+ * @var Dispatcher
+ */
+ protected $bus;
+
+ /**
+ * @param Dispatcher $bus
+ */
+ public function __construct(Dispatcher $bus)
+ {
+ $this->bus = $bus;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function data(ServerRequestInterface $request, Document $document)
+ {
+ return $this->bus->dispatch(
+ new CreateFlag($request->getAttribute('actor'), array_get($request->getParsedBody(), 'data', []))
+ );
+ }
+}
diff --git a/extensions/flags/src/Api/DeleteAction.php b/extensions/flags/src/Api/Controller/DeleteFlagsController.php
similarity index 54%
rename from extensions/flags/src/Api/DeleteAction.php
rename to extensions/flags/src/Api/Controller/DeleteFlagsController.php
index 7621da62b..6777768b8 100644
--- a/extensions/flags/src/Api/DeleteAction.php
+++ b/extensions/flags/src/Api/Controller/DeleteFlagsController.php
@@ -8,14 +8,14 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Flags\Api;
+namespace Flarum\Flags\Api\Controller;
-use Flarum\Flags\Commands\DeleteFlags;
-use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
-use Flarum\Api\Request;
+use Flarum\Api\Controller\AbstractDeleteController;
+use Flarum\Flags\Command\DeleteFlags;
use Illuminate\Contracts\Bus\Dispatcher;
+use Psr\Http\Message\ServerRequestInterface;
-class DeleteAction extends BaseDeleteAction
+class DeleteFlagsController extends AbstractDeleteController
{
/**
* @var Dispatcher
@@ -31,14 +31,12 @@ class DeleteAction extends BaseDeleteAction
}
/**
- * Delete flags for a post.
- *
- * @param Request $request
+ * {@inheritdoc}
*/
- protected function delete(Request $request)
+ protected function delete(ServerRequestInterface $request)
{
$this->bus->dispatch(
- new DeleteFlags($request->get('id'), $request->actor, $request->all())
+ new DeleteFlags(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'), $request->getParsedBody())
);
}
}
diff --git a/extensions/flags/src/Api/Controller/ListFlagsController.php b/extensions/flags/src/Api/Controller/ListFlagsController.php
new file mode 100644
index 000000000..62071fd1b
--- /dev/null
+++ b/extensions/flags/src/Api/Controller/ListFlagsController.php
@@ -0,0 +1,52 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Flarum\Flags\Api\Controller;
+
+use Flarum\Api\Controller\AbstractCollectionController;
+use Flarum\Flags\Api\Serializer\FlagSerializer;
+use Flarum\Flags\Flag;
+use Psr\Http\Message\ServerRequestInterface;
+use Tobscure\JsonApi\Document;
+
+class ListFlagsController extends AbstractCollectionController
+{
+ /**
+ * {@inheritdoc}
+ */
+ public $serializer = FlagSerializer::class;
+
+ /**
+ * {@inheritdoc}
+ */
+ public $include = [
+ 'user',
+ 'post',
+ 'post.user',
+ 'post.discussion'
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function data(ServerRequestInterface $request, Document $document)
+ {
+ $actor = $request->getAttribute('actor');
+
+ $actor->flags_read_time = time();
+ $actor->save();
+
+ return Flag::whereVisibleTo($actor)
+ ->with($this->extractInclude($request))
+ ->latest('flags.time')
+ ->groupBy('post_id')
+ ->get();
+ }
+}
diff --git a/extensions/flags/src/Api/CreateAction.php b/extensions/flags/src/Api/CreateAction.php
deleted file mode 100644
index 8eb3d61bf..000000000
--- a/extensions/flags/src/Api/CreateAction.php
+++ /dev/null
@@ -1,58 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags\Api;
-
-use Flarum\Flags\Commands\CreateFlag;
-use Flarum\Api\Actions\CreateAction as BaseCreateAction;
-use Flarum\Api\JsonApiRequest;
-use Illuminate\Contracts\Bus\Dispatcher;
-
-class CreateAction extends BaseCreateAction
-{
- /**
- * @var Dispatcher
- */
- protected $bus;
-
- /**
- * @inheritdoc
- */
- public $serializer = 'Flarum\Flags\Api\FlagSerializer';
-
- /**
- * @inheritdoc
- */
- public $include = [
- 'post' => true,
- 'post.flags' => true
- ];
-
- /**
- * @param Dispatcher $bus
- */
- public function __construct(Dispatcher $bus)
- {
- $this->bus = $bus;
- }
-
- /**
- * Create a flag according to input from the API request.
- *
- * @param JsonApiRequest $request
- * @return \Flarum\Flags\Flag
- */
- protected function create(JsonApiRequest $request)
- {
- return $this->bus->dispatch(
- new CreateFlag($request->actor, $request->get('data'))
- );
- }
-}
diff --git a/extensions/flags/src/Api/IndexAction.php b/extensions/flags/src/Api/IndexAction.php
deleted file mode 100644
index 12d7d6e85..000000000
--- a/extensions/flags/src/Api/IndexAction.php
+++ /dev/null
@@ -1,53 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags\Api;
-
-use Flarum\Api\Actions\SerializeCollectionAction;
-use Flarum\Api\JsonApiRequest;
-use Flarum\Flags\Flag;
-use Tobscure\JsonApi\Document;
-
-class IndexAction extends SerializeCollectionAction
-{
- /**
- * @inheritdoc
- */
- public $serializer = 'Flarum\Flags\Api\FlagSerializer';
-
- /**
- * @inheritdoc
- */
- public $include = [
- 'user' => true,
- 'post' => true,
- 'post.user' => true,
- 'post.discussion' => true
- ];
-
- /**
- * @inheritdoc
- */
- public $link = [];
-
- protected function data(JsonApiRequest $request, Document $document)
- {
- $actor = $request->actor;
-
- $actor->flags_read_time = time();
- $actor->save();
-
- return Flag::whereVisibleTo($actor)
- ->with($request->include)
- ->latest('flags.time')
- ->groupBy('post_id')
- ->get();
- }
-}
diff --git a/extensions/flags/src/Api/FlagSerializer.php b/extensions/flags/src/Api/Serializer/FlagSerializer.php
similarity index 51%
rename from extensions/flags/src/Api/FlagSerializer.php
rename to extensions/flags/src/Api/Serializer/FlagSerializer.php
index 7604197e9..2e9e68fae 100644
--- a/extensions/flags/src/Api/FlagSerializer.php
+++ b/extensions/flags/src/Api/Serializer/FlagSerializer.php
@@ -8,14 +8,22 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Flags\Api;
+namespace Flarum\Flags\Api\Serializer;
-use Flarum\Api\Serializers\Serializer;
+use Flarum\Api\Serializer\AbstractSerializer;
+use Flarum\Api\Serializer\PostSerializer;
+use Flarum\Api\Serializer\UserBasicSerializer;
-class FlagSerializer extends Serializer
+class FlagSerializer extends AbstractSerializer
{
+ /**
+ * {@inheritdoc}
+ */
protected $type = 'flags';
+ /**
+ * {@inheritdoc}
+ */
protected function getDefaultAttributes($flag)
{
return [
@@ -25,13 +33,19 @@ class FlagSerializer extends Serializer
];
}
+ /**
+ * @return \Flarum\Api\Relationship\HasOneBuilder
+ */
protected function post()
{
- return $this->hasOne('Flarum\Api\Serializers\PostSerializer');
+ return $this->hasOne(PostSerializer::class);
}
+ /**
+ * @return \Flarum\Api\Relationship\HasOneBuilder
+ */
protected function user()
{
- return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
+ return $this->hasOne(UserBasicSerializer::class);
}
}
diff --git a/extensions/flags/src/Commands/CreateFlag.php b/extensions/flags/src/Command/CreateFlag.php
similarity index 92%
rename from extensions/flags/src/Commands/CreateFlag.php
rename to extensions/flags/src/Command/CreateFlag.php
index 204010f82..728e72d68 100644
--- a/extensions/flags/src/Commands/CreateFlag.php
+++ b/extensions/flags/src/Command/CreateFlag.php
@@ -8,9 +8,9 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Flags\Commands;
+namespace Flarum\Flags\Command;
-use Flarum\Core\Users\User;
+use Flarum\Core\User;
class CreateFlag
{
diff --git a/extensions/flags/src/Commands/CreateFlagHandler.php b/extensions/flags/src/Command/CreateFlagHandler.php
similarity index 70%
rename from extensions/flags/src/Commands/CreateFlagHandler.php
rename to extensions/flags/src/Command/CreateFlagHandler.php
index 64e33be4f..aad7b2510 100644
--- a/extensions/flags/src/Commands/CreateFlagHandler.php
+++ b/extensions/flags/src/Command/CreateFlagHandler.php
@@ -8,17 +8,26 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Flags\Commands;
+namespace Flarum\Flags\Command;
+use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Flags\Flag;
-use Flarum\Core\Posts\PostRepository;
-use Flarum\Core\Posts\CommentPost;
-use Exception;
+use Flarum\Core\Repository\PostRepository;
+use Flarum\Core\Post\CommentPost;
+use Tobscure\JsonApi\Exception\InvalidParameterException;
class CreateFlagHandler
{
- private $posts;
+ use AssertPermissionTrait;
+ /**
+ * @var PostRepository
+ */
+ protected $posts;
+
+ /**
+ * @param PostRepository $posts
+ */
public function __construct(PostRepository $posts)
{
$this->posts = $posts;
@@ -27,6 +36,7 @@ class CreateFlagHandler
/**
* @param CreateFlag $command
* @return Flag
+ * @throws InvalidParameterException
*/
public function handle(CreateFlag $command)
{
@@ -37,11 +47,10 @@ class CreateFlagHandler
$post = $this->posts->findOrFail($postId, $actor);
if (! ($post instanceof CommentPost)) {
- // TODO: throw 400(?) error
- throw new Exception;
+ throw new InvalidParameterException;
}
- $post->assertCan($actor, 'flag');
+ $this->assertCan($actor, 'flag', $post);
Flag::unguard();
diff --git a/extensions/flags/src/Commands/DeleteFlags.php b/extensions/flags/src/Command/DeleteFlags.php
similarity index 90%
rename from extensions/flags/src/Commands/DeleteFlags.php
rename to extensions/flags/src/Command/DeleteFlags.php
index 2f70fb6aa..1fd1c44d2 100644
--- a/extensions/flags/src/Commands/DeleteFlags.php
+++ b/extensions/flags/src/Command/DeleteFlags.php
@@ -8,10 +8,9 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Flags\Commands;
+namespace Flarum\Flags\Command;
-use Flarum\Flags\Flag;
-use Flarum\Core\Users\User;
+use Flarum\Core\User;
class DeleteFlags
{
diff --git a/extensions/flags/src/Command/DeleteFlagsHandler.php b/extensions/flags/src/Command/DeleteFlagsHandler.php
new file mode 100644
index 000000000..b52cb6a43
--- /dev/null
+++ b/extensions/flags/src/Command/DeleteFlagsHandler.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Flarum\Flags\Command;
+
+use Flarum\Core\Access\AssertPermissionTrait;
+use Flarum\Core\Repository\PostRepository;
+use Flarum\Flags\Event\FlagsWillBeDeleted;
+use Flarum\Flags\Flag;
+use Illuminate\Contracts\Events\Dispatcher;
+
+class DeleteFlagsHandler
+{
+ use AssertPermissionTrait;
+
+ /**
+ * @var PostRepository
+ */
+ protected $posts;
+
+ /**
+ * @var Dispatcher
+ */
+ protected $events;
+
+ /**
+ * @param PostRepository $posts
+ * @param Dispatcher $events
+ */
+ public function __construct(PostRepository $posts, Dispatcher $events)
+ {
+ $this->posts = $posts;
+ $this->events = $events;
+ }
+
+ /**
+ * @param DeleteFlags $command
+ * @return Flag
+ */
+ public function handle(DeleteFlags $command)
+ {
+ $actor = $command->actor;
+
+ $post = $this->posts->findOrFail($command->postId, $actor);
+
+ $this->assertCan($actor, 'viewFlags', $post->discussion);
+
+ $this->events->fire(new FlagsWillBeDeleted($post, $actor, $command->data));
+
+ $post->flags()->delete();
+
+ return $post;
+ }
+}
diff --git a/extensions/flags/src/Commands/DeleteFlagsHandler.php b/extensions/flags/src/Commands/DeleteFlagsHandler.php
deleted file mode 100644
index 7b5478419..000000000
--- a/extensions/flags/src/Commands/DeleteFlagsHandler.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags\Commands;
-
-use Flarum\Flags\Flag;
-use Flarum\Core\Posts\PostRepository;
-use Flarum\Flags\Events\FlagsWillBeDeleted;
-
-class DeleteFlagsHandler
-{
- protected $posts;
-
- public function __construct(PostRepository $posts)
- {
- $this->posts = $posts;
- }
-
- /**
- * @param DeleteFlag $command
- * @return Flag
- * @throws \Flarum\Core\Exceptions\PermissionDeniedException
- */
- public function handle(DeleteFlags $command)
- {
- $actor = $command->actor;
-
- $post = $this->posts->findOrFail($command->postId, $actor);
-
- $post->discussion->assertCan($actor, 'viewFlags');
-
- event(new FlagsWillBeDeleted($post, $actor, $command->data));
-
- $post->flags()->delete();
-
- return $post;
- }
-}
diff --git a/extensions/flags/src/Events/FlagsWillBeDeleted.php b/extensions/flags/src/Event/FlagsWillBeDeleted.php
similarity index 88%
rename from extensions/flags/src/Events/FlagsWillBeDeleted.php
rename to extensions/flags/src/Event/FlagsWillBeDeleted.php
index b824c662a..a38884c8c 100644
--- a/extensions/flags/src/Events/FlagsWillBeDeleted.php
+++ b/extensions/flags/src/Event/FlagsWillBeDeleted.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Flarum\Flags\Events;
+namespace Flarum\Flags\Event;
-use Flarum\Core\Posts\Post;
-use Flarum\Core\Users\User;
+use Flarum\Core\Post;
+use Flarum\Core\User;
class FlagsWillBeDeleted
{
diff --git a/extensions/flags/src/Extension.php b/extensions/flags/src/Extension.php
deleted file mode 100644
index 31bac2cca..000000000
--- a/extensions/flags/src/Extension.php
+++ /dev/null
@@ -1,25 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags;
-
-use Flarum\Support\Extension as BaseExtension;
-use Illuminate\Events\Dispatcher;
-use Flarum\Core\Posts\Post;
-
-class Extension extends BaseExtension
-{
- public function listen(Dispatcher $events)
- {
- $events->subscribe('Flarum\Flags\Listeners\AddClientAssets');
- $events->subscribe('Flarum\Flags\Listeners\AddApiAttributes');
- $events->subscribe('Flarum\Flags\Listeners\AddModelRelationship');
- }
-}
diff --git a/extensions/flags/src/Flag.php b/extensions/flags/src/Flag.php
index 515ff75fc..5531bbebf 100644
--- a/extensions/flags/src/Flag.php
+++ b/extensions/flags/src/Flag.php
@@ -10,24 +10,38 @@
namespace Flarum\Flags;
-use Flarum\Core\Model;
-use Flarum\Core\Support\VisibleScope;
+use Flarum\Core\Post;
+use Flarum\Core\Support\ScopeVisibilityTrait;
+use Flarum\Core\User;
+use Flarum\Database\AbstractModel;
-class Flag extends Model
+class Flag extends AbstractModel
{
- use VisibleScope;
+ use ScopeVisibilityTrait;
+ /**
+ * {@inheritdoc}
+ */
protected $table = 'flags';
+ /**
+ * {@inheritdoc}
+ */
protected $dates = ['time'];
+ /**
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
public function post()
{
- return $this->belongsTo('Flarum\Core\Posts\Post');
+ return $this->belongsTo(Post::class);
}
+ /**
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
public function user()
{
- return $this->belongsTo('Flarum\Core\Users\User');
+ return $this->belongsTo(User::class);
}
}
diff --git a/extensions/flags/src/Listener/AddClientAssets.php b/extensions/flags/src/Listener/AddClientAssets.php
new file mode 100644
index 000000000..19d9b4a8e
--- /dev/null
+++ b/extensions/flags/src/Listener/AddClientAssets.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Flarum\Flags\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/flags/main');
+ $event->addTranslations('flarum-flags.forum');
+ }
+
+ if ($event->isAdmin()) {
+ $event->addAssets([
+ __DIR__.'/../../js/admin/dist/extension.js'
+ ]);
+ $event->addBootstrapper('flarum/flags/main');
+ $event->addTranslations('flarum-flags.admin');
+ }
+ }
+}
diff --git a/extensions/flags/src/Listener/AddFlagsApi.php b/extensions/flags/src/Listener/AddFlagsApi.php
new file mode 100755
index 000000000..bc8fee2be
--- /dev/null
+++ b/extensions/flags/src/Listener/AddFlagsApi.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Flarum\Flags\Listener;
+
+use Flarum\Api\Serializer\ForumSerializer;
+use Flarum\Api\Serializer\PostSerializer;
+use Flarum\Core\User;
+use Flarum\Event\ConfigureApiRoutes;
+use Flarum\Event\ConfigureModelDates;
+use Flarum\Event\PrepareApiAttributes;
+use Flarum\Flags\Api\Controller;
+use Flarum\Flags\Flag;
+use Illuminate\Contracts\Events\Dispatcher;
+
+class AddFlagsApi
+{
+ /**
+ * @param Dispatcher $events
+ */
+ public function subscribe(Dispatcher $events)
+ {
+ $events->listen(ConfigureModelDates::class, [$this, 'configureModelDates']);
+ $events->listen(PrepareApiAttributes::class, [$this, 'prepareApiAttributes']);
+ $events->listen(ConfigureApiRoutes::class, [$this, 'configureApiRoutes']);
+ }
+
+ /**
+ * @param ConfigureModelDates $event
+ */
+ public function configureModelDates(ConfigureModelDates $event)
+ {
+ if ($event->isModel(User::class)) {
+ $event->dates[] = 'flags_read_time';
+ }
+ }
+
+ /**
+ * @param PrepareApiAttributes $event
+ */
+ public function prepareApiAttributes(PrepareApiAttributes $event)
+ {
+ if ($event->isSerializer(ForumSerializer::class)) {
+ $event->attributes['canViewFlags'] = $event->actor->hasPermissionLike('discussion.viewFlags');
+
+ if ($event->attributes['canViewFlags']) {
+ $query = Flag::whereVisibleTo($event->actor);
+
+ if ($time = $event->actor->flags_read_time) {
+ $query->where('flags.time', '>', $time);
+ }
+
+ $event->attributes['unreadFlagsCount'] = $query->distinct('flags.post_id')->count();
+ }
+ }
+
+ if ($event->isSerializer(PostSerializer::class)) {
+ $event->attributes['canFlag'] = $event->actor->can('flag', $event->model);
+ }
+ }
+
+ /**
+ * @param ConfigureApiRoutes $event
+ */
+ public function configureApiRoutes(ConfigureApiRoutes $event)
+ {
+ $event->get('/flags', 'flags.index', Controller\ListFlagsController::class);
+ $event->post('/flags', 'flags.create', Controller\CreateFlagController::class);
+ $event->delete('/posts/{id}/flags', 'flags.delete', Controller\DeleteFlagsController::class);
+ }
+}
diff --git a/extensions/flags/src/Listener/AddPostFlagsRelationship.php b/extensions/flags/src/Listener/AddPostFlagsRelationship.php
new file mode 100755
index 000000000..f6f4821ee
--- /dev/null
+++ b/extensions/flags/src/Listener/AddPostFlagsRelationship.php
@@ -0,0 +1,137 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Flarum\Flags\Listener;
+
+use Flarum\Api\Controller;
+use Flarum\Api\Serializer\PostSerializer;
+use Flarum\Core\Post;
+use Flarum\Event\ConfigureApiController;
+use Flarum\Event\GetApiRelationship;
+use Flarum\Event\GetModelRelationship;
+use Flarum\Event\PostWasDeleted;
+use Flarum\Event\PrepareApiData;
+use Flarum\Flags\Api\Controller\CreateFlagController;
+use Flarum\Flags\Api\Serializer\FlagSerializer;
+use Flarum\Flags\Flag;
+use Illuminate\Contracts\Events\Dispatcher;
+use Illuminate\Database\Eloquent\Collection;
+
+class AddPostFlagsRelationship
+{
+ /**
+ * @param Dispatcher $events
+ */
+ public function subscribe(Dispatcher $events)
+ {
+ $events->listen(GetModelRelationship::class, [$this, 'getModelRelationship']);
+ $events->listen(PostWasDeleted::class, [$this, 'postWasDeleted']);
+ $events->listen(GetApiRelationship::class, [$this, 'getApiRelationship']);
+ $events->listen(ConfigureApiController::class, [$this, 'includeFlagsRelationship']);
+ $events->listen(PrepareApiData::class, [$this, 'prepareApiData']);
+ }
+
+ /**
+ * @param GetModelRelationship $event
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany|null
+ */
+ public function getModelRelationship(GetModelRelationship $event)
+ {
+ if ($event->isRelationship(Post::class, 'flags')) {
+ return $event->model->hasMany(Flag::class, 'post_id');
+ }
+ }
+
+ /**
+ * @param PostWasDeleted $event
+ */
+ public function postWasDeleted(PostWasDeleted $event)
+ {
+ $event->post->flags()->delete();
+ }
+
+ /**
+ * @param GetApiRelationship $event
+ * @return \Flarum\Api\Relationship\HasManyBuilder|null
+ */
+ public function getApiRelationship(GetApiRelationship $event)
+ {
+ if ($event->isRelationship(PostSerializer::class, 'flags')) {
+ return $event->serializer->hasMany(FlagSerializer::class, 'flags');
+ }
+ }
+
+ /**
+ * @param ConfigureApiController $event
+ */
+ public function includeFlagsRelationship(ConfigureApiController $event)
+ {
+ if ($event->isController(Controller\ShowDiscussionController::class)) {
+ $event->addInclude([
+ 'posts.flags',
+ 'posts.flags.user'
+ ]);
+ }
+
+ if ($event->isController(Controller\ListPostsController::class)
+ || $event->isController(Controller\ShowPostController::class)) {
+ $event->addInclude([
+ 'flags',
+ 'flags.user'
+ ]);
+ }
+ }
+
+ /**
+ * @param PrepareApiData $event
+ */
+ public function prepareApiData(PrepareApiData $event)
+ {
+ // For any API action that allows the 'flags' relationship to be
+ // included, we need to preload this relationship onto the data (Post
+ // models) so that we can selectively expose only the flags that the
+ // user has permission to view.
+ if ($event->isController(Controller\ShowDiscussionController::class)) {
+ $posts = $event->data->posts;
+ }
+
+ if ($event->isController(Controller\ListPostsController::class)) {
+ $posts = $event->data->all();
+ }
+
+ if ($event->isController(Controller\ShowPostController::class)) {
+ $posts = [$event->data];
+ }
+
+ if ($event->isController(CreateFlagController::class)) {
+ $posts = [$event->data->post];
+ }
+
+ if (isset($posts)) {
+ $actor = $event->request->getAttribute('actor');
+ $postsWithPermission = [];
+
+ foreach ($posts as $post) {
+ $post->setRelation('flags', null);
+
+ if ($actor->can('viewFlags', $post->discussion)) {
+ $postsWithPermission[] = $post;
+ }
+ }
+
+ if (count($postsWithPermission)) {
+ (new Collection($postsWithPermission))
+ ->load('flags', 'flags.user');
+ }
+ }
+ }
+
+
+}
diff --git a/extensions/flags/src/Listeners/AddApiAttributes.php b/extensions/flags/src/Listeners/AddApiAttributes.php
deleted file mode 100755
index f52053633..000000000
--- a/extensions/flags/src/Listeners/AddApiAttributes.php
+++ /dev/null
@@ -1,129 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags\Listeners;
-
-use Flarum\Events\ApiRelationship;
-use Flarum\Events\WillSerializeData;
-use Flarum\Events\BuildApiAction;
-use Flarum\Events\ApiAttributes;
-use Flarum\Events\RegisterApiRoutes;
-use Flarum\Api\Serializers\PostSerializer;
-use Flarum\Api\Serializers\ForumSerializer;
-use Flarum\Api\Actions\Posts;
-use Flarum\Api\Actions\Discussions;
-use Flarum\Flags\Flag;
-use Flarum\Flags\Api\CreateAction as FlagsCreateAction;
-use Illuminate\Database\Eloquent\Collection;
-
-class AddApiAttributes
-{
- public function subscribe($events)
- {
- $events->listen(ApiRelationship::class, [$this, 'addFlagsRelationship']);
- $events->listen(WillSerializeData::class, [$this, 'loadFlagsRelationship']);
- $events->listen(BuildApiAction::class, [$this, 'includeFlagsRelationship']);
- $events->listen(ApiAttributes::class, [$this, 'addAttributes']);
- $events->listen(RegisterApiRoutes::class, [$this, 'addRoutes']);
- }
-
- public function loadFlagsRelationship(WillSerializeData $event)
- {
- // For any API action that allows the 'flags' relationship to be
- // included, we need to preload this relationship onto the data (Post
- // models) so that we can selectively expose only the flags that the
- // user has permission to view.
- if ($event->action instanceof Discussions\ShowAction) {
- $discussion = $event->data;
- $posts = $discussion->posts->all();
- }
-
- if ($event->action instanceof Posts\IndexAction) {
- $posts = $event->data->all();
- }
-
- if ($event->action instanceof Posts\ShowAction) {
- $posts = [$event->data];
- }
-
- if ($event->action instanceof FlagsCreateAction) {
- $flag = $event->data;
- $posts = [$flag->post];
- }
-
- if (isset($posts)) {
- $actor = $event->request->actor;
- $postsWithPermission = [];
-
- foreach ($posts as $post) {
- $post->setRelation('flags', null);
-
- if ($post->discussion->can($actor, 'viewFlags')) {
- $postsWithPermission[] = $post;
- }
- }
-
- if (count($postsWithPermission)) {
- (new Collection($postsWithPermission))
- ->load('flags', 'flags.user');
- }
- }
- }
-
- public function addFlagsRelationship(ApiRelationship $event)
- {
- if ($event->serializer instanceof PostSerializer &&
- $event->relationship === 'flags') {
- return $event->serializer->hasMany('Flarum\Flags\Api\FlagSerializer', 'flags');
- }
- }
-
- public function includeFlagsRelationship(BuildApiAction $event)
- {
- if ($event->action instanceof Discussions\ShowAction) {
- $event->addInclude('posts.flags');
- $event->addInclude('posts.flags.user');
- }
-
- if ($event->action instanceof Posts\IndexAction ||
- $event->action instanceof Posts\ShowAction) {
- $event->addInclude('flags');
- $event->addInclude('flags.user');
- }
- }
-
- public function addAttributes(ApiAttributes $event)
- {
- if ($event->serializer instanceof ForumSerializer) {
- $event->attributes['canViewFlags'] = $event->actor->hasPermissionLike('discussion.viewFlags');
-
- if ($event->attributes['canViewFlags']) {
- $query = Flag::whereVisibleTo($event->actor);
-
- if ($time = $event->actor->flags_read_time) {
- $query->where('flags.time', '>', $time);
- }
-
- $event->attributes['unreadFlagsCount'] = $query->distinct('flags.post_id')->count();
- }
- }
-
- if ($event->serializer instanceof PostSerializer) {
- $event->attributes['canFlag'] = $event->model->can($event->actor, 'flag');
- }
- }
-
- public function addRoutes(RegisterApiRoutes $event)
- {
- $event->get('/flags', 'flags.index', 'Flarum\Flags\Api\IndexAction');
- $event->post('/flags', 'flags.create', 'Flarum\Flags\Api\CreateAction');
- $event->delete('/posts/{id}/flags', 'flags.delete', 'Flarum\Flags\Api\DeleteAction');
- }
-}
diff --git a/extensions/flags/src/Listeners/AddClientAssets.php b/extensions/flags/src/Listeners/AddClientAssets.php
deleted file mode 100644
index 48f0f8153..000000000
--- a/extensions/flags/src/Listeners/AddClientAssets.php
+++ /dev/null
@@ -1,60 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags\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('flags/main');
-
- $event->forumTranslations([
- 'flags.reason_off_topic',
- 'flags.reason_spam',
- 'flags.reason_inappropriate',
- 'flags.reason_other',
- 'flags.flagged_by',
- 'flags.flagged_by_with_reason',
- 'flags.no_flags'
- ]);
-
- $event->adminAssets([
- __DIR__.'/../../js/admin/dist/extension.js',
- __DIR__.'/../../less/admin/extension.less'
- ]);
-
- $event->adminBootstrapper('flags/main');
-
- $event->adminTranslations([
- // 'flag.hello_world'
- ]);
- }
-}
diff --git a/extensions/flags/src/Listeners/AddModelRelationship.php b/extensions/flags/src/Listeners/AddModelRelationship.php
deleted file mode 100755
index 72bc12472..000000000
--- a/extensions/flags/src/Listeners/AddModelRelationship.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Flarum\Flags\Listeners;
-
-use Flarum\Events\ModelRelationship;
-use Flarum\Events\ModelDates;
-use Flarum\Events\PostWasDeleted;
-use Flarum\Core\Posts\Post;
-use Flarum\Core\Users\User;
-use Flarum\Flags\Flag;
-
-class AddModelRelationship
-{
- public function subscribe($events)
- {
- $events->listen(ModelRelationship::class, [$this, 'addFlagsRelationship']);
- $events->listen(ModelDates::class, [$this, 'modelDates']);
- $events->listen(PostWasDeleted::class, [$this, 'deleteFlags']);
- }
-
- public function addFlagsRelationship(ModelRelationship $event)
- {
- if ($event->model instanceof Post && $event->relationship === 'flags') {
- return $event->model->hasMany('Flarum\Flags\Flag', 'post_id');
- }
- }
-
- public function modelDates(ModelDates $event)
- {
- if ($event->model instanceof User) {
- $event->dates[] = 'flags_read_time';
- }
- }
-
- public function deleteFlags(PostWasDeleted $event)
- {
- $event->post->flags()->delete();
- }
-}