mirror of
https://github.com/flarum/framework.git
synced 2025-04-10 08:40:25 +08:00
Merge remote-tracking branch 'extensions_approval/REWRITE'
This commit is contained in:
commit
4b8573b726
19
extensions/approval/.editorconfig
Normal file
19
extensions/approval/.editorconfig
Normal file
@ -0,0 +1,19 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{diff,md}]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{php,xml,json}]
|
||||
indent_size = 4
|
18
extensions/approval/.gitattributes
vendored
Normal file
18
extensions/approval/.gitattributes
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.gitmodules export-ignore
|
||||
.github export-ignore
|
||||
.travis export-ignore
|
||||
.travis.yml export-ignore
|
||||
.editorconfig export-ignore
|
||||
.styleci.yml export-ignore
|
||||
|
||||
phpunit.xml export-ignore
|
||||
tests export-ignore
|
||||
|
||||
js/dist/* -diff
|
||||
js/dist/* linguist-generated
|
||||
js/dist-typings/* linguist-generated
|
||||
js/yarn.lock -diff
|
||||
|
||||
* text=auto eol=lf
|
15
extensions/approval/.github/workflows/backend.yml
vendored
Normal file
15
extensions/approval/.github/workflows/backend.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: Approval PHP
|
||||
|
||||
on: [workflow_dispatch, push, pull_request]
|
||||
|
||||
# The reusable workflow definitions will be moved to the `flarum/framework` repo soon.
|
||||
# This will break your current script.
|
||||
# When this happens, run `flarum-cli audit infra --fix` to update your infrastructure.
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: flarum/.github/.github/workflows/REUSABLE_backend.yml@main
|
||||
with:
|
||||
enable_backend_testing: false
|
||||
|
||||
backend_directory: .
|
21
extensions/approval/.github/workflows/frontend.yml
vendored
Normal file
21
extensions/approval/.github/workflows/frontend.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Approval JS
|
||||
|
||||
on: [workflow_dispatch, push, pull_request]
|
||||
|
||||
# The reusable workflow definitions will be moved to the `flarum/framework` repo soon.
|
||||
# This will break your current script.
|
||||
# When this happens, run `flarum-cli audit infra --fix` to update your infrastructure.
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: flarum/.github/.github/workflows/REUSABLE_frontend.yml@main
|
||||
with:
|
||||
enable_bundlewatch: false
|
||||
enable_prettier: true
|
||||
enable_typescript: false
|
||||
|
||||
frontend_directory: ./js
|
||||
main_git_branch: master
|
||||
|
||||
secrets:
|
||||
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
|
12
extensions/approval/.gitignore
vendored
Normal file
12
extensions/approval/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/vendor
|
||||
composer.lock
|
||||
composer.phar
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
tests/.phpunit.result.cache
|
||||
/tests/integration/tmp
|
||||
.vagrant
|
||||
.idea/*
|
||||
.vscode
|
||||
js/coverage-ts
|
14
extensions/approval/.styleci.yml
Normal file
14
extensions/approval/.styleci.yml
Normal file
@ -0,0 +1,14 @@
|
||||
preset: recommended
|
||||
|
||||
enabled:
|
||||
- logical_not_operators_with_successor_space
|
||||
|
||||
disabled:
|
||||
- align_double_arrow
|
||||
- blank_line_after_opening_tag
|
||||
- multiline_array_trailing_comma
|
||||
- new_with_braces
|
||||
- phpdoc_align
|
||||
- phpdoc_order
|
||||
- phpdoc_separation
|
||||
- phpdoc_types
|
49
extensions/approval/CHANGELOG.md
Normal file
49
extensions/approval/CHANGELOG.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.0](https://github.com/flarum/approval/compare/v1.1.0...v1.2.0)
|
||||
|
||||
No changes.
|
||||
|
||||
## [1.1.0](https://github.com/flarum/approval/compare/v1.0.0...v1.1.0)
|
||||
|
||||
No changes.
|
||||
|
||||
## [1.0.0](https://github.com/flarum/approval/compare/v0.1.0-beta.16...v1.0.0)
|
||||
|
||||
### Changed
|
||||
- Compatibility with Flarum v1.0.0.
|
||||
- Simplified TagPolicy.
|
||||
|
||||
### Fixed
|
||||
- Unpredictable behaviour existed with discussions marked `is_private` (https://github.com/flarum/approval/pull/26)
|
||||
|
||||
## [0.1.0-beta.16](https://github.com/flarum/approval/compare/v0.1.0-beta.15...v0.1.0-beta.16)
|
||||
|
||||
### Changed
|
||||
- Updated admin category from moderation to feature (https://github.com/flarum/approval/pull/24)
|
||||
- Moved locale files from translation pack to extension (https://github.com/flarum/approval/pull/22)
|
||||
|
||||
### Fixed
|
||||
- Comment and discussion count not updated after post approval (https://github.com/flarum/approval/pull/16)
|
||||
|
||||
## [0.1.0-beta.15](https://github.com/flarum/approval/compare/v0.1.0-beta.14...v0.1.0-beta.15)
|
||||
|
||||
### Changed
|
||||
- Updated composer.json and admin javascript for new admin area.
|
||||
- Updated extend.php with latest extenders.
|
||||
|
||||
## [0.1.0-beta.14](https://github.com/flarum/approval/compare/v0.1.0-beta.13...v0.1.0-beta.14)
|
||||
|
||||
### Changed
|
||||
- Updated mithril to version 2
|
||||
- Load language strings correctly on en-/disable
|
||||
- Updated JS dependencies
|
||||
|
||||
### Removed
|
||||
- Removed AssertPermissionTrait (#19)
|
||||
|
||||
## [0.1.0-beta.13](https://github.com/flarum/approval/compare/v0.1.0-beta.12...v0.1.0-beta.13)
|
||||
|
||||
### Changed
|
||||
- Updated JS dependencies
|
||||
- Stop using deprecated core events, use extenders instead
|
22
extensions/approval/LICENSE
Normal file
22
extensions/approval/LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
|
||||
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
61
extensions/approval/composer.json
Normal file
61
extensions/approval/composer.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "flarum/approval",
|
||||
"description": "Make discussions and posts require moderator approval.",
|
||||
"type": "flarum-extension",
|
||||
"keywords": [
|
||||
"moderation"
|
||||
],
|
||||
"license": "MIT",
|
||||
"support": {
|
||||
"issues": "https://github.com/flarum/core/issues",
|
||||
"source": "https://github.com/flarum/approval",
|
||||
"forum": "https://discuss.flarum.org"
|
||||
},
|
||||
"homepage": "https://flarum.org",
|
||||
"funding": [
|
||||
{
|
||||
"type": "website",
|
||||
"url": "https://flarum.org/donate/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.2",
|
||||
"flarum/flags": "^1.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Flarum\\Approval\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
},
|
||||
"flarum-extension": {
|
||||
"title": "Approval",
|
||||
"category": "feature",
|
||||
"icon": {
|
||||
"name": "fas fa-check",
|
||||
"backgroundColor": "#ABDC88",
|
||||
"color": "#3F8A32"
|
||||
}
|
||||
},
|
||||
"flarum-cli": {
|
||||
"modules": {
|
||||
"admin": true,
|
||||
"forum": true,
|
||||
"js": true,
|
||||
"jsCommon": false,
|
||||
"css": true,
|
||||
"gitConf": true,
|
||||
"githubActions": true,
|
||||
"prettier": true,
|
||||
"typescript": false,
|
||||
"bundlewatch": false,
|
||||
"backendTesting": false,
|
||||
"editorConfig": true,
|
||||
"styleci": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
71
extensions/approval/extend.php
Normal file
71
extensions/approval/extend.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Flarum\Api\Serializer\BasicDiscussionSerializer;
|
||||
use Flarum\Api\Serializer\PostSerializer;
|
||||
use Flarum\Approval\Access;
|
||||
use Flarum\Approval\Event\PostWasApproved;
|
||||
use Flarum\Approval\Listener;
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\Extend;
|
||||
use Flarum\Post\CommentPost;
|
||||
use Flarum\Post\Event\Saving;
|
||||
use Flarum\Post\Post;
|
||||
use Flarum\Tags\Tag;
|
||||
|
||||
return [
|
||||
(new Extend\Frontend('forum'))
|
||||
->js(__DIR__.'/js/dist/forum.js')
|
||||
->css(__DIR__.'/less/forum.less'),
|
||||
|
||||
(new Extend\Frontend('admin'))
|
||||
->js(__DIR__.'/js/dist/admin.js'),
|
||||
|
||||
// Discussions should be approved by default
|
||||
(new Extend\Model(Discussion::class))
|
||||
->default('is_approved', true),
|
||||
|
||||
// Posts should be approved by default
|
||||
(new Extend\Model(Post::class))
|
||||
->default('is_approved', true),
|
||||
|
||||
(new Extend\ApiSerializer(BasicDiscussionSerializer::class))
|
||||
->attribute('isApproved', function ($serializer, Discussion $discussion) {
|
||||
return (bool) $discussion->is_approved;
|
||||
}),
|
||||
|
||||
(new Extend\ApiSerializer(PostSerializer::class))
|
||||
->attribute('isApproved', function ($serializer, Post $post) {
|
||||
return (bool) $post->is_approved;
|
||||
})->attribute('canApprove', function (PostSerializer $serializer, Post $post) {
|
||||
return (bool) $serializer->getActor()->can('approvePosts', $post->discussion);
|
||||
}),
|
||||
|
||||
new Extend\Locales(__DIR__.'/locale'),
|
||||
|
||||
(new Extend\Event())
|
||||
->listen(Saving::class, [Listener\ApproveContent::class, 'approvePost'])
|
||||
->listen(Saving::class, [Listener\UnapproveNewContent::class, 'unapproveNewPosts'])
|
||||
->listen(PostWasApproved::class, [Listener\ApproveContent::class, 'approveDiscussion']),
|
||||
|
||||
(new Extend\Policy())
|
||||
->modelPolicy(Tag::class, Access\TagPolicy::class),
|
||||
|
||||
(new Extend\ModelVisibility(Post::class))
|
||||
->scope(Access\ScopePrivatePostVisibility::class, 'viewPrivate'),
|
||||
|
||||
(new Extend\ModelVisibility(Discussion::class))
|
||||
->scope(Access\ScopePrivateDiscussionVisibility::class, 'viewPrivate'),
|
||||
|
||||
(new Extend\ModelPrivate(Discussion::class))
|
||||
->checker([Listener\UnapproveNewContent::class, 'markUnapprovedContentAsPrivate']),
|
||||
|
||||
(new Extend\ModelPrivate(CommentPost::class))
|
||||
->checker([Listener\UnapproveNewContent::class, 'markUnapprovedContentAsPrivate']),
|
||||
];
|
9
extensions/approval/js/.gitignore
vendored
Normal file
9
extensions/approval/js/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
node_modules
|
1
extensions/approval/js/admin.js
Normal file
1
extensions/approval/js/admin.js
Normal file
@ -0,0 +1 @@
|
||||
export * from './src/admin';
|
2
extensions/approval/js/dist/admin.js
generated
vendored
Normal file
2
extensions/approval/js/dist/admin.js
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
(()=>{var r={n:s=>{var e=s&&s.__esModule?()=>s.default:()=>s;return r.d(e,{a:e}),e},d:(s,e)=>{for(var a in e)r.o(e,a)&&!r.o(s,a)&&Object.defineProperty(s,a,{enumerable:!0,get:e[a]})},o:(r,s)=>Object.prototype.hasOwnProperty.call(r,s),r:r=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})}},s={};(()=>{"use strict";r.r(s);const e=flarum.core.compat["common/extend"],a=flarum.core.compat["admin/app"];var o=r.n(a);o().initializers.add("flarum-approval",(function(){(0,e.extend)(o(),"getRequiredPermissions",(function(r,s){"discussion.startWithoutApproval"===s&&r.push("startDiscussion"),"discussion.replyWithoutApproval"===s&&r.push("discussion.reply")})),o().extensionData.for("flarum-approval").registerPermission({icon:"fas fa-check",label:o().translator.trans("flarum-approval.admin.permissions.start_discussions_without_approval_label"),permission:"discussion.startWithoutApproval"},"start",95).registerPermission({icon:"fas fa-check",label:o().translator.trans("flarum-approval.admin.permissions.reply_without_approval_label"),permission:"discussion.replyWithoutApproval"},"reply",95).registerPermission({icon:"fas fa-check",label:o().translator.trans("flarum-approval.admin.permissions.approve_posts_label"),permission:"discussion.approvePosts"},"moderate",65)}))})(),module.exports=s})();
|
||||
//# sourceMappingURL=admin.js.map
|
1
extensions/approval/js/dist/admin.js.map
generated
vendored
Normal file
1
extensions/approval/js/dist/admin.js.map
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,GCLRF,EAAwB,CAACM,EAASC,KACjC,IAAI,IAAIC,KAAOD,EACXP,EAAoBS,EAAEF,EAAYC,KAASR,EAAoBS,EAAEH,EAASE,IAC5EE,OAAOC,eAAeL,EAASE,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,MCJ3ER,EAAwB,CAACc,EAAKC,IAAUL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,GCClFf,EAAyBM,IACH,oBAAXa,QAA0BA,OAAOC,aAC1CV,OAAOC,eAAeL,EAASa,OAAOC,YAAa,CAAEC,MAAO,WAE7DX,OAAOC,eAAeL,EAAS,aAAc,CAAEe,OAAO,M,+BCLvD,MAAM,EAA+BC,OAAOC,KAAKC,OAAO,iBCAlD,EAA+BF,OAAOC,KAAKC,OAAO,a,aCGxDC,IAAAA,aAAAA,IAAqB,mBAAmB,YACtCC,EAAAA,EAAAA,QAAOD,IAAK,0BAA0B,SAAUE,EAAUC,GACrC,oCAAfA,GACFD,EAASE,KAAK,mBAEG,oCAAfD,GACFD,EAASE,KAAK,uBAIlBJ,IAAAA,cAAAA,IACO,mBACJK,mBACC,CACEC,KAAM,eACNC,MAAOP,IAAAA,WAAAA,MAAqB,8EAC5BG,WAAY,mCAEd,QACA,IAEDE,mBACC,CACEC,KAAM,eACNC,MAAOP,IAAAA,WAAAA,MAAqB,kEAC5BG,WAAY,mCAEd,QACA,IAEDE,mBACC,CACEC,KAAM,eACNC,MAAOP,IAAAA,WAAAA,MAAqB,yDAC5BG,WAAY,2BAEd,WACA,Q","sources":["webpack://@flarum/approval/webpack/bootstrap","webpack://@flarum/approval/webpack/runtime/compat get default export","webpack://@flarum/approval/webpack/runtime/define property getters","webpack://@flarum/approval/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/approval/webpack/runtime/make namespace object","webpack://@flarum/approval/external root \"flarum.core.compat['common/extend']\"","webpack://@flarum/approval/external root \"flarum.core.compat['admin/app']\"","webpack://@flarum/approval/./src/admin/index.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.core.compat['common/extend'];","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.core.compat['admin/app'];","import { extend } from 'flarum/common/extend';\nimport app from 'flarum/admin/app';\n\napp.initializers.add('flarum-approval', () => {\n extend(app, 'getRequiredPermissions', function (required, permission) {\n if (permission === 'discussion.startWithoutApproval') {\n required.push('startDiscussion');\n }\n if (permission === 'discussion.replyWithoutApproval') {\n required.push('discussion.reply');\n }\n });\n\n app.extensionData\n .for('flarum-approval')\n .registerPermission(\n {\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),\n permission: 'discussion.startWithoutApproval',\n },\n 'start',\n 95\n )\n .registerPermission(\n {\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),\n permission: 'discussion.replyWithoutApproval',\n },\n 'reply',\n 95\n )\n .registerPermission(\n {\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),\n permission: 'discussion.approvePosts',\n },\n 'moderate',\n 65\n );\n});\n"],"names":["__webpack_require__","module","getter","__esModule","d","a","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","flarum","core","compat","app","extend","required","permission","push","registerPermission","icon","label"],"sourceRoot":""}
|
2
extensions/approval/js/dist/forum.js
generated
vendored
Normal file
2
extensions/approval/js/dist/forum.js
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
(()=>{var o={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return o.d(r,{a:r}),r},d:(t,r)=>{for(var e in r)o.o(r,e)&&!o.o(t,e)&&Object.defineProperty(t,e,{enumerable:!0,get:r[e]})},o:(o,t)=>Object.prototype.hasOwnProperty.call(o,t),r:o=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})}},t={};(()=>{"use strict";o.r(t);const r=flarum.core.compat["common/extend"],e=flarum.core.compat["forum/app"];var a=o.n(e);const p=flarum.core.compat["common/models/Discussion"];var n=o.n(p);const s=flarum.core.compat["common/models/Post"];var i=o.n(s);const c=flarum.core.compat["common/components/Badge"];var u=o.n(c);const l=flarum.core.compat["forum/components/DiscussionListItem"];var d=o.n(l);const v=flarum.core.compat["forum/components/Post"];var f=o.n(v);const A=flarum.core.compat["forum/components/CommentPost"];var y=o.n(A);const b=flarum.core.compat["common/components/Button"];var g=o.n(b);const h=flarum.core.compat["forum/utils/PostControls"];var _=o.n(h);a().initializers.add("flarum-approval",(function(){n().prototype.isApproved=n().attribute("isApproved"),(0,r.extend)(n().prototype,"badges",(function(o){this.isApproved()||o.has("hidden")||o.add("awaitingApproval",m(u(),{type:"awaitingApproval",icon:"fas fa-gavel",label:a().translator.trans("flarum-approval.forum.badge.awaiting_approval_tooltip")}))})),i().prototype.isApproved=i().attribute("isApproved"),i().prototype.canApprove=i().attribute("canApprove"),(0,r.extend)(d().prototype,"elementAttrs",(function(o){this.attrs.discussion.isApproved()||(o.className+=" DiscussionListItem--unapproved")})),(0,r.extend)(f().prototype,"elementAttrs",(function(o){this.attrs.post.isApproved()||(o.className+=" Post--unapproved")})),(0,r.extend)(y().prototype,"headerItems",(function(o){this.attrs.post.isApproved()||this.attrs.post.isHidden()||o.add("unapproved",a().translator.trans("flarum-approval.forum.post.awaiting_approval_text"))})),(0,r.override)(f().prototype,"flagReason",(function(o,t){return"approval"===t.type()?a().translator.trans("flarum-approval.forum.post.awaiting_approval_text"):o(t)})),(0,r.extend)(_(),"destructiveControls",(function(o,t){!t.isApproved()&&t.canApprove()&&o.add("approve",m(g(),{icon:"fas fa-check",onclick:_().approveAction.bind(t)},a().translator.trans("flarum-approval.forum.post_controls.approve_button")),10)})),_().approveAction=function(){this.save({isApproved:!0}),1===this.number()&&this.discussion().pushAttributes({isApproved:!0})}}),-10)})(),module.exports=t})();
|
||||
//# sourceMappingURL=forum.js.map
|
1
extensions/approval/js/dist/forum.js.map
generated
vendored
Normal file
1
extensions/approval/js/dist/forum.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
extensions/approval/js/forum.js
Normal file
1
extensions/approval/js/forum.js
Normal file
@ -0,0 +1 @@
|
||||
export * from './src/forum';
|
19
extensions/approval/js/package.json
Normal file
19
extensions/approval/js/package.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@flarum/approval",
|
||||
"prettier": "@flarum/prettier-config",
|
||||
"devDependencies": {
|
||||
"prettier": "^2.5.1",
|
||||
"flarum-webpack-config": "^2.0.0",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"@flarum/prettier-config": "^1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack --mode development --watch",
|
||||
"build": "webpack --mode production",
|
||||
"format": "prettier --write src",
|
||||
"format-check": "prettier --check src",
|
||||
"analyze": "cross-env ANALYZER=true yarn build"
|
||||
}
|
||||
}
|
43
extensions/approval/js/src/admin/index.js
Normal file
43
extensions/approval/js/src/admin/index.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { extend } from 'flarum/common/extend';
|
||||
import app from 'flarum/admin/app';
|
||||
|
||||
app.initializers.add('flarum-approval', () => {
|
||||
extend(app, 'getRequiredPermissions', function (required, permission) {
|
||||
if (permission === 'discussion.startWithoutApproval') {
|
||||
required.push('startDiscussion');
|
||||
}
|
||||
if (permission === 'discussion.replyWithoutApproval') {
|
||||
required.push('discussion.reply');
|
||||
}
|
||||
});
|
||||
|
||||
app.extensionData
|
||||
.for('flarum-approval')
|
||||
.registerPermission(
|
||||
{
|
||||
icon: 'fas fa-check',
|
||||
label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),
|
||||
permission: 'discussion.startWithoutApproval',
|
||||
},
|
||||
'start',
|
||||
95
|
||||
)
|
||||
.registerPermission(
|
||||
{
|
||||
icon: 'fas fa-check',
|
||||
label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),
|
||||
permission: 'discussion.replyWithoutApproval',
|
||||
},
|
||||
'reply',
|
||||
95
|
||||
)
|
||||
.registerPermission(
|
||||
{
|
||||
icon: 'fas fa-check',
|
||||
label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),
|
||||
permission: 'discussion.approvePosts',
|
||||
},
|
||||
'moderate',
|
||||
65
|
||||
);
|
||||
});
|
76
extensions/approval/js/src/forum/index.js
Normal file
76
extensions/approval/js/src/forum/index.js
Normal file
@ -0,0 +1,76 @@
|
||||
import { extend, override } from 'flarum/common/extend';
|
||||
import app from 'flarum/forum/app';
|
||||
import Discussion from 'flarum/common/models/Discussion';
|
||||
import Post from 'flarum/common/models/Post';
|
||||
import Badge from 'flarum/common/components/Badge';
|
||||
import DiscussionListItem from 'flarum/forum/components/DiscussionListItem';
|
||||
import PostComponent from 'flarum/forum/components/Post';
|
||||
import CommentPost from 'flarum/forum/components/CommentPost';
|
||||
import Button from 'flarum/common/components/Button';
|
||||
import PostControls from 'flarum/forum/utils/PostControls';
|
||||
|
||||
app.initializers.add(
|
||||
'flarum-approval',
|
||||
() => {
|
||||
Discussion.prototype.isApproved = Discussion.attribute('isApproved');
|
||||
|
||||
extend(Discussion.prototype, 'badges', function (items) {
|
||||
if (!this.isApproved() && !items.has('hidden')) {
|
||||
items.add(
|
||||
'awaitingApproval',
|
||||
<Badge type="awaitingApproval" icon="fas fa-gavel" label={app.translator.trans('flarum-approval.forum.badge.awaiting_approval_tooltip')} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Post.prototype.isApproved = Post.attribute('isApproved');
|
||||
Post.prototype.canApprove = Post.attribute('canApprove');
|
||||
|
||||
extend(DiscussionListItem.prototype, 'elementAttrs', function (attrs) {
|
||||
if (!this.attrs.discussion.isApproved()) {
|
||||
attrs.className += ' DiscussionListItem--unapproved';
|
||||
}
|
||||
});
|
||||
|
||||
extend(PostComponent.prototype, 'elementAttrs', function (attrs) {
|
||||
if (!this.attrs.post.isApproved()) {
|
||||
attrs.className += ' Post--unapproved';
|
||||
}
|
||||
});
|
||||
|
||||
extend(CommentPost.prototype, 'headerItems', function (items) {
|
||||
if (!this.attrs.post.isApproved() && !this.attrs.post.isHidden()) {
|
||||
items.add('unapproved', app.translator.trans('flarum-approval.forum.post.awaiting_approval_text'));
|
||||
}
|
||||
});
|
||||
|
||||
override(PostComponent.prototype, 'flagReason', function (original, flag) {
|
||||
if (flag.type() === 'approval') {
|
||||
return app.translator.trans('flarum-approval.forum.post.awaiting_approval_text');
|
||||
}
|
||||
|
||||
return original(flag);
|
||||
});
|
||||
|
||||
extend(PostControls, 'destructiveControls', function (items, post) {
|
||||
if (!post.isApproved() && post.canApprove()) {
|
||||
items.add(
|
||||
'approve',
|
||||
<Button icon="fas fa-check" onclick={PostControls.approveAction.bind(post)}>
|
||||
{app.translator.trans('flarum-approval.forum.post_controls.approve_button')}
|
||||
</Button>,
|
||||
10
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
PostControls.approveAction = function () {
|
||||
this.save({ isApproved: true });
|
||||
|
||||
if (this.number() === 1) {
|
||||
this.discussion().pushAttributes({ isApproved: true });
|
||||
}
|
||||
};
|
||||
},
|
||||
-10
|
||||
); // set initializer priority to run after reports
|
1
extensions/approval/js/webpack.config.js
Normal file
1
extensions/approval/js/webpack.config.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require('flarum-webpack-config')();
|
2284
extensions/approval/js/yarn.lock
Normal file
2284
extensions/approval/js/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
0
extensions/approval/less/admin.less
Normal file
0
extensions/approval/less/admin.less
Normal file
11
extensions/approval/less/forum.less
Normal file
11
extensions/approval/less/forum.less
Normal file
@ -0,0 +1,11 @@
|
||||
.Post--unapproved {
|
||||
.Post-header,
|
||||
.Post-body,
|
||||
.EventPost-icon,
|
||||
.EventPost-info {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
.DiscussionListItem--unapproved {
|
||||
.DiscussionListItem--hidden();
|
||||
}
|
37
extensions/approval/locale/en.yml
Normal file
37
extensions/approval/locale/en.yml
Normal file
@ -0,0 +1,37 @@
|
||||
flarum-approval:
|
||||
|
||||
##
|
||||
# UNIQUE KEYS - The following keys are used in only one location each.
|
||||
##
|
||||
|
||||
# Translations in this namespace are used by the admin interface.
|
||||
admin:
|
||||
|
||||
# These translations are used in the Permissions page of the admin interface.
|
||||
permissions:
|
||||
approve_posts_label: Approve posts
|
||||
reply_without_approval_label: Reply to discussions without approval
|
||||
start_discussions_without_approval_label: Start discussions without approval
|
||||
|
||||
# Translations in this namespace are used by the forum user interface.
|
||||
forum:
|
||||
|
||||
# These translations are displayed as tooltips for discussion badges.
|
||||
badge:
|
||||
awaiting_approval_tooltip: => flarum-approval.ref.awaiting_approval
|
||||
|
||||
# These translations are displayed in the post header.
|
||||
post:
|
||||
awaiting_approval_text: => flarum-approval.ref.awaiting_approval
|
||||
|
||||
# These translations are used by the post control buttons.
|
||||
post_controls:
|
||||
approve_button: Approve
|
||||
|
||||
##
|
||||
# REUSED TRANSLATIONS - These keys should not be used directly in code!
|
||||
##
|
||||
|
||||
# Translations in this namespace are referenced by two or more unique keys.
|
||||
ref:
|
||||
awaiting_approval: Awaiting approval
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Flarum\Database\Migration;
|
||||
|
||||
return Migration::addColumns('discussions', [
|
||||
'is_approved' => ['boolean', 'default' => 1]
|
||||
]);
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Flarum\Database\Migration;
|
||||
|
||||
return Migration::addColumns('posts', [
|
||||
'is_approved' => ['boolean', 'default' => 1]
|
||||
]);
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Flarum\Database\Migration;
|
||||
use Flarum\Group\Group;
|
||||
|
||||
return Migration::addPermissions([
|
||||
'discussion.startWithoutApproval' => Group::MEMBER_ID,
|
||||
'discussion.replyWithoutApproval' => Group::MEMBER_ID,
|
||||
'discussion.approvePosts' => Group::MODERATOR_ID
|
||||
]);
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Approval\Access;
|
||||
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class ScopePrivateDiscussionVisibility
|
||||
{
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @param User $actor
|
||||
*/
|
||||
public function __invoke(User $actor, Builder $query)
|
||||
{
|
||||
// All statements need to be wrapped in an orWhere, since we're adding a
|
||||
// subset of private discussions that should be visible, not restricting the visible
|
||||
// set.
|
||||
$query->orWhere(function ($query) use ($actor) {
|
||||
// Show empty/private discussions if they require approval and they are
|
||||
// authored by the current user, or the current user has permission to
|
||||
// approve posts.
|
||||
$query->where('discussions.is_approved', 0);
|
||||
|
||||
if (! $actor->hasPermission('discussion.approvePosts')) {
|
||||
$query->where(function (Builder $query) use ($actor) {
|
||||
$query->where('discussions.user_id', $actor->id)
|
||||
->orWhere(function ($query) use ($actor) {
|
||||
$query->whereVisibleTo($actor, 'approvePosts');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Approval\Access;
|
||||
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class ScopePrivatePostVisibility
|
||||
{
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @param User $actor
|
||||
*/
|
||||
public function __invoke(User $actor, Builder $query)
|
||||
{
|
||||
// All statements need to be wrapped in an orWhere, since we're adding a
|
||||
// subset of private posts that should be visible, not restricting the visible
|
||||
// set.
|
||||
$query->orWhere(function ($query) use ($actor) {
|
||||
// Show private posts if they require approval and they are
|
||||
// authored by the current user, or the current user has permission to
|
||||
// approve posts.
|
||||
$query->where('posts.is_approved', 0);
|
||||
|
||||
if (! $actor->hasPermission('discussion.approvePosts')) {
|
||||
$query->where(function (Builder $query) use ($actor) {
|
||||
$query->where('posts.user_id', $actor->id)
|
||||
->orWhereExists($this->discussionWhereCanApprovePosts($actor));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function discussionWhereCanApprovePosts(User $actor)
|
||||
{
|
||||
return function ($query) use ($actor) {
|
||||
$query->selectRaw('1')
|
||||
->from('discussions')
|
||||
->whereColumn('discussions.id', 'posts.discussion_id')
|
||||
->where(function ($query) use ($actor) {
|
||||
Discussion::query()->setQuery($query)->whereVisibleTo($actor, 'approvePosts');
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
25
extensions/approval/src/Access/TagPolicy.php
Executable file
25
extensions/approval/src/Access/TagPolicy.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Approval\Access;
|
||||
|
||||
use Flarum\Tags\Tag;
|
||||
use Flarum\User\Access\AbstractPolicy;
|
||||
use Flarum\User\User;
|
||||
|
||||
class TagPolicy extends AbstractPolicy
|
||||
{
|
||||
/**
|
||||
* @return bool|null
|
||||
*/
|
||||
public function addToDiscussion(User $actor, Tag $tag)
|
||||
{
|
||||
return $actor->can('discussion.startWithoutApproval', $tag);
|
||||
}
|
||||
}
|
38
extensions/approval/src/Event/PostWasApproved.php
Normal file
38
extensions/approval/src/Event/PostWasApproved.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Approval\Event;
|
||||
|
||||
use Flarum\Post\Post;
|
||||
use Flarum\User\User;
|
||||
|
||||
class PostWasApproved
|
||||
{
|
||||
/**
|
||||
* The post that was approved.
|
||||
*
|
||||
* @var Post
|
||||
*/
|
||||
public $post;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
public $actor;
|
||||
|
||||
/**
|
||||
* @param Post $post
|
||||
* @param User $actor
|
||||
*/
|
||||
public function __construct(Post $post, User $actor)
|
||||
{
|
||||
$this->post = $post;
|
||||
$this->actor = $actor;
|
||||
}
|
||||
}
|
65
extensions/approval/src/Listener/ApproveContent.php
Executable file
65
extensions/approval/src/Listener/ApproveContent.php
Executable file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Approval\Listener;
|
||||
|
||||
use Flarum\Approval\Event\PostWasApproved;
|
||||
use Flarum\Post\Event\Saving;
|
||||
|
||||
class ApproveContent
|
||||
{
|
||||
/**
|
||||
* @param Saving $event
|
||||
*/
|
||||
public static function approvePost(Saving $event)
|
||||
{
|
||||
$attributes = $event->data['attributes'];
|
||||
$post = $event->post;
|
||||
|
||||
if (isset($attributes['isApproved'])) {
|
||||
$event->actor->assertCan('approve', $post);
|
||||
|
||||
$isApproved = (bool) $attributes['isApproved'];
|
||||
} elseif (! empty($attributes['isHidden']) && $event->actor->can('approve', $post)) {
|
||||
$isApproved = true;
|
||||
}
|
||||
|
||||
if (! empty($isApproved)) {
|
||||
$post->is_approved = true;
|
||||
|
||||
$post->raise(new PostWasApproved($post, $event->actor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PostWasApproved $event
|
||||
*/
|
||||
public static function approveDiscussion(PostWasApproved $event)
|
||||
{
|
||||
$post = $event->post;
|
||||
$discussion = $post->discussion;
|
||||
$user = $discussion->user;
|
||||
|
||||
$discussion->refreshCommentCount();
|
||||
$discussion->refreshLastPost();
|
||||
|
||||
if ($post->number == 1) {
|
||||
$discussion->is_approved = true;
|
||||
|
||||
$discussion->afterSave(function () use ($user) {
|
||||
$user->refreshDiscussionCount();
|
||||
});
|
||||
}
|
||||
|
||||
$discussion->save();
|
||||
|
||||
$user->refreshCommentCount();
|
||||
$user->save();
|
||||
}
|
||||
}
|
66
extensions/approval/src/Listener/UnapproveNewContent.php
Normal file
66
extensions/approval/src/Listener/UnapproveNewContent.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Approval\Listener;
|
||||
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\Flags\Flag;
|
||||
use Flarum\Post\CommentPost;
|
||||
use Flarum\Post\Event\Saving;
|
||||
|
||||
class UnapproveNewContent
|
||||
{
|
||||
/**
|
||||
* @param Saving $event
|
||||
*/
|
||||
public static function unapproveNewPosts(Saving $event)
|
||||
{
|
||||
$post = $event->post;
|
||||
|
||||
if (! $post->exists) {
|
||||
$ability = $post->discussion->post_number_index == 0 ? 'startWithoutApproval' : 'replyWithoutApproval';
|
||||
|
||||
if ($event->actor->can($ability, $post->discussion)) {
|
||||
if ($post->is_approved === null) {
|
||||
$post->is_approved = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$post->is_approved = false;
|
||||
|
||||
$post->afterSave(function ($post) {
|
||||
if ($post->number == 1) {
|
||||
$post->discussion->is_approved = false;
|
||||
$post->discussion->save();
|
||||
}
|
||||
|
||||
$flag = new Flag;
|
||||
|
||||
$flag->post_id = $post->id;
|
||||
$flag->type = 'approval';
|
||||
$flag->created_at = time();
|
||||
|
||||
$flag->save();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Discussion|CommentPost $instance
|
||||
* @return bool|null
|
||||
*/
|
||||
public static function markUnapprovedContentAsPrivate($instance)
|
||||
{
|
||||
if (! $instance->is_approved) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user