From 5f9d45c4aba44abf3e8252e6880fe1204d039e93 Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Sun, 11 Oct 2015 18:51:25 +1030 Subject: [PATCH] Update for composer branch --- extensions/flags/.gitignore | 2 + extensions/flags/bootstrap.php | 9 +- extensions/flags/composer.json | 28 +- extensions/flags/flarum.json | 25 - extensions/flags/js/.gitignore | 3 - extensions/flags/js/admin/Gulpfile.js | 2 +- extensions/flags/js/admin/dist/extension.js | 34 + extensions/flags/js/admin/src/main.js | 2 +- extensions/flags/js/forum/Gulpfile.js | 2 +- extensions/flags/js/forum/dist/extension.js | 646 ++++++++++++++++++ .../flags/js/forum/src/addFlagControl.js | 2 +- .../flags/js/forum/src/addFlagsDropdown.js | 2 +- .../flags/js/forum/src/addFlagsToPosts.js | 2 +- .../flags/js/forum/src/components/FlagList.js | 2 +- .../js/forum/src/components/FlagsDropdown.js | 6 +- .../js/forum/src/components/FlagsPage.js | 2 +- extensions/flags/js/forum/src/main.js | 12 +- extensions/flags/js/forum/src/models/Flag.js | 8 +- extensions/flags/less/admin/extension.less | 0 extensions/flags/locale/en.yml | 8 - ...000_add_flags_read_time_to_users_table.php | 6 +- .../2015_09_02_000000_create_flags_table.php | 6 +- extensions/flags/scripts/compile.sh | 27 + .../Api/Controller/CreateFlagController.php | 57 ++ .../DeleteFlagsController.php} | 18 +- .../Api/Controller/ListFlagsController.php | 52 ++ extensions/flags/src/Api/CreateAction.php | 58 -- extensions/flags/src/Api/IndexAction.php | 53 -- .../Api/{ => Serializer}/FlagSerializer.php | 24 +- .../src/{Commands => Command}/CreateFlag.php | 4 +- .../CreateFlagHandler.php | 25 +- .../src/{Commands => Command}/DeleteFlags.php | 5 +- .../flags/src/Command/DeleteFlagsHandler.php | 61 ++ .../flags/src/Commands/DeleteFlagsHandler.php | 45 -- .../{Events => Event}/FlagsWillBeDeleted.php | 6 +- extensions/flags/src/Extension.php | 25 - extensions/flags/src/Flag.php | 26 +- .../flags/src/Listener/AddClientAssets.php | 48 ++ extensions/flags/src/Listener/AddFlagsApi.php | 78 +++ .../src/Listener/AddPostFlagsRelationship.php | 137 ++++ .../flags/src/Listeners/AddApiAttributes.php | 129 ---- .../flags/src/Listeners/AddClientAssets.php | 60 -- .../src/Listeners/AddModelRelationship.php | 47 -- 43 files changed, 1277 insertions(+), 517 deletions(-) delete mode 100644 extensions/flags/flarum.json delete mode 100644 extensions/flags/js/.gitignore create mode 100644 extensions/flags/js/admin/dist/extension.js create mode 100644 extensions/flags/js/forum/dist/extension.js delete mode 100644 extensions/flags/less/admin/extension.less delete mode 100644 extensions/flags/locale/en.yml create mode 100755 extensions/flags/scripts/compile.sh create mode 100644 extensions/flags/src/Api/Controller/CreateFlagController.php rename extensions/flags/src/Api/{DeleteAction.php => Controller/DeleteFlagsController.php} (54%) create mode 100644 extensions/flags/src/Api/Controller/ListFlagsController.php delete mode 100644 extensions/flags/src/Api/CreateAction.php delete mode 100644 extensions/flags/src/Api/IndexAction.php rename extensions/flags/src/Api/{ => Serializer}/FlagSerializer.php (51%) rename extensions/flags/src/{Commands => Command}/CreateFlag.php (92%) rename extensions/flags/src/{Commands => Command}/CreateFlagHandler.php (70%) rename extensions/flags/src/{Commands => Command}/DeleteFlags.php (90%) create mode 100644 extensions/flags/src/Command/DeleteFlagsHandler.php delete mode 100644 extensions/flags/src/Commands/DeleteFlagsHandler.php rename extensions/flags/src/{Events => Event}/FlagsWillBeDeleted.php (88%) delete mode 100644 extensions/flags/src/Extension.php create mode 100644 extensions/flags/src/Listener/AddClientAssets.php create mode 100755 extensions/flags/src/Listener/AddFlagsApi.php create mode 100755 extensions/flags/src/Listener/AddPostFlagsRelationship.php delete mode 100755 extensions/flags/src/Listeners/AddApiAttributes.php delete mode 100644 extensions/flags/src/Listeners/AddClientAssets.php delete mode 100755 extensions/flags/src/Listeners/AddModelRelationship.php 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(); - } -}