mirror of
https://github.com/flarum/core.git
synced 2025-07-18 15:21:16 +02:00
Rename to Flags, tweak flag controls
- Display post "destructiveControls" in flag instead of custom buttons - Make flags more versatile/extensible - Delete associated flags when a post is deleted Uninstall the Reports extension before installing.
This commit is contained in:
@@ -11,4 +11,4 @@
|
|||||||
|
|
||||||
require __DIR__.'/vendor/autoload.php';
|
require __DIR__.'/vendor/autoload.php';
|
||||||
|
|
||||||
return 'Flarum\Reports\Extension';
|
return 'Flarum\Flags\Extension';
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Flarum\\Reports\\": "src/"
|
"Flarum\\Flags\\": "src/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "reports",
|
"name": "flags",
|
||||||
"title": "Reports",
|
"title": "Flags",
|
||||||
"description": "Allow users to report posts for moderator review.",
|
"description": "Allow users to flag posts for moderator review.",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"version": "0.1.0-beta.2",
|
"version": "0.1.0-beta.2",
|
||||||
"author": {
|
"author": {
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"flarum": ">=0.1.0-beta.2"
|
"flarum": ">=0.1.0-beta.2"
|
||||||
},
|
},
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/flarum/reports",
|
"source": "https://github.com/flarum/flags",
|
||||||
"issues": "https://github.com/flarum/core/issues"
|
"issues": "https://github.com/flarum/core/issues"
|
||||||
},
|
},
|
||||||
"icon": {
|
"icon": {
|
||||||
|
@@ -2,6 +2,6 @@ var gulp = require('flarum-gulp');
|
|||||||
|
|
||||||
gulp({
|
gulp({
|
||||||
modules: {
|
modules: {
|
||||||
'reports': 'src/**/*.js'
|
'flags': 'src/**/*.js'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -2,18 +2,20 @@ import { extend } from 'flarum/extend';
|
|||||||
import app from 'flarum/app';
|
import app from 'flarum/app';
|
||||||
import PermissionGrid from 'flarum/components/PermissionGrid';
|
import PermissionGrid from 'flarum/components/PermissionGrid';
|
||||||
|
|
||||||
app.initializers.add('reports', () => {
|
app.initializers.add('flags', () => {
|
||||||
extend(PermissionGrid.prototype, 'moderateItems', items => {
|
extend(PermissionGrid.prototype, 'moderateItems', items => {
|
||||||
items.add('viewReports', {
|
items.add('viewFlags', {
|
||||||
label: 'View reported posts',
|
icon: 'flag',
|
||||||
permission: 'discussion.viewReports'
|
label: 'View flagged posts',
|
||||||
});
|
permission: 'discussion.viewFlags'
|
||||||
|
}, 65);
|
||||||
});
|
});
|
||||||
|
|
||||||
extend(PermissionGrid.prototype, 'replyItems', items => {
|
extend(PermissionGrid.prototype, 'replyItems', items => {
|
||||||
items.add('reportPosts', {
|
items.add('flagPosts', {
|
||||||
label: 'Report posts',
|
icon: 'flag',
|
||||||
permission: 'discussion.reportPosts'
|
label: 'Flag posts',
|
||||||
});
|
permission: 'discussion.flagPosts'
|
||||||
|
}, 70);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -2,6 +2,6 @@ var gulp = require('flarum-gulp');
|
|||||||
|
|
||||||
gulp({
|
gulp({
|
||||||
modules: {
|
modules: {
|
||||||
'reports': 'src/**/*.js'
|
'flags': 'src/**/*.js'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -3,14 +3,14 @@ import app from 'flarum/app';
|
|||||||
import PostControls from 'flarum/utils/PostControls';
|
import PostControls from 'flarum/utils/PostControls';
|
||||||
import Button from 'flarum/components/Button';
|
import Button from 'flarum/components/Button';
|
||||||
|
|
||||||
import ReportPostModal from 'reports/components/ReportPostModal';
|
import FlagPostModal from 'flags/components/FlagPostModal';
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
extend(PostControls, 'userControls', function(items, post) {
|
extend(PostControls, 'userControls', function(items, post) {
|
||||||
if (post.isHidden() || post.contentType() !== 'comment' || !post.canReport() || post.user() === app.session.user) return;
|
if (post.isHidden() || post.contentType() !== 'comment' || !post.canFlag() || post.user() === app.session.user) return;
|
||||||
|
|
||||||
items.add('report',
|
items.add('flag',
|
||||||
<Button icon="flag" onclick={() => app.modal.show(new ReportPostModal({post}))}>Report</Button>
|
<Button icon="flag" onclick={() => app.modal.show(new FlagPostModal({post}))}>Flag</Button>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
@@ -1,12 +1,12 @@
|
|||||||
import { extend } from 'flarum/extend';
|
import { extend } from 'flarum/extend';
|
||||||
import app from 'flarum/app';
|
import app from 'flarum/app';
|
||||||
import HeaderSecondary from 'flarum/components/HeaderSecondary';
|
import HeaderSecondary from 'flarum/components/HeaderSecondary';
|
||||||
import ReportsDropdown from 'reports/components/ReportsDropdown';
|
import FlagsDropdown from 'flags/components/FlagsDropdown';
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
extend(HeaderSecondary.prototype, 'items', function(items) {
|
extend(HeaderSecondary.prototype, 'items', function(items) {
|
||||||
if (app.forum.attribute('canViewReports')) {
|
if (app.forum.attribute('canViewFlags')) {
|
||||||
items.add('reports', <ReportsDropdown/>, 15);
|
items.add('flags', <FlagsDropdown/>, 15);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
109
extensions/flags/js/forum/src/addFlagsToPosts.js
Normal file
109
extensions/flags/js/forum/src/addFlagsToPosts.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { extend } from 'flarum/extend';
|
||||||
|
import app from 'flarum/app';
|
||||||
|
import CommentPost from 'flarum/components/CommentPost';
|
||||||
|
import Button from 'flarum/components/Button';
|
||||||
|
import punctuate from 'flarum/helpers/punctuate';
|
||||||
|
import username from 'flarum/helpers/username';
|
||||||
|
import ItemList from 'flarum/utils/ItemList';
|
||||||
|
import PostControls from 'flarum/utils/PostControls';
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
extend(CommentPost.prototype, 'attrs', function(attrs) {
|
||||||
|
if (this.props.post.flags().length) {
|
||||||
|
attrs.className += ' Post--flagged';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
CommentPost.prototype.dismissFlag = function(data) {
|
||||||
|
const post = this.props.post;
|
||||||
|
|
||||||
|
delete post.data.relationships.flags;
|
||||||
|
|
||||||
|
this.subtree.invalidate();
|
||||||
|
|
||||||
|
if (app.cache.flags) {
|
||||||
|
app.cache.flags.some((flag, i) => {
|
||||||
|
if (flag.post() === post) {
|
||||||
|
app.cache.flags.splice(i, 1);
|
||||||
|
|
||||||
|
if (app.cache.flagIndex === post) {
|
||||||
|
let next = app.cache.flags[i];
|
||||||
|
|
||||||
|
if (!next) next = app.cache.flags[0];
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
const 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
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
CommentPost.prototype.flagActionItems = function() {
|
||||||
|
const items = new ItemList();
|
||||||
|
|
||||||
|
const controls = PostControls.destructiveControls(this.props.post);
|
||||||
|
|
||||||
|
Object.keys(controls).forEach(k => {
|
||||||
|
const props = controls[k].content.props;
|
||||||
|
|
||||||
|
props.className = 'Button';
|
||||||
|
|
||||||
|
extend(props, 'onclick', () => this.dismissFlag());
|
||||||
|
});
|
||||||
|
|
||||||
|
items.merge(controls);
|
||||||
|
|
||||||
|
items.add('dismiss', <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) {
|
||||||
|
const post = this.props.post;
|
||||||
|
const flags = post.flags();
|
||||||
|
|
||||||
|
if (!flags.length) return;
|
||||||
|
|
||||||
|
if (post.isHidden()) this.revealContent = true;
|
||||||
|
|
||||||
|
vdom.unshift(
|
||||||
|
<div className="Post-flagged">
|
||||||
|
<div className="Post-flagged-flags">
|
||||||
|
{flags.map(flag =>
|
||||||
|
<div className="Post-flagged-flag">
|
||||||
|
{this.flagReason(flag)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="Post-flagged-actions">
|
||||||
|
{this.flagActionItems().toArray()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
CommentPost.prototype.flagReason = function(flag) {
|
||||||
|
if (flag.type() === 'user') {
|
||||||
|
const user = flag.user();
|
||||||
|
const reason = flag.reason();
|
||||||
|
const detail = flag.reasonDetail();
|
||||||
|
|
||||||
|
return [
|
||||||
|
app.trans(reason ? 'flags.flagged_by_with_reason' : 'flags.flagged_by', {user, reason}),
|
||||||
|
detail ? <span className="Post-flagged-detail">{detail}</span> : ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -1,134 +0,0 @@
|
|||||||
import { extend } from 'flarum/extend';
|
|
||||||
import app from 'flarum/app';
|
|
||||||
import CommentPost from 'flarum/components/CommentPost';
|
|
||||||
import Button from 'flarum/components/Button';
|
|
||||||
import punctuate from 'flarum/helpers/punctuate';
|
|
||||||
import username from 'flarum/helpers/username';
|
|
||||||
import ItemList from 'flarum/utils/ItemList';
|
|
||||||
import PostControls from 'flarum/utils/PostControls';
|
|
||||||
|
|
||||||
export default function() {
|
|
||||||
extend(CommentPost.prototype, 'attrs', function(attrs) {
|
|
||||||
if (this.props.post.reports().length) {
|
|
||||||
attrs.className += ' Post--reported';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
CommentPost.prototype.dismissReport = function(data) {
|
|
||||||
const post = this.props.post;
|
|
||||||
|
|
||||||
delete post.data.relationships.reports;
|
|
||||||
|
|
||||||
this.subtree.invalidate();
|
|
||||||
|
|
||||||
if (app.cache.reports) {
|
|
||||||
app.cache.reports.some((report, i) => {
|
|
||||||
if (report.post() === post) {
|
|
||||||
app.cache.reports.splice(i, 1);
|
|
||||||
|
|
||||||
if (app.cache.reportIndex === post) {
|
|
||||||
let next = app.cache.reports[i];
|
|
||||||
|
|
||||||
if (!next) next = app.cache.reports[0];
|
|
||||||
|
|
||||||
if (next) {
|
|
||||||
const nextPost = next.post();
|
|
||||||
app.cache.reportIndex = nextPost;
|
|
||||||
m.route(app.route.post(nextPost));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return app.request({
|
|
||||||
url: app.forum.attribute('apiUrl') + post.apiEndpoint() + '/reports',
|
|
||||||
method: 'DELETE',
|
|
||||||
data
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
CommentPost.prototype.reportActionItems = function() {
|
|
||||||
const items = new ItemList();
|
|
||||||
|
|
||||||
if (this.props.post.isHidden()) {
|
|
||||||
if (this.props.post.canDelete()) {
|
|
||||||
items.add('delete',
|
|
||||||
<Button className="Button"
|
|
||||||
icon="trash-o"
|
|
||||||
onclick={() => {
|
|
||||||
this.dismissReport().then(() => {
|
|
||||||
PostControls.deleteAction.apply(this.props.post);
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
Delete Forever
|
|
||||||
</Button>,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
items.add('hide',
|
|
||||||
<Button className="Button"
|
|
||||||
icon="trash-o"
|
|
||||||
onclick={() => {
|
|
||||||
this.dismissReport().then(() => {
|
|
||||||
PostControls.hideAction.apply(this.props.post);
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
Delete Post
|
|
||||||
</Button>,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
items.add('dismiss', <Button className="Button Button--icon Button--link" icon="times" onclick={this.dismissReport.bind(this)}>Dismiss Report</Button>, -100);
|
|
||||||
|
|
||||||
return items;
|
|
||||||
};
|
|
||||||
|
|
||||||
extend(CommentPost.prototype, 'content', function(vdom) {
|
|
||||||
const post = this.props.post;
|
|
||||||
const reports = post.reports();
|
|
||||||
|
|
||||||
if (!reports.length) return;
|
|
||||||
|
|
||||||
if (post.isHidden()) this.revealContent = true;
|
|
||||||
|
|
||||||
const users = reports.map(report => {
|
|
||||||
const user = report.user();
|
|
||||||
|
|
||||||
return user
|
|
||||||
? <a href={app.route.user(user)} config={m.route}>{username(user)}</a>
|
|
||||||
: report.reporter();
|
|
||||||
});
|
|
||||||
|
|
||||||
const usedReasons = [];
|
|
||||||
const reasons = reports.map(report => report.reason()).filter(reason => {
|
|
||||||
if (reason && usedReasons.indexOf(reason) === -1) {
|
|
||||||
usedReasons.push(reason);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const details = reports.map(report => report.reasonDetail()).filter(detail => detail);
|
|
||||||
|
|
||||||
vdom.unshift(
|
|
||||||
<div className="Post-reported">
|
|
||||||
<div className="Post-reported-summary">
|
|
||||||
{app.trans(reasons.length ? 'reports.reported_by_with_reason' : 'reports.reported_by', {
|
|
||||||
reasons: punctuate(reasons.map(reason => app.trans('reports.reason_' + reason, undefined, reason))),
|
|
||||||
users: punctuate(users)
|
|
||||||
})}
|
|
||||||
{details.map(detail => <div className="Post-reported-detail">{detail}</div>)}
|
|
||||||
</div>
|
|
||||||
<div className="Post-reported-actions">
|
|
||||||
{this.reportActionItems().toArray()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
@@ -5,7 +5,7 @@ import username from 'flarum/helpers/username';
|
|||||||
import icon from 'flarum/helpers/icon';
|
import icon from 'flarum/helpers/icon';
|
||||||
import humanTime from 'flarum/helpers/humanTime';
|
import humanTime from 'flarum/helpers/humanTime';
|
||||||
|
|
||||||
export default class ReportList extends Component {
|
export default class FlagList extends Component {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
@@ -18,32 +18,32 @@ export default class ReportList extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
const reports = app.cache.reports || [];
|
const flags = app.cache.flags || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="NotificationList ReportList">
|
<div className="NotificationList FlagList">
|
||||||
<div className="NotificationList-header">
|
<div className="NotificationList-header">
|
||||||
<h4 className="App-titleControl App-titleControl--text">Reported Posts</h4>
|
<h4 className="App-titleControl App-titleControl--text">Flagged Posts</h4>
|
||||||
</div>
|
</div>
|
||||||
<div className="NotificationList-content">
|
<div className="NotificationList-content">
|
||||||
<ul className="NotificationGroup-content">
|
<ul className="NotificationGroup-content">
|
||||||
{reports.length
|
{flags.length
|
||||||
? reports.map(report => {
|
? flags.map(flag => {
|
||||||
const post = report.post();
|
const post = flag.post();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<a href={app.route.post(post)} className="Notification Report" config={function(element, isInitialized) {
|
<a href={app.route.post(post)} className="Notification Flag" config={function(element, isInitialized) {
|
||||||
m.route.apply(this, arguments);
|
m.route.apply(this, arguments);
|
||||||
|
|
||||||
if (!isInitialized) $(element).on('click', () => app.cache.reportIndex = post);
|
if (!isInitialized) $(element).on('click', () => app.cache.flagIndex = post);
|
||||||
}}>
|
}}>
|
||||||
{avatar(post.user())}
|
{avatar(post.user())}
|
||||||
{icon('flag', {className: 'Notification-icon'})}
|
{icon('flag', {className: 'Notification-icon'})}
|
||||||
<span className="Notification-content">
|
<span className="Notification-content">
|
||||||
{username(post.user())} in <em>{post.discussion().title()}</em>
|
{username(post.user())} in <em>{post.discussion().title()}</em>
|
||||||
</span>
|
</span>
|
||||||
{humanTime(report.time())}
|
{humanTime(flag.time())}
|
||||||
<div className="Notification-excerpt">
|
<div className="Notification-excerpt">
|
||||||
{post.contentPlain()}
|
{post.contentPlain()}
|
||||||
</div>
|
</div>
|
||||||
@@ -52,7 +52,7 @@ export default class ReportList extends Component {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
: !this.loading
|
: !this.loading
|
||||||
? <div className="NotificationList-empty">{app.trans('reports.no_reports')}</div>
|
? <div className="NotificationList-empty">{app.trans('flags.no_flags')}</div>
|
||||||
: LoadingIndicator.component({className: 'LoadingIndicator--block'})}
|
: LoadingIndicator.component({className: 'LoadingIndicator--block'})}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,20 +61,20 @@ export default class ReportList extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load reports into the application's cache if they haven't already
|
* Load flags into the application's cache if they haven't already
|
||||||
* been loaded.
|
* been loaded.
|
||||||
*/
|
*/
|
||||||
load() {
|
load() {
|
||||||
if (app.cache.reports && !app.forum.attribute('unreadReportsCount')) {
|
if (app.cache.flags && !app.forum.attribute('unreadFlagsCount')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
m.redraw();
|
m.redraw();
|
||||||
|
|
||||||
app.store.find('reports').then(reports => {
|
app.store.find('flags').then(flags => {
|
||||||
app.forum.pushAttributes({unreadReportsCount: 0});
|
app.forum.pushAttributes({unreadFlagsCount: 0});
|
||||||
app.cache.reports = reports.sort((a, b) => b.time() - a.time());
|
app.cache.flags = flags.sort((a, b) => b.time() - a.time());
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
m.redraw();
|
m.redraw();
|
@@ -1,7 +1,7 @@
|
|||||||
import Modal from 'flarum/components/Modal';
|
import Modal from 'flarum/components/Modal';
|
||||||
import Button from 'flarum/components/Button';
|
import Button from 'flarum/components/Button';
|
||||||
|
|
||||||
export default class ReportPostModal extends Modal {
|
export default class FlagPostModal extends Modal {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
@@ -10,11 +10,11 @@ export default class ReportPostModal extends Modal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
className() {
|
className() {
|
||||||
return 'ReportPostModal Modal--small';
|
return 'FlagPostModal Modal--small';
|
||||||
}
|
}
|
||||||
|
|
||||||
title() {
|
title() {
|
||||||
return 'Report Post';
|
return 'Flag Post';
|
||||||
}
|
}
|
||||||
|
|
||||||
content() {
|
content() {
|
||||||
@@ -55,7 +55,7 @@ export default class ReportPostModal extends Modal {
|
|||||||
type="submit"
|
type="submit"
|
||||||
loading={this.loading}
|
loading={this.loading}
|
||||||
disabled={!this.reason()}>
|
disabled={!this.reason()}>
|
||||||
Report Post
|
Flag Post
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,7 +68,7 @@ export default class ReportPostModal extends Modal {
|
|||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
app.store.createRecord('reports').save({
|
app.store.createRecord('flags').save({
|
||||||
reason: this.reason() === 'other' ? null : this.reason(),
|
reason: this.reason() === 'other' ? null : this.reason(),
|
||||||
reasonDetail: this.reasonDetail(),
|
reasonDetail: this.reasonDetail(),
|
||||||
relationships: {
|
relationships: {
|
26
extensions/flags/js/forum/src/components/FlagsDropdown.js
Normal file
26
extensions/flags/js/forum/src/components/FlagsDropdown.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import NotificationsDropdown from 'flarum/components/NotificationsDropdown';
|
||||||
|
|
||||||
|
import FlagList from 'flags/components/FlagList';
|
||||||
|
|
||||||
|
export default class FlagsDropdown extends NotificationsDropdown {
|
||||||
|
static initProps(props) {
|
||||||
|
props.label = props.label || 'Flagged Posts';
|
||||||
|
props.icon = props.icon || 'flag';
|
||||||
|
|
||||||
|
super.initProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
|
||||||
|
this.list = new FlagList();
|
||||||
|
}
|
||||||
|
|
||||||
|
goToRoute() {
|
||||||
|
m.route(app.route('flags'));
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnreadCount() {
|
||||||
|
return app.forum.attribute('unreadFlagsCount');
|
||||||
|
}
|
||||||
|
}
|
24
extensions/flags/js/forum/src/components/FlagsPage.js
Normal file
24
extensions/flags/js/forum/src/components/FlagsPage.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import Page from 'flarum/components/Page';
|
||||||
|
|
||||||
|
import FlagList from 'flags/components/FlagList';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `FlagsPage` component shows the flags list. It is only
|
||||||
|
* used on mobile devices where the flags dropdown is within the drawer.
|
||||||
|
*/
|
||||||
|
export default class FlagsPage extends Page {
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
|
||||||
|
app.history.push('flags');
|
||||||
|
|
||||||
|
this.list = new FlagList();
|
||||||
|
this.list.load();
|
||||||
|
|
||||||
|
this.bodyClass = 'App--flags';
|
||||||
|
}
|
||||||
|
|
||||||
|
view() {
|
||||||
|
return <div className="FlagsPage">{this.list.render()}</div>;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,26 +0,0 @@
|
|||||||
import NotificationsDropdown from 'flarum/components/NotificationsDropdown';
|
|
||||||
|
|
||||||
import ReportList from 'reports/components/ReportList';
|
|
||||||
|
|
||||||
export default class ReportsDropdown extends NotificationsDropdown {
|
|
||||||
static initProps(props) {
|
|
||||||
props.label = props.label || 'Reports';
|
|
||||||
props.icon = props.icon || 'flag';
|
|
||||||
|
|
||||||
super.initProps(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
this.list = new ReportList();
|
|
||||||
}
|
|
||||||
|
|
||||||
goToRoute() {
|
|
||||||
m.route(app.route('reports'));
|
|
||||||
}
|
|
||||||
|
|
||||||
getUnreadCount() {
|
|
||||||
return app.forum.attribute('unreadReportsCount');
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,24 +0,0 @@
|
|||||||
import Page from 'flarum/components/Page';
|
|
||||||
|
|
||||||
import ReportList from 'reports/components/ReportList';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `ReportsPage` component shows the reports list. It is only
|
|
||||||
* used on mobile devices where the reports dropdown is within the drawer.
|
|
||||||
*/
|
|
||||||
export default class ReportsPage extends Page {
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
app.history.push('reports');
|
|
||||||
|
|
||||||
this.list = new ReportList();
|
|
||||||
this.list.load();
|
|
||||||
|
|
||||||
this.bodyClass = 'App--reports';
|
|
||||||
}
|
|
||||||
|
|
||||||
view() {
|
|
||||||
return <div className="ReportsPage">{this.list.render()}</div>;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,21 +1,21 @@
|
|||||||
import app from 'flarum/app';
|
import app from 'flarum/app';
|
||||||
import Model from 'flarum/Model';
|
import Model from 'flarum/Model';
|
||||||
|
|
||||||
import Report from 'reports/models/Report';
|
import Flag from 'flags/models/Flag';
|
||||||
import ReportsPage from 'reports/components/ReportsPage';
|
import FlagsPage from 'flags/components/FlagsPage';
|
||||||
import addReportControl from 'reports/addReportControl';
|
import addFlagControl from 'flags/addFlagControl';
|
||||||
import addReportsDropdown from 'reports/addReportsDropdown';
|
import addFlagsDropdown from 'flags/addFlagsDropdown';
|
||||||
import addReportsToPosts from 'reports/addReportsToPosts';
|
import addFlagsToPosts from 'flags/addFlagsToPosts';
|
||||||
|
|
||||||
app.initializers.add('reports', () => {
|
app.initializers.add('flags', () => {
|
||||||
app.store.models.posts.prototype.reports = Model.hasMany('reports');
|
app.store.models.posts.prototype.flags = Model.hasMany('flags');
|
||||||
app.store.models.posts.prototype.canReport = Model.attribute('canReport');
|
app.store.models.posts.prototype.canFlag = Model.attribute('canFlag');
|
||||||
|
|
||||||
app.store.models.reports = Report;
|
app.store.models.flags = Flag;
|
||||||
|
|
||||||
app.routes.reports = {path: '/reports', component: <ReportsPage/>};
|
app.routes.flags = {path: '/flags', component: <FlagsPage/>};
|
||||||
|
|
||||||
addReportControl();
|
addFlagControl();
|
||||||
addReportsDropdown();
|
addFlagsDropdown();
|
||||||
addReportsToPosts();
|
addFlagsToPosts();
|
||||||
});
|
});
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import Model from 'flarum/Model';
|
import Model from 'flarum/Model';
|
||||||
import mixin from 'flarum/utils/mixin';
|
import mixin from 'flarum/utils/mixin';
|
||||||
|
|
||||||
export default class Report extends mixin(Model, {
|
export default class Flag extends mixin(Model, {
|
||||||
reporter: Model.attribute('reporter'),
|
type: Model.attribute('type'),
|
||||||
reason: Model.attribute('reason'),
|
reason: Model.attribute('reason'),
|
||||||
reasonDetail: Model.attribute('reasonDetail'),
|
reasonDetail: Model.attribute('reasonDetail'),
|
||||||
time: Model.attribute('time', Model.transformDate),
|
time: Model.attribute('time', Model.transformDate),
|
@@ -1,34 +1,32 @@
|
|||||||
.Post--reported {
|
.Post--flagged {
|
||||||
padding-top: 0 !important;
|
padding-top: 0 !important;
|
||||||
border: 2px solid @primary-color;
|
border: 2px solid @primary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Post-header .item-reported {
|
.Post-header .item-flagged {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.Post-reported {
|
.Post-flagged {
|
||||||
background: @primary-color;
|
background: @primary-color;
|
||||||
margin-top: -2px;
|
margin-top: -2px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
margin-left: -22px;
|
margin-left: -22px;
|
||||||
margin-right: -22px;
|
margin-right: -22px;
|
||||||
|
|
||||||
@media @tablet-up {
|
|
||||||
margin-left: -22px - 85px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: @border-radius @border-radius 0 0;
|
border-radius: @border-radius @border-radius 0 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
.light-contents(@color: @body-bg; @control-color: @body-bg);
|
.light-contents(@color: @body-bg; @control-color: @body-bg);
|
||||||
|
|
||||||
|
@media @tablet-up {
|
||||||
|
margin-left: -22px - 85px;
|
||||||
|
}
|
||||||
|
|
||||||
&, a {
|
&, a {
|
||||||
color: @body-bg !important;
|
color: @body-bg !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.Post-reported-summary {
|
.Post-flagged-flags {
|
||||||
@media @tablet-up {
|
@media @tablet-up {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
@@ -38,16 +36,21 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.Post-reported-detail {
|
.Post-flagged-detail {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 5px;
|
margin-left: 10px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
.Post-reported-actions .Button {
|
.Post-flagged-actions {
|
||||||
|
@media @tablet-up {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.Post-flagged-actions .Button {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ReportsDropdown .Dropdown-toggle {
|
.FlagsDropdown .Dropdown-toggle {
|
||||||
.Button-label,
|
.Button-label,
|
||||||
.Button-caret {
|
.Button-caret {
|
||||||
display: none;
|
display: none;
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
reports:
|
flags:
|
||||||
reason_off_topic: Off-topic
|
reason_off_topic: Off-topic
|
||||||
reason_spam: Spam
|
reason_spam: Spam
|
||||||
reason_inappropriate: Inappropriate
|
reason_inappropriate: Inappropriate
|
||||||
reason_other: Other
|
reason_other: Other
|
||||||
reported_by: "Reported by {users}"
|
flagged_by: "{username} flagged"
|
||||||
reported_by_with_reason: "Reported as {reasons} by {users}"
|
flagged_by_with_reason: "{username} flagged as {reason}"
|
||||||
no_reports: No Reports
|
no_flags: No Flags
|
||||||
|
@@ -8,22 +8,22 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Migrations\Reports;
|
namespace Flarum\Migrations\Flags;
|
||||||
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Flarum\Migrations\Migration;
|
use Flarum\Migrations\Migration;
|
||||||
|
|
||||||
class AddReportsReadTimeToUsersTable extends Migration
|
class AddFlagsReadTimeToUsersTable extends Migration
|
||||||
{
|
{
|
||||||
public function up()
|
public function up()
|
||||||
{
|
{
|
||||||
$this->schema->table('users', function (Blueprint $table) {
|
$this->schema->table('users', function (Blueprint $table) {
|
||||||
$table->dateTime('reports_read_time')->nullable();
|
$table->dateTime('flags_read_time')->nullable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
$this->schema->drop('reports_read_time');
|
$this->schema->drop('flags_read_time');
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,20 +8,20 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Migrations\Reports;
|
namespace Flarum\Migrations\Flags;
|
||||||
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Flarum\Migrations\Migration;
|
use Flarum\Migrations\Migration;
|
||||||
|
|
||||||
class CreateReportsTable extends Migration
|
class CreateFlagsTable extends Migration
|
||||||
{
|
{
|
||||||
public function up()
|
public function up()
|
||||||
{
|
{
|
||||||
$this->schema->create('reports', function (Blueprint $table) {
|
$this->schema->create('flags', function (Blueprint $table) {
|
||||||
$table->increments('id');
|
$table->increments('id');
|
||||||
$table->integer('post_id')->unsigned();
|
$table->integer('post_id')->unsigned();
|
||||||
$table->integer('user_id')->unsigned();
|
$table->string('type');
|
||||||
$table->string('reporter')->nullable();
|
$table->integer('user_id')->unsigned()->nullable();
|
||||||
$table->string('reason')->nullable();
|
$table->string('reason')->nullable();
|
||||||
$table->string('reason_detail')->nullable();
|
$table->string('reason_detail')->nullable();
|
||||||
$table->dateTime('time');
|
$table->dateTime('time');
|
||||||
@@ -30,6 +30,6 @@ class CreateReportsTable extends Migration
|
|||||||
|
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
$this->schema->drop('reports');
|
$this->schema->drop('flags');
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,9 +8,9 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Api;
|
namespace Flarum\Flags\Api;
|
||||||
|
|
||||||
use Flarum\Reports\Commands\CreateReport;
|
use Flarum\Flags\Commands\CreateFlag;
|
||||||
use Flarum\Api\Actions\CreateAction as BaseCreateAction;
|
use Flarum\Api\Actions\CreateAction as BaseCreateAction;
|
||||||
use Flarum\Api\JsonApiRequest;
|
use Flarum\Api\JsonApiRequest;
|
||||||
use Illuminate\Contracts\Bus\Dispatcher;
|
use Illuminate\Contracts\Bus\Dispatcher;
|
||||||
@@ -25,14 +25,14 @@ class CreateAction extends BaseCreateAction
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public $serializer = 'Flarum\Reports\Api\ReportSerializer';
|
public $serializer = 'Flarum\Flags\Api\FlagSerializer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public $include = [
|
public $include = [
|
||||||
'post' => true,
|
'post' => true,
|
||||||
'post.reports' => true
|
'post.flags' => true
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,15 +44,15 @@ class CreateAction extends BaseCreateAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a report according to input from the API request.
|
* Create a flag according to input from the API request.
|
||||||
*
|
*
|
||||||
* @param JsonApiRequest $request
|
* @param JsonApiRequest $request
|
||||||
* @return \Flarum\Reports\Report
|
* @return \Flarum\Flags\Flag
|
||||||
*/
|
*/
|
||||||
protected function create(JsonApiRequest $request)
|
protected function create(JsonApiRequest $request)
|
||||||
{
|
{
|
||||||
return $this->bus->dispatch(
|
return $this->bus->dispatch(
|
||||||
new CreateReport($request->actor, $request->get('data'))
|
new CreateFlag($request->actor, $request->get('data'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,9 +8,9 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Api;
|
namespace Flarum\Flags\Api;
|
||||||
|
|
||||||
use Flarum\Reports\Commands\DeleteReports;
|
use Flarum\Flags\Commands\DeleteFlags;
|
||||||
use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
|
use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
|
||||||
use Flarum\Api\Request;
|
use Flarum\Api\Request;
|
||||||
use Illuminate\Contracts\Bus\Dispatcher;
|
use Illuminate\Contracts\Bus\Dispatcher;
|
||||||
@@ -31,14 +31,14 @@ class DeleteAction extends BaseDeleteAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete reports for a post.
|
* Delete flags for a post.
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*/
|
*/
|
||||||
protected function delete(Request $request)
|
protected function delete(Request $request)
|
||||||
{
|
{
|
||||||
$this->bus->dispatch(
|
$this->bus->dispatch(
|
||||||
new DeleteReports($request->get('id'), $request->actor, $request->all())
|
new DeleteFlags($request->get('id'), $request->actor, $request->all())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,20 +8,20 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Api;
|
namespace Flarum\Flags\Api;
|
||||||
|
|
||||||
use Flarum\Api\Serializers\Serializer;
|
use Flarum\Api\Serializers\Serializer;
|
||||||
|
|
||||||
class ReportSerializer extends Serializer
|
class FlagSerializer extends Serializer
|
||||||
{
|
{
|
||||||
protected $type = 'reports';
|
protected $type = 'flags';
|
||||||
|
|
||||||
protected function getDefaultAttributes($report)
|
protected function getDefaultAttributes($flag)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'reporter' => $report->reporter,
|
'type' => $flag->type,
|
||||||
'reason' => $report->reason,
|
'reason' => $flag->reason,
|
||||||
'reasonDetail' => $report->reason_detail,
|
'reasonDetail' => $flag->reason_detail,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@@ -8,11 +8,11 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Api;
|
namespace Flarum\Flags\Api;
|
||||||
|
|
||||||
use Flarum\Api\Actions\SerializeCollectionAction;
|
use Flarum\Api\Actions\SerializeCollectionAction;
|
||||||
use Flarum\Api\JsonApiRequest;
|
use Flarum\Api\JsonApiRequest;
|
||||||
use Flarum\Reports\Report;
|
use Flarum\Flags\Flag;
|
||||||
use Tobscure\JsonApi\Document;
|
use Tobscure\JsonApi\Document;
|
||||||
|
|
||||||
class IndexAction extends SerializeCollectionAction
|
class IndexAction extends SerializeCollectionAction
|
||||||
@@ -20,7 +20,7 @@ class IndexAction extends SerializeCollectionAction
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public $serializer = 'Flarum\Reports\Api\ReportSerializer';
|
public $serializer = 'Flarum\Flags\Api\FlagSerializer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
@@ -41,12 +41,12 @@ class IndexAction extends SerializeCollectionAction
|
|||||||
{
|
{
|
||||||
$actor = $request->actor;
|
$actor = $request->actor;
|
||||||
|
|
||||||
$actor->reports_read_time = time();
|
$actor->flags_read_time = time();
|
||||||
$actor->save();
|
$actor->save();
|
||||||
|
|
||||||
return Report::whereVisibleTo($actor)
|
return Flag::whereVisibleTo($actor)
|
||||||
->with($request->include)
|
->with($request->include)
|
||||||
->latest('reports.time')
|
->latest('flags.time')
|
||||||
->groupBy('post_id')
|
->groupBy('post_id')
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
@@ -8,11 +8,11 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Commands;
|
namespace Flarum\Flags\Commands;
|
||||||
|
|
||||||
use Flarum\Core\Users\User;
|
use Flarum\Core\Users\User;
|
||||||
|
|
||||||
class CreateReport
|
class CreateFlag
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The user performing the action.
|
* The user performing the action.
|
||||||
@@ -22,7 +22,7 @@ class CreateReport
|
|||||||
public $actor;
|
public $actor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes of the new report.
|
* The attributes of the new flag.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@@ -30,7 +30,7 @@ class CreateReport
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param User $actor The user performing the action.
|
* @param User $actor The user performing the action.
|
||||||
* @param array $data The attributes of the new report.
|
* @param array $data The attributes of the new flag.
|
||||||
*/
|
*/
|
||||||
public function __construct(User $actor, array $data)
|
public function __construct(User $actor, array $data)
|
||||||
{
|
{
|
@@ -8,14 +8,14 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Commands;
|
namespace Flarum\Flags\Commands;
|
||||||
|
|
||||||
use Flarum\Reports\Report;
|
use Flarum\Flags\Flag;
|
||||||
use Flarum\Core\Posts\PostRepository;
|
use Flarum\Core\Posts\PostRepository;
|
||||||
use Flarum\Core\Posts\CommentPost;
|
use Flarum\Core\Posts\CommentPost;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class CreateReportHandler
|
class CreateFlagHandler
|
||||||
{
|
{
|
||||||
private $posts;
|
private $posts;
|
||||||
|
|
||||||
@@ -25,10 +25,10 @@ class CreateReportHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param CreateReport $command
|
* @param CreateFlag $command
|
||||||
* @return Report
|
* @return Flag
|
||||||
*/
|
*/
|
||||||
public function handle(CreateReport $command)
|
public function handle(CreateFlag $command)
|
||||||
{
|
{
|
||||||
$actor = $command->actor;
|
$actor = $command->actor;
|
||||||
$data = $command->data;
|
$data = $command->data;
|
||||||
@@ -41,23 +41,24 @@ class CreateReportHandler
|
|||||||
throw new Exception;
|
throw new Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
$post->assertCan($actor, 'report');
|
$post->assertCan($actor, 'flag');
|
||||||
|
|
||||||
Report::unguard();
|
Flag::unguard();
|
||||||
|
|
||||||
$report = Report::firstOrNew([
|
$flag = Flag::firstOrNew([
|
||||||
'post_id' => $post->id,
|
'post_id' => $post->id,
|
||||||
'user_id' => $actor->id
|
'user_id' => $actor->id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$report->post_id = $post->id;
|
$flag->post_id = $post->id;
|
||||||
$report->user_id = $actor->id;
|
$flag->user_id = $actor->id;
|
||||||
$report->reason = array_get($data, 'attributes.reason');
|
$flag->type = 'user';
|
||||||
$report->reason_detail = array_get($data, 'attributes.reasonDetail');
|
$flag->reason = array_get($data, 'attributes.reason');
|
||||||
$report->time = time();
|
$flag->reason_detail = array_get($data, 'attributes.reasonDetail');
|
||||||
|
$flag->time = time();
|
||||||
|
|
||||||
$report->save();
|
$flag->save();
|
||||||
|
|
||||||
return $report;
|
return $flag;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,15 +8,15 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Commands;
|
namespace Flarum\Flags\Commands;
|
||||||
|
|
||||||
use Flarum\Reports\Report;
|
use Flarum\Flags\Flag;
|
||||||
use Flarum\Core\Users\User;
|
use Flarum\Core\Users\User;
|
||||||
|
|
||||||
class DeleteReports
|
class DeleteFlags
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The ID of the post to delete reports for.
|
* The ID of the post to delete flags for.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
@@ -35,7 +35,7 @@ class DeleteReports
|
|||||||
public $data;
|
public $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $postId The ID of the post to delete reports for.
|
* @param int $postId The ID of the post to delete flags for.
|
||||||
* @param User $actor The user performing the action.
|
* @param User $actor The user performing the action.
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*/
|
*/
|
@@ -8,13 +8,13 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Commands;
|
namespace Flarum\Flags\Commands;
|
||||||
|
|
||||||
use Flarum\Reports\Report;
|
use Flarum\Flags\Flag;
|
||||||
use Flarum\Core\Posts\PostRepository;
|
use Flarum\Core\Posts\PostRepository;
|
||||||
use Flarum\Reports\Events\ReportsWillBeDeleted;
|
use Flarum\Flags\Events\FlagsWillBeDeleted;
|
||||||
|
|
||||||
class DeleteReportsHandler
|
class DeleteFlagsHandler
|
||||||
{
|
{
|
||||||
protected $posts;
|
protected $posts;
|
||||||
|
|
||||||
@@ -24,21 +24,21 @@ class DeleteReportsHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param DeleteReport $command
|
* @param DeleteFlag $command
|
||||||
* @return Report
|
* @return Flag
|
||||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||||
*/
|
*/
|
||||||
public function handle(DeleteReports $command)
|
public function handle(DeleteFlags $command)
|
||||||
{
|
{
|
||||||
$actor = $command->actor;
|
$actor = $command->actor;
|
||||||
|
|
||||||
$post = $this->posts->findOrFail($command->postId, $actor);
|
$post = $this->posts->findOrFail($command->postId, $actor);
|
||||||
|
|
||||||
$post->discussion->assertCan($actor, 'viewReports');
|
$post->discussion->assertCan($actor, 'viewFlags');
|
||||||
|
|
||||||
event(new ReportsWillBeDeleted($post, $actor, $command->data));
|
event(new FlagsWillBeDeleted($post, $actor, $command->data));
|
||||||
|
|
||||||
$post->reports()->delete();
|
$post->flags()->delete();
|
||||||
|
|
||||||
return $post;
|
return $post;
|
||||||
}
|
}
|
@@ -9,12 +9,12 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Events;
|
namespace Flarum\Flags\Events;
|
||||||
|
|
||||||
use Flarum\Core\Posts\Post;
|
use Flarum\Core\Posts\Post;
|
||||||
use Flarum\Core\Users\User;
|
use Flarum\Core\Users\User;
|
||||||
|
|
||||||
class ReportsWillBeDeleted
|
class FlagsWillBeDeleted
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Post
|
* @var Post
|
@@ -8,17 +8,18 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports;
|
namespace Flarum\Flags;
|
||||||
|
|
||||||
use Flarum\Support\Extension as BaseExtension;
|
use Flarum\Support\Extension as BaseExtension;
|
||||||
use Illuminate\Events\Dispatcher;
|
use Illuminate\Events\Dispatcher;
|
||||||
|
use Flarum\Core\Posts\Post;
|
||||||
|
|
||||||
class Extension extends BaseExtension
|
class Extension extends BaseExtension
|
||||||
{
|
{
|
||||||
public function listen(Dispatcher $events)
|
public function listen(Dispatcher $events)
|
||||||
{
|
{
|
||||||
$events->subscribe('Flarum\Reports\Listeners\AddClientAssets');
|
$events->subscribe('Flarum\Flags\Listeners\AddClientAssets');
|
||||||
$events->subscribe('Flarum\Reports\Listeners\AddApiAttributes');
|
$events->subscribe('Flarum\Flags\Listeners\AddApiAttributes');
|
||||||
$events->subscribe('Flarum\Reports\Listeners\AddModelRelationship');
|
$events->subscribe('Flarum\Flags\Listeners\AddModelRelationship');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,16 +8,16 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports;
|
namespace Flarum\Flags;
|
||||||
|
|
||||||
use Flarum\Core\Model;
|
use Flarum\Core\Model;
|
||||||
use Flarum\Core\Support\VisibleScope;
|
use Flarum\Core\Support\VisibleScope;
|
||||||
|
|
||||||
class Report extends Model
|
class Flag extends Model
|
||||||
{
|
{
|
||||||
use VisibleScope;
|
use VisibleScope;
|
||||||
|
|
||||||
protected $table = 'reports';
|
protected $table = 'flags';
|
||||||
|
|
||||||
protected $dates = ['time'];
|
protected $dates = ['time'];
|
||||||
|
|
@@ -8,7 +8,7 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Listeners;
|
namespace Flarum\Flags\Listeners;
|
||||||
|
|
||||||
use Flarum\Events\ApiRelationship;
|
use Flarum\Events\ApiRelationship;
|
||||||
use Flarum\Events\WillSerializeData;
|
use Flarum\Events\WillSerializeData;
|
||||||
@@ -19,26 +19,26 @@ use Flarum\Api\Serializers\PostSerializer;
|
|||||||
use Flarum\Api\Serializers\ForumSerializer;
|
use Flarum\Api\Serializers\ForumSerializer;
|
||||||
use Flarum\Api\Actions\Posts;
|
use Flarum\Api\Actions\Posts;
|
||||||
use Flarum\Api\Actions\Discussions;
|
use Flarum\Api\Actions\Discussions;
|
||||||
use Flarum\Reports\Report;
|
use Flarum\Flags\Flag;
|
||||||
use Flarum\Reports\Api\CreateAction as ReportsCreateAction;
|
use Flarum\Flags\Api\CreateAction as FlagsCreateAction;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class AddApiAttributes
|
class AddApiAttributes
|
||||||
{
|
{
|
||||||
public function subscribe($events)
|
public function subscribe($events)
|
||||||
{
|
{
|
||||||
$events->listen(ApiRelationship::class, [$this, 'addReportsRelationship']);
|
$events->listen(ApiRelationship::class, [$this, 'addFlagsRelationship']);
|
||||||
$events->listen(WillSerializeData::class, [$this, 'loadReportsRelationship']);
|
$events->listen(WillSerializeData::class, [$this, 'loadFlagsRelationship']);
|
||||||
$events->listen(BuildApiAction::class, [$this, 'includeReportsRelationship']);
|
$events->listen(BuildApiAction::class, [$this, 'includeFlagsRelationship']);
|
||||||
$events->listen(ApiAttributes::class, [$this, 'addAttributes']);
|
$events->listen(ApiAttributes::class, [$this, 'addAttributes']);
|
||||||
$events->listen(RegisterApiRoutes::class, [$this, 'addRoutes']);
|
$events->listen(RegisterApiRoutes::class, [$this, 'addRoutes']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadReportsRelationship(WillSerializeData $event)
|
public function loadFlagsRelationship(WillSerializeData $event)
|
||||||
{
|
{
|
||||||
// For any API action that allows the 'reports' relationship to be
|
// For any API action that allows the 'flags' relationship to be
|
||||||
// included, we need to preload this relationship onto the data (Post
|
// included, we need to preload this relationship onto the data (Post
|
||||||
// models) so that we can selectively expose only the reports that the
|
// models) so that we can selectively expose only the flags that the
|
||||||
// user has permission to view.
|
// user has permission to view.
|
||||||
if ($event->action instanceof Discussions\ShowAction) {
|
if ($event->action instanceof Discussions\ShowAction) {
|
||||||
$discussion = $event->data;
|
$discussion = $event->data;
|
||||||
@@ -53,9 +53,9 @@ class AddApiAttributes
|
|||||||
$posts = [$event->data];
|
$posts = [$event->data];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event->action instanceof ReportsCreateAction) {
|
if ($event->action instanceof FlagsCreateAction) {
|
||||||
$report = $event->data;
|
$flag = $event->data;
|
||||||
$posts = [$report->post];
|
$posts = [$flag->post];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($posts)) {
|
if (isset($posts)) {
|
||||||
@@ -63,67 +63,67 @@ class AddApiAttributes
|
|||||||
$postsWithPermission = [];
|
$postsWithPermission = [];
|
||||||
|
|
||||||
foreach ($posts as $post) {
|
foreach ($posts as $post) {
|
||||||
$post->setRelation('reports', null);
|
$post->setRelation('flags', null);
|
||||||
|
|
||||||
if ($post->discussion->can($actor, 'viewReports')) {
|
if ($post->discussion->can($actor, 'viewFlags')) {
|
||||||
$postsWithPermission[] = $post;
|
$postsWithPermission[] = $post;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($postsWithPermission)) {
|
if (count($postsWithPermission)) {
|
||||||
(new Collection($postsWithPermission))
|
(new Collection($postsWithPermission))
|
||||||
->load('reports', 'reports.user');
|
->load('flags', 'flags.user');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addReportsRelationship(ApiRelationship $event)
|
public function addFlagsRelationship(ApiRelationship $event)
|
||||||
{
|
{
|
||||||
if ($event->serializer instanceof PostSerializer &&
|
if ($event->serializer instanceof PostSerializer &&
|
||||||
$event->relationship === 'reports') {
|
$event->relationship === 'flags') {
|
||||||
return $event->serializer->hasMany('Flarum\Reports\Api\ReportSerializer', 'reports');
|
return $event->serializer->hasMany('Flarum\Flags\Api\FlagSerializer', 'flags');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function includeReportsRelationship(BuildApiAction $event)
|
public function includeFlagsRelationship(BuildApiAction $event)
|
||||||
{
|
{
|
||||||
if ($event->action instanceof Discussions\ShowAction) {
|
if ($event->action instanceof Discussions\ShowAction) {
|
||||||
$event->addInclude('posts.reports');
|
$event->addInclude('posts.flags');
|
||||||
$event->addInclude('posts.reports.user');
|
$event->addInclude('posts.flags.user');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event->action instanceof Posts\IndexAction ||
|
if ($event->action instanceof Posts\IndexAction ||
|
||||||
$event->action instanceof Posts\ShowAction) {
|
$event->action instanceof Posts\ShowAction) {
|
||||||
$event->addInclude('reports');
|
$event->addInclude('flags');
|
||||||
$event->addInclude('reports.user');
|
$event->addInclude('flags.user');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addAttributes(ApiAttributes $event)
|
public function addAttributes(ApiAttributes $event)
|
||||||
{
|
{
|
||||||
if ($event->serializer instanceof ForumSerializer) {
|
if ($event->serializer instanceof ForumSerializer) {
|
||||||
$event->attributes['canViewReports'] = $event->actor->hasPermissionLike('discussion.viewReports');
|
$event->attributes['canViewFlags'] = $event->actor->hasPermissionLike('discussion.viewFlags');
|
||||||
|
|
||||||
if ($event->attributes['canViewReports']) {
|
if ($event->attributes['canViewFlags']) {
|
||||||
$query = Report::whereVisibleTo($event->actor);
|
$query = Flag::whereVisibleTo($event->actor);
|
||||||
|
|
||||||
if ($time = $event->actor->reports_read_time) {
|
if ($time = $event->actor->flags_read_time) {
|
||||||
$query->where('reports.time', '>', $time);
|
$query->where('flags.time', '>', $time);
|
||||||
}
|
}
|
||||||
|
|
||||||
$event->attributes['unreadReportsCount'] = $query->distinct('reports.post_id')->count();
|
$event->attributes['unreadFlagsCount'] = $query->distinct('flags.post_id')->count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event->serializer instanceof PostSerializer) {
|
if ($event->serializer instanceof PostSerializer) {
|
||||||
$event->attributes['canReport'] = $event->model->can($event->actor, 'report');
|
$event->attributes['canFlag'] = $event->model->can($event->actor, 'flag');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRoutes(RegisterApiRoutes $event)
|
public function addRoutes(RegisterApiRoutes $event)
|
||||||
{
|
{
|
||||||
$event->get('/reports', 'reports.index', 'Flarum\Reports\Api\IndexAction');
|
$event->get('/flags', 'flags.index', 'Flarum\Flags\Api\IndexAction');
|
||||||
$event->post('/reports', 'reports.create', 'Flarum\Reports\Api\CreateAction');
|
$event->post('/flags', 'flags.create', 'Flarum\Flags\Api\CreateAction');
|
||||||
$event->delete('/posts/{id}/reports', 'reports.delete', 'Flarum\Reports\Api\DeleteAction');
|
$event->delete('/posts/{id}/flags', 'flags.delete', 'Flarum\Flags\Api\DeleteAction');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Listeners;
|
namespace Flarum\Flags\Listeners;
|
||||||
|
|
||||||
use Flarum\Events\RegisterLocales;
|
use Flarum\Events\RegisterLocales;
|
||||||
use Flarum\Events\BuildClientView;
|
use Flarum\Events\BuildClientView;
|
||||||
@@ -34,16 +34,16 @@ class AddClientAssets
|
|||||||
__DIR__.'/../../less/forum/extension.less'
|
__DIR__.'/../../less/forum/extension.less'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event->forumBootstrapper('reports/main');
|
$event->forumBootstrapper('flags/main');
|
||||||
|
|
||||||
$event->forumTranslations([
|
$event->forumTranslations([
|
||||||
'reports.reason_off_topic',
|
'flags.reason_off_topic',
|
||||||
'reports.reason_spam',
|
'flags.reason_spam',
|
||||||
'reports.reason_inappropriate',
|
'flags.reason_inappropriate',
|
||||||
'reports.reason_other',
|
'flags.reason_other',
|
||||||
'reports.reported_by',
|
'flags.flagged_by',
|
||||||
'reports.reported_by_with_reason',
|
'flags.flagged_by_with_reason',
|
||||||
'reports.no_reports'
|
'flags.no_flags'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event->adminAssets([
|
$event->adminAssets([
|
||||||
@@ -51,10 +51,10 @@ class AddClientAssets
|
|||||||
__DIR__.'/../../less/admin/extension.less'
|
__DIR__.'/../../less/admin/extension.less'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event->adminBootstrapper('reports/main');
|
$event->adminBootstrapper('flags/main');
|
||||||
|
|
||||||
$event->adminTranslations([
|
$event->adminTranslations([
|
||||||
// 'report.hello_world'
|
// 'flag.hello_world'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,33 +8,40 @@
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Flarum\Reports\Listeners;
|
namespace Flarum\Flags\Listeners;
|
||||||
|
|
||||||
use Flarum\Events\ModelRelationship;
|
use Flarum\Events\ModelRelationship;
|
||||||
use Flarum\Events\ModelDates;
|
use Flarum\Events\ModelDates;
|
||||||
|
use Flarum\Events\PostWasDeleted;
|
||||||
use Flarum\Core\Posts\Post;
|
use Flarum\Core\Posts\Post;
|
||||||
use Flarum\Core\Users\User;
|
use Flarum\Core\Users\User;
|
||||||
use Flarum\Reports\Report;
|
use Flarum\Flags\Flag;
|
||||||
|
|
||||||
class AddModelRelationship
|
class AddModelRelationship
|
||||||
{
|
{
|
||||||
public function subscribe($events)
|
public function subscribe($events)
|
||||||
{
|
{
|
||||||
$events->listen(ModelRelationship::class, [$this, 'addReportsRelationship']);
|
$events->listen(ModelRelationship::class, [$this, 'addFlagsRelationship']);
|
||||||
$events->listen(ModelDates::class, [$this, 'modelDates']);
|
$events->listen(ModelDates::class, [$this, 'modelDates']);
|
||||||
|
$events->listen(PostWasDeleted::class, [$this, 'deleteFlags']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addReportsRelationship(ModelRelationship $event)
|
public function addFlagsRelationship(ModelRelationship $event)
|
||||||
{
|
{
|
||||||
if ($event->model instanceof Post && $event->relationship === 'reports') {
|
if ($event->model instanceof Post && $event->relationship === 'flags') {
|
||||||
return $event->model->hasMany('Flarum\Reports\Report', 'post_id');
|
return $event->model->hasMany('Flarum\Flags\Flag', 'post_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function modelDates(ModelDates $event)
|
public function modelDates(ModelDates $event)
|
||||||
{
|
{
|
||||||
if ($event->model instanceof User) {
|
if ($event->model instanceof User) {
|
||||||
$event->dates[] = 'reports_read_time';
|
$event->dates[] = 'flags_read_time';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteFlags(PostWasDeleted $event)
|
||||||
|
{
|
||||||
|
$event->post->flags()->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user