mirror of
https://github.com/flarum/core.git
synced 2025-08-14 04:14:06 +02:00
Compare commits
25 Commits
sm/qa-flag
...
dk/no-one-
Author | SHA1 | Date | |
---|---|---|---|
|
70135459ce | ||
|
3c82a887a8 | ||
|
7dcbbf29ab | ||
|
bddc9d96f2 | ||
|
d684248492 | ||
|
85b63681ae | ||
|
8372363cc2 | ||
|
a6a067ad48 | ||
|
241eba4d0c | ||
|
a6b12826c3 | ||
|
dd868ab44e | ||
|
5f3e0d6a09 | ||
|
661b9d7d9a | ||
|
b7498d6cb1 | ||
|
e7c55532a0 | ||
|
cce6b74fce | ||
|
da651c722b | ||
|
abc9670659 | ||
|
b66fe5dd5f | ||
|
7d79895ae0 | ||
|
3ab4529232 | ||
|
360a2ba1d8 | ||
|
eaa4063fef | ||
|
72d277bd45 | ||
|
28e3ccfde6 |
2
.github/workflows/REUSABLE_frontend.yml
vendored
2
.github/workflows/REUSABLE_frontend.yml
vendored
@@ -118,7 +118,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.0'
|
||||
php-version: '8.2'
|
||||
extensions: curl, dom, gd, json, mbstring, openssl, pdo_mysql, tokenizer, zip
|
||||
tools: composer:v2
|
||||
|
||||
|
67
CHANGELOG.md
67
CHANGELOG.md
@@ -1,6 +1,71 @@
|
||||
# Changelog
|
||||
|
||||
# [v1.6.3](https://github.com/flarum/framework/compare/v1.6.2...v1.6.3)
|
||||
## [v1.7.1](https://github.com/flarum/framework/compare/v1.7.0...v1.7.1)
|
||||
### Fixed
|
||||
- (tags) composer tag selection modal using wrong primary max & min numbers (abc9670659426b765274376945b818b70d84848c)
|
||||
- missing parameter names in token title translation. (#3752)
|
||||
- hardcoded language strings in StatusWidget (#3754)
|
||||
- hide developer tokens section in if there is nothing to display or create (#3753)
|
||||
- improve sessions user UI on mobile (dd868ab44e11e892d020e3b9412553c6a789e68d)
|
||||
|
||||
## [v1.7.0](https://github.com/flarum/framework/compare/v1.6.3...v1.7.0)
|
||||
### Added
|
||||
- (actions) allow running JS tests in GH actions [#3730]
|
||||
- (core) PHP 8.2 Support [#3709]
|
||||
- (jest) create jest config package for unit testing [#3678]
|
||||
- (jest) mithril component testing [#3679]
|
||||
- (phpstan) foundation for usage in extensions [#3666]
|
||||
- (seo) Do not use h3 header for poster author in posts stream [#3732]
|
||||
- (seo) Use h2 header for discussions on discussions list [#3731]
|
||||
- (seo) shift h1 tag from logo to discussion title [#3724]
|
||||
- (tags) admin tag selection component (reusable tag selection modal) [#3686]
|
||||
- Admin User Search [#3712]
|
||||
- access tokens user management UI [#3587]
|
||||
- add display name column to admin users list [#3740]
|
||||
- allow push additional items to the end of the poststream [#3691]
|
||||
- allow using utf8 characters in tag slugs [#3588]
|
||||
- expose queue driver, schedule status [#3593]
|
||||
- expose {time} to eventPost data, fix renamed tooltip [#3698]
|
||||
- frontend `Model` extender [#3646]
|
||||
- global logout to clear all sessions, access tokens, email tokens and password tokens [#3605]
|
||||
- improved page navigation for users list [#3741]
|
||||
- introduce frontend extenders [#3645]
|
||||
### Fixed
|
||||
- (mentions) correctly convert a 3 char. hex color to a 6 char. one [#3694]
|
||||
- (mentions) post reply mention missing notification on approval [#3738]
|
||||
- (phpstan) adapt phpstan package for extension use [#3727]
|
||||
- (tags) clickable tag labels have underline [#3737]
|
||||
- (tags) tag text color contrast [#3653]
|
||||
- 3 digit hex color value in color input not supported [#3706]
|
||||
- column `id` can be ambiguous in group filter with extensions [#3696]
|
||||
- disallow certain dangerous LESS features ([1761660](1761660c98ea5a3e9665fb8e6041d1f2ee62a444))
|
||||
- evaluated page title content [#3684]
|
||||
- invalid translation key for scheduler dashboard [#3736]
|
||||
- load actor.groups on showforumcontroller [#3716]
|
||||
- make go-to-page input number-like [#3743]
|
||||
- normal logout affects all sessions [#3571]
|
||||
- permissions table on mobile is unusable [#3722]
|
||||
- post dropdown opens all dropdowns in `.Post-actions` [#3675]
|
||||
- typo in Formatter extender docblock [#3676]
|
||||
- undefined showing in dropdown active title [#3700]
|
||||
### Changed
|
||||
- (phpstan) enable phpstan in bundled extensions [#3667]
|
||||
- Add missing states exports to `compat.ts` [#3683]
|
||||
- Indicate cross-origin request in generic error message [#3669]
|
||||
- Merge branch 'release/v1.6.2' ([e0b9dcf](e0b9dcfbcd7db175368dbc98255f9223da8df17d))
|
||||
- The negate field doesn't get used, which means you cant exclude tags [#3713]
|
||||
- Update forum.less to fix the misalignment of the choose tags button [#3726]
|
||||
- `yarn audit-fix` ([8ddb0fe](8ddb0feb097dad06c5763107d7a7f7b5a55562c4))
|
||||
- `yarn` ([ee1e04c](ee1e04cdc26b3e63057a58899f32f482901a95fd))
|
||||
- convert `Dropdown` components to TS [#3608]
|
||||
- fix php 8.1 on preg_match 2nd argument being null, which also optimizes slightly ([d7b9a03](d7b9a03f31847c39631ba495df8f515509774610))
|
||||
- improve group mentions parsing [#3723]
|
||||
- prepare `@flarum/jest-config` for release ([748cca6](748cca6d12f8b1744a6017c09395725bdbb4a118))
|
||||
- remove use of deprecated phpunit assertion ([3af0481](3af0481f304277f5380fac9c9b169a7fa651f53b))
|
||||
- set flarum version to 1.7.0 for dev ([2517bc0](2517bc0f70b0f0e3d3ea3f6ae06af8604d89b25d))
|
||||
- update JS dependencies [#3695]
|
||||
|
||||
## [v1.6.3](https://github.com/flarum/framework/compare/v1.6.2...v1.6.3)
|
||||
### Fixed
|
||||
* Post mentions can be used to read any post on the forum without access control (ab1c868b978e8b0d09a5d682c54665dae17d0985).
|
||||
* Notifications can leak restricted content (d0a2b95dca57d3dae9a0d77b610b1cb1d0b1766a).
|
||||
|
@@ -19,8 +19,8 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6",
|
||||
"flarum/approval": "^1.2"
|
||||
"flarum/core": "^1.7",
|
||||
"flarum/approval": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/akismet/js/dist/forum.js
generated
vendored
2
extensions/akismet/js/dist/forum.js
generated
vendored
@@ -1,2 +1,2 @@
|
||||
(()=>{var t={n:e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return t.d(o,{a:o}),o},d:(e,o)=>{for(var r in o)t.o(o,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:o[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};(()=>{"use strict";t.r(e);const o=flarum.core.compat["common/extend"],r=flarum.core.compat["forum/app"];var a=t.n(r);const n=flarum.core.compat["forum/utils/PostControls"];var m=t.n(n);const s=flarum.core.compat["forum/components/CommentPost"];var l=t.n(s);a().initializers.add("flarum-akismet",(function(){(0,o.extend)(m(),"destructiveControls",(function(t,e){if(t.has("approve")){var o=e.flags();if(o&&o.some((function(t){return"akismet"===(null==t?void 0:t.type())}))){var r=t.get("approve");r&&"object"==typeof r&&"children"in r&&(r.children=a().translator.trans("flarum-akismet.forum.post.not_spam_button"))}}})),(0,o.override)(l().prototype,"flagReason",(function(t,e){return"akismet"===e.type()?a().translator.trans("flarum-akismet.forum.post.akismet_flagged_text"):t(e)}))}))})(),module.exports=e})();
|
||||
(()=>{var t={n:e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return t.d(o,{a:o}),o},d:(e,o)=>{for(var r in o)t.o(o,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:o[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};(()=>{"use strict";t.r(e);const o=flarum.core.compat["common/extend"],r=flarum.core.compat["forum/app"];var a=t.n(r);const n=flarum.core.compat["forum/utils/PostControls"];var s=t.n(n);const l=flarum.core.compat["forum/components/Post"];var u=t.n(l);a().initializers.add("flarum-akismet",(function(){(0,o.extend)(s(),"destructiveControls",(function(t,e){if(t.has("approve")){var o=e.flags();if(o&&o.some((function(t){return"akismet"===(null==t?void 0:t.type())}))){var r=t.get("approve");r&&"object"==typeof r&&"children"in r&&(r.children=a().translator.trans("flarum-akismet.forum.post.not_spam_button"))}}})),(0,o.override)(u().prototype,"flagReason",(function(t,e){return"akismet"===e.type()?a().translator.trans("flarum-akismet.forum.post.akismet_flagged_text"):t(e)}))}))})(),module.exports=e})();
|
||||
//# sourceMappingURL=forum.js.map
|
2
extensions/akismet/js/dist/forum.js.map
generated
vendored
2
extensions/akismet/js/dist/forum.js.map
generated
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"forum.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,CAAM,ECLdF,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,IAE1E,ECNDR,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,GAAO,G,+BCL9D,MAAM,EAA+BC,OAAOC,KAAKC,OAAO,iBCAlD,EAA+BF,OAAOC,KAAKC,OAAO,a,aCAxD,MAAM,EAA+BF,OAAOC,KAAKC,OAAO,4B,aCAxD,MAAM,EAA+BF,OAAOC,KAAKC,OAAO,gC,aCSxDC,IAAAA,aAAAA,IAAqB,kBAAkB,YACrCC,EAAAA,EAAAA,QAAOC,IAAc,uBAAuB,SAAUC,EAAmCC,GACvF,GAAID,EAAME,IAAI,WAAY,CACxB,IAAMC,EAAQF,EAAKE,QAEnB,GAAIA,GAASA,EAAMC,MAAK,SAACC,GAAI,MAAsB,aAAb,MAAJA,OAAI,EAAJA,EAAMC,OAAoB,IAAG,CAC7D,IAAMC,EAAcP,EAAMf,IAAI,WAC1BsB,GAAsC,iBAAhBA,GAA4B,aAAcA,IAClEA,EAAYC,SAAWX,IAAAA,WAAAA,MAAqB,6CAEhD,CACF,CACF,KAEAY,EAAAA,EAAAA,UAASC,IAAAA,UAAuB,cAAc,SAAUC,EAAUN,GAChE,MAAoB,YAAhBA,EAAKC,OACAT,IAAAA,WAAAA,MAAqB,kDAGvBc,EAASN,EAClB,GACF,G","sources":["webpack://@flarum/akismet/webpack/bootstrap","webpack://@flarum/akismet/webpack/runtime/compat get default export","webpack://@flarum/akismet/webpack/runtime/define property getters","webpack://@flarum/akismet/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/akismet/webpack/runtime/make namespace object","webpack://@flarum/akismet/external root \"flarum.core.compat['common/extend']\"","webpack://@flarum/akismet/external root \"flarum.core.compat['forum/app']\"","webpack://@flarum/akismet/external root \"flarum.core.compat['forum/utils/PostControls']\"","webpack://@flarum/akismet/external root \"flarum.core.compat['forum/components/CommentPost']\"","webpack://@flarum/akismet/./src/forum/index.ts"],"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['forum/app'];","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.core.compat['forum/utils/PostControls'];","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.core.compat['forum/components/CommentPost'];","import { extend, override } from 'flarum/common/extend';\nimport app from 'flarum/forum/app';\nimport type Post from 'flarum/common/models/Post';\nimport type ItemList from 'flarum/common/utils/ItemList';\n\nimport PostControls from 'flarum/forum/utils/PostControls';\nimport CommentPost from 'flarum/forum/components/CommentPost';\nimport type Mithril from 'mithril';\n\napp.initializers.add('flarum-akismet', () => {\n extend(PostControls, 'destructiveControls', function (items: ItemList<Mithril.Children>, post: Post) {\n if (items.has('approve')) {\n const flags = post.flags();\n\n if (flags && flags.some((flag) => flag?.type() === 'akismet')) {\n const approveItem = items.get('approve');\n if (approveItem && typeof approveItem === 'object' && 'children' in approveItem) {\n approveItem.children = app.translator.trans('flarum-akismet.forum.post.not_spam_button');\n }\n }\n }\n });\n\n override(CommentPost.prototype, 'flagReason', function (original, flag) {\n if (flag.type() === 'akismet') {\n return app.translator.trans('flarum-akismet.forum.post.akismet_flagged_text');\n }\n\n return original(flag);\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","PostControls","items","post","has","flags","some","flag","type","approveItem","children","override","CommentPost","original"],"sourceRoot":""}
|
||||
{"version":3,"file":"forum.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,CAAM,ECLdF,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,IAE1E,ECNDR,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,GAAO,G,+BCL9D,MAAM,EAA+BC,OAAOC,KAAKC,OAAO,iBCAlD,EAA+BF,OAAOC,KAAKC,OAAO,a,aCAxD,MAAM,EAA+BF,OAAOC,KAAKC,OAAO,4B,aCAxD,MAAM,EAA+BF,OAAOC,KAAKC,OAAO,yB,aCSxDC,IAAAA,aAAAA,IAAqB,kBAAkB,YACrCC,EAAAA,EAAAA,QAAOC,IAAc,uBAAuB,SAAUC,EAAmCC,GACvF,GAAID,EAAME,IAAI,WAAY,CACxB,IAAMC,EAAQF,EAAKE,QAEnB,GAAIA,GAASA,EAAMC,MAAK,SAACC,GAAI,MAAsB,aAAb,MAAJA,OAAI,EAAJA,EAAMC,OAAoB,IAAG,CAC7D,IAAMC,EAAcP,EAAMf,IAAI,WAC1BsB,GAAsC,iBAAhBA,GAA4B,aAAcA,IAClEA,EAAYC,SAAWX,IAAAA,WAAAA,MAAqB,6CAEhD,CACF,CACF,KAEAY,EAAAA,EAAAA,UAASC,IAAAA,UAAyB,cAAc,SAAUC,EAAUN,GAClE,MAAoB,YAAhBA,EAAKC,OACAT,IAAAA,WAAAA,MAAqB,kDAGvBc,EAASN,EAClB,GACF,G","sources":["webpack://@flarum/akismet/webpack/bootstrap","webpack://@flarum/akismet/webpack/runtime/compat get default export","webpack://@flarum/akismet/webpack/runtime/define property getters","webpack://@flarum/akismet/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/akismet/webpack/runtime/make namespace object","webpack://@flarum/akismet/external root \"flarum.core.compat['common/extend']\"","webpack://@flarum/akismet/external root \"flarum.core.compat['forum/app']\"","webpack://@flarum/akismet/external root \"flarum.core.compat['forum/utils/PostControls']\"","webpack://@flarum/akismet/external root \"flarum.core.compat['forum/components/Post']\"","webpack://@flarum/akismet/./src/forum/index.ts"],"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['forum/app'];","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.core.compat['forum/utils/PostControls'];","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.core.compat['forum/components/Post'];","import { extend, override } from 'flarum/common/extend';\nimport app from 'flarum/forum/app';\nimport type Post from 'flarum/common/models/Post';\nimport type ItemList from 'flarum/common/utils/ItemList';\n\nimport PostControls from 'flarum/forum/utils/PostControls';\nimport PostComponent from 'flarum/forum/components/Post';\nimport type Mithril from 'mithril';\n\napp.initializers.add('flarum-akismet', () => {\n extend(PostControls, 'destructiveControls', function (items: ItemList<Mithril.Children>, post: Post) {\n if (items.has('approve')) {\n const flags = post.flags();\n\n if (flags && flags.some((flag) => flag?.type() === 'akismet')) {\n const approveItem = items.get('approve');\n if (approveItem && typeof approveItem === 'object' && 'children' in approveItem) {\n approveItem.children = app.translator.trans('flarum-akismet.forum.post.not_spam_button');\n }\n }\n }\n });\n\n override(PostComponent.prototype, 'flagReason', function (original, flag) {\n if (flag.type() === 'akismet') {\n return app.translator.trans('flarum-akismet.forum.post.akismet_flagged_text');\n }\n\n return original(flag);\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","PostControls","items","post","has","flags","some","flag","type","approveItem","children","override","PostComponent","original"],"sourceRoot":""}
|
@@ -4,7 +4,7 @@ import type Post from 'flarum/common/models/Post';
|
||||
import type ItemList from 'flarum/common/utils/ItemList';
|
||||
|
||||
import PostControls from 'flarum/forum/utils/PostControls';
|
||||
import CommentPost from 'flarum/forum/components/CommentPost';
|
||||
import PostComponent from 'flarum/forum/components/Post';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
app.initializers.add('flarum-akismet', () => {
|
||||
@@ -21,7 +21,7 @@ app.initializers.add('flarum-akismet', () => {
|
||||
}
|
||||
});
|
||||
|
||||
override(CommentPost.prototype, 'flagReason', function (original, flag) {
|
||||
override(PostComponent.prototype, 'flagReason', function (original, flag) {
|
||||
if (flag.type() === 'akismet') {
|
||||
return app.translator.trans('flarum-akismet.forum.post.akismet_flagged_text');
|
||||
}
|
||||
|
@@ -19,8 +19,8 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6",
|
||||
"flarum/flags": "^1.2"
|
||||
"flarum/core": "^1.7",
|
||||
"flarum/flags": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/flags/js/dist/forum.js
generated
vendored
2
extensions/flags/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/flags/js/dist/forum.js.map
generated
vendored
2
extensions/flags/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
9
extensions/flags/js/src/@types/shims.d.ts
vendored
9
extensions/flags/js/src/@types/shims.d.ts
vendored
@@ -1,7 +1,6 @@
|
||||
import type Flag from '../forum/models/Flag';
|
||||
import type FlagListState from '../forum/states/FlagListState';
|
||||
import type Mithril from 'mithril';
|
||||
import type ItemList from 'flarum/common/utils/ItemList';
|
||||
import Flag from '../forum/models/Flag';
|
||||
import FlagListState from '../forum/states/FlagListState';
|
||||
import Mithril from 'mithril';
|
||||
|
||||
declare module 'flarum/common/models/Post' {
|
||||
export default interface Post {
|
||||
@@ -18,8 +17,6 @@ declare module 'flarum/forum/ForumApplication' {
|
||||
|
||||
declare module 'flarum/forum/components/Post' {
|
||||
export default interface Post {
|
||||
dismissFlag: (body: any) => Promise<any>;
|
||||
flagActionItems: () => ItemList<Mithril.Children>;
|
||||
flagReason: (flag: Flag) => Mithril.Children;
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,10 @@
|
||||
import { extend } from 'flarum/common/extend';
|
||||
import app from 'flarum/forum/app';
|
||||
import Post from 'flarum/forum/components/Post';
|
||||
import CommentPost from 'flarum/forum/components/CommentPost';
|
||||
import Button from 'flarum/common/components/Button';
|
||||
import ItemList from 'flarum/common/utils/ItemList';
|
||||
import PostControls from 'flarum/forum/utils/PostControls';
|
||||
import humanTime from 'flarum/common/utils/humanTime';
|
||||
import isObject from 'flarum/common/utils/isObject';
|
||||
import type Flag from './models/Flag';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
export default function () {
|
||||
extend(Post.prototype, 'elementAttrs', function (attrs) {
|
||||
@@ -25,7 +21,7 @@ export default function () {
|
||||
this.subtree.invalidate();
|
||||
|
||||
if (app.flags.cache) {
|
||||
app.flags.cache.some((flag: Flag, i: number) => {
|
||||
app.flags.cache.some((flag, i) => {
|
||||
if (flag.post() === post) {
|
||||
app.flags.cache.splice(i, 1);
|
||||
|
||||
@@ -43,8 +39,6 @@ export default function () {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,17 +50,16 @@ export default function () {
|
||||
};
|
||||
|
||||
Post.prototype.flagActionItems = function () {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
const items = new ItemList();
|
||||
|
||||
const controls = PostControls.destructiveControls(this.attrs.post, this);
|
||||
const controls = PostControls.destructiveControls(this.attrs.post);
|
||||
|
||||
Object.keys(controls.items).forEach((k) => {
|
||||
const item = controls.get(k);
|
||||
const attrs = isObject(item) && 'attrs' in item ? item.attrs : {};
|
||||
const attrs = controls.get(k).attrs;
|
||||
|
||||
attrs.className = 'Button';
|
||||
|
||||
extend(attrs, 'onclick', () => this.dismissFlag({}));
|
||||
extend(attrs, 'onclick', () => this.dismissFlag());
|
||||
});
|
||||
|
||||
items.add('controls', <div className="ButtonGroup">{controls.toArray()}</div>);
|
||||
@@ -88,16 +81,12 @@ export default function () {
|
||||
|
||||
if (!flags.length) return;
|
||||
|
||||
if (post.isHidden() && this instanceof CommentPost) {
|
||||
this.revealContent = true;
|
||||
}
|
||||
|
||||
if (!isObject(vdom) || !('unshift' in vdom)) return;
|
||||
if (post.isHidden()) this.revealContent = true;
|
||||
|
||||
vdom.unshift(
|
||||
<div className="Post-flagged">
|
||||
<div className="Post-flagged-flags">
|
||||
{flags.map((flag: Flag) => (
|
||||
{flags.map((flag) => (
|
||||
<div className="Post-flagged-flag">{this.flagReason(flag)}</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -122,7 +111,5 @@ export default function () {
|
||||
detail ? <span className="Post-flagged-detail">{detail}</span> : '',
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
@@ -1,6 +1,4 @@
|
||||
export default class FlagListState {
|
||||
index = 0;
|
||||
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6.3"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -103,7 +103,7 @@ class UpdateMentionsMetadataWhenVisible
|
||||
$post->unsetRelation('mentionsGroups');
|
||||
|
||||
$users = User::whereHas('groups', function ($query) use ($mentioned) {
|
||||
$query->whereIn('id', $mentioned);
|
||||
$query->whereIn('groups.id', $mentioned);
|
||||
})
|
||||
->get()
|
||||
->filter(function (User $user) use ($post) {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6",
|
||||
"flarum/core": "^1.7",
|
||||
"pusher/pusher-php-server": "^2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6.3"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^1.6"
|
||||
"flarum/core": "^1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/tags/js/dist/forum.js
generated
vendored
2
extensions/tags/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/tags/js/dist/forum.js.map
generated
vendored
2
extensions/tags/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -27,11 +27,11 @@ export default class TagDiscussionModal extends TagSelectionModal<TagDiscussionM
|
||||
attrs.limits = {
|
||||
allowBypassing: attrs.allowResetting,
|
||||
max: {
|
||||
primary: app.forum.attribute<number>('minPrimaryTags'),
|
||||
primary: app.forum.attribute<number>('maxPrimaryTags'),
|
||||
secondary: app.forum.attribute<number>('maxSecondaryTags'),
|
||||
},
|
||||
min: {
|
||||
primary: app.forum.attribute<number>('maxPrimaryTags'),
|
||||
primary: app.forum.attribute<number>('minPrimaryTags'),
|
||||
secondary: app.forum.attribute<number>('minSecondaryTags'),
|
||||
},
|
||||
};
|
||||
|
@@ -10,7 +10,7 @@ export default class TagHero extends Component {
|
||||
|
||||
return (
|
||||
<header
|
||||
className={classList('Hero', 'TagHero', { 'TagHero--colored': color }, textContrastClass(color))}
|
||||
className={classList('Hero', 'TagHero', { 'TagHero--colored': color, [textContrastClass(color)]: color })}
|
||||
style={color ? { '--hero-bg': color } : ''}
|
||||
>
|
||||
<div className="container">
|
||||
|
@@ -36,7 +36,7 @@
|
||||
"chat": "https://flarum.org/chat"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.3",
|
||||
"php": ">=7.3 || ^8.0",
|
||||
"components/font-awesome": "^5.14.0",
|
||||
"dflydev/fig-cookies": "^3.0.0",
|
||||
"doctrine/dbal": "^2.7",
|
||||
|
30362
framework/core/js/dist/admin.js
generated
vendored
30362
framework/core/js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/admin.js.map
generated
vendored
2
framework/core/js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
37513
framework/core/js/dist/forum.js
generated
vendored
37513
framework/core/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum.js.map
generated
vendored
2
framework/core/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -52,11 +52,14 @@ export default class PermissionDropdown<CustomAttrs extends IPermissionDropdownA
|
||||
|
||||
groupIds = filterByRequiredPermissions(groupIds, this.attrs.permission);
|
||||
|
||||
const no_one = groupIds.length === 0;
|
||||
const everyone = groupIds.includes(Group.GUEST_ID);
|
||||
const members = groupIds.includes(Group.MEMBER_ID);
|
||||
const adminGroup = app.store.getById<Group>('groups', Group.ADMINISTRATOR_ID)!;
|
||||
|
||||
if (everyone) {
|
||||
if (this.attrs.allowNoOne && no_one) {
|
||||
this.attrs.label = Badge.component({ icon: 'fas fa-user-slash' });
|
||||
} else if (everyone) {
|
||||
this.attrs.label = Badge.component({ icon: 'fas fa-globe' });
|
||||
} else if (members) {
|
||||
this.attrs.label = Badge.component({ icon: 'fas fa-user' });
|
||||
@@ -65,6 +68,17 @@ export default class PermissionDropdown<CustomAttrs extends IPermissionDropdownA
|
||||
}
|
||||
|
||||
if (this.showing) {
|
||||
if (this.attrs.allowNoOne) {
|
||||
children.push(
|
||||
Button.component(
|
||||
{
|
||||
icon: no_one ? 'fas fa-check' : true,
|
||||
onclick: () => this.save([Group.NO_ONE_ID]),
|
||||
},
|
||||
[Badge.component({ icon: 'fas fa-user-slash' }), ' ', app.translator.trans('core.admin.permissions_controls.no_one_button')]
|
||||
)
|
||||
);
|
||||
}
|
||||
if (this.attrs.allowGuest) {
|
||||
children.push(
|
||||
Button.component(
|
||||
|
@@ -12,6 +12,7 @@ export interface PermissionConfig {
|
||||
icon: string;
|
||||
label: Mithril.Children;
|
||||
allowGuest?: boolean;
|
||||
allowNoOne?: boolean;
|
||||
}
|
||||
|
||||
export interface PermissionSetting {
|
||||
@@ -435,6 +436,7 @@ export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = I
|
||||
return PermissionDropdown.component({
|
||||
permission: item.permission,
|
||||
allowGuest: item.allowGuest,
|
||||
allowNoOne: item.allowNoOne,
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -39,7 +39,7 @@ export default class StatusWidget extends DashboardWidget {
|
||||
'schedule-status',
|
||||
[
|
||||
<span>
|
||||
<strong>Scheduler</strong>{' '}
|
||||
<strong>{app.translator.trans('core.admin.dashboard.status.headers.scheduler-status')}</strong>{' '}
|
||||
<LinkButton href="https://discuss.flarum.org/d/24118" external={true} target="_blank" icon="fas fa-info-circle" />
|
||||
</span>,
|
||||
<br />,
|
||||
@@ -49,8 +49,16 @@ export default class StatusWidget extends DashboardWidget {
|
||||
);
|
||||
}
|
||||
|
||||
items.add('queue-driver', [<strong>Queue Driver</strong>, <br />, app.data.queueDriver], 60);
|
||||
items.add('session-driver', [<strong>Session Driver</strong>, <br />, app.data.sessionDriver], 50);
|
||||
items.add(
|
||||
'queue-driver',
|
||||
[<strong>{app.translator.trans('core.admin.dashboard.status.headers.queue-driver')}</strong>, <br />, app.data.queueDriver],
|
||||
60
|
||||
);
|
||||
items.add(
|
||||
'session-driver',
|
||||
[<strong>{app.translator.trans('core.admin.dashboard.status.headers.session-driver')}</strong>, <br />, app.data.sessionDriver],
|
||||
50
|
||||
);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
@@ -39,6 +39,6 @@ export default class LinkButton extends Button {
|
||||
* @return {boolean}
|
||||
*/
|
||||
static isActive(attrs) {
|
||||
return typeof attrs.active !== 'undefined' ? attrs.active : m.route.get() === attrs.href;
|
||||
return typeof attrs.active !== 'undefined' ? attrs.active : m.route.get()?.split('?')[0] === attrs.href?.split('?')[0];
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import Dropdown, { IDropdownAttrs } from './Dropdown';
|
||||
import icon from '../helpers/icon';
|
||||
import extractText from '../utils/extractText';
|
||||
import classList from '../utils/classList';
|
||||
import type Component from '../Component';
|
||||
import type Mithril from 'mithril';
|
||||
@@ -50,7 +49,8 @@ export default class SelectDropdown<CustomAttrs extends ISelectDropdownAttrs = I
|
||||
const activeChild = children.find(isActive);
|
||||
let label = (activeChild && typeof activeChild === 'object' && 'children' in activeChild && activeChild.children) || this.attrs.defaultLabel;
|
||||
|
||||
label = extractText(label);
|
||||
// @ts-ignore
|
||||
if (Array.isArray(label)) label = label[0];
|
||||
|
||||
return [<span className="Button-label">{label}</span>, this.attrs.caretIcon ? icon(this.attrs.caretIcon, { className: 'Button-caret' }) : null];
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import Model from '../Model';
|
||||
|
||||
export default class Group extends Model {
|
||||
static NO_ONE_ID = '-1';
|
||||
static ADMINISTRATOR_ID = '1';
|
||||
static GUEST_ID = '2';
|
||||
static MEMBER_ID = '3';
|
||||
|
@@ -185,7 +185,7 @@ export default class AccessTokensList<CustomAttrs extends IAccessTokensListAttrs
|
||||
const name = token.title() || app.translator.trans('core.forum.security.token_title_placeholder');
|
||||
const value = this.tokenValueDisplay(token);
|
||||
|
||||
return app.translator.trans('core.forum.security.token_item_title', { name, value });
|
||||
return app.translator.trans('core.forum.security.token_item_title', { title: name, token: value });
|
||||
}
|
||||
|
||||
tokenValueDisplay(token: AccessToken): Mithril.Children {
|
||||
|
@@ -51,17 +51,27 @@ export default class UserSecurityPage<CustomAttrs extends IUserPageAttrs = IUser
|
||||
settingsItems() {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
['developerTokens', 'sessions'].forEach((section) => {
|
||||
const sectionName = `${section}Items` as 'developerTokensItems' | 'sessionsItems';
|
||||
const sectionLocale = camelCaseToSnakeCase(section);
|
||||
|
||||
if (
|
||||
app.forum.attribute('canCreateAccessToken') ||
|
||||
app.forum.attribute('canModerateAccessTokens') ||
|
||||
(this.state.hasLoadedTokens() && this.state.getDeveloperTokens()?.length)
|
||||
) {
|
||||
items.add(
|
||||
section,
|
||||
<FieldSet className={`UserSecurityPage-${section}`} label={app.translator.trans(`core.forum.security.${sectionLocale}_heading`)}>
|
||||
{this[sectionName]().toArray()}
|
||||
'developerTokens',
|
||||
<FieldSet className="UserSecurityPage-developerTokens" label={app.translator.trans(`core.forum.security.developer_tokens_heading`)}>
|
||||
{this.developerTokensItems().toArray()}
|
||||
</FieldSet>
|
||||
);
|
||||
});
|
||||
} else if (!this.state.hasLoadedTokens()) {
|
||||
items.add('developerTokens', <LoadingIndicator />);
|
||||
}
|
||||
|
||||
items.add(
|
||||
'sessions',
|
||||
<FieldSet className="UserSecurityPage-sessions" label={app.translator.trans(`core.forum.security.sessions_heading`)}>
|
||||
{this.sessionsItems().toArray()}
|
||||
</FieldSet>
|
||||
);
|
||||
|
||||
if (this.user!.id() === app.session.user!.id()) {
|
||||
items.add(
|
||||
|
@@ -40,7 +40,7 @@
|
||||
--yiq-threshold: 108;
|
||||
}
|
||||
& when (@config-dark-mode = false) {
|
||||
--yiq-threshold: 138;
|
||||
--yiq-threshold: 150;
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
|
@@ -16,10 +16,6 @@
|
||||
border-radius: var(--border-radius);
|
||||
overflow: hidden;
|
||||
|
||||
> *:not(:first-child) {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
padding: 16px 16px 16px 0;
|
||||
@@ -65,26 +61,19 @@
|
||||
|
||||
@media @phone {
|
||||
.AccessTokensList {
|
||||
> *:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&-item {
|
||||
flex-wrap: wrap;
|
||||
padding: 16px;
|
||||
|
||||
> *:not(:first-child) {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
width: 100%;
|
||||
justify-content: start;
|
||||
padding: 8px;
|
||||
width: auto;
|
||||
min-width: calc(~"var(--font-size) + 4rem");
|
||||
}
|
||||
|
||||
&-actions {
|
||||
width: 100%;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -58,6 +58,10 @@ core:
|
||||
description: Your forum at a glance.
|
||||
io_error_message: "Could not write to filesystem. Check your filesystem permissions and try again. Or try running from the command line."
|
||||
status:
|
||||
headers:
|
||||
scheduler-status: Scheduler
|
||||
queue-driver: Queue Driver
|
||||
session-driver: Session Driver
|
||||
scheduler:
|
||||
active: Active
|
||||
inactive: Inactive
|
||||
@@ -65,7 +69,7 @@ core:
|
||||
title: Dashboard
|
||||
tools_button: Tools
|
||||
|
||||
# These translations are usin in the debug warning widget.
|
||||
# These translations are used in the debug warning widget.
|
||||
debug-warning:
|
||||
detail: |
|
||||
When <code>debug</code> mode is active, Flarum will rebuild its <code>JavaScript</code> and <code>CSS</code> assets on every request, and could also potentially leak other information, such as database secrets, environment variables, etc.
|
||||
@@ -231,6 +235,7 @@ core:
|
||||
members_button: => core.group.members
|
||||
signup_closed_button: Closed
|
||||
signup_open_button: Open
|
||||
no_one_button: No one
|
||||
|
||||
# These translations are used generically in setting fields.
|
||||
settings:
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace Flarum\Api\Controller;
|
||||
|
||||
use Flarum\Group\Group;
|
||||
use Flarum\Group\Permission;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use Illuminate\Support\Arr;
|
||||
@@ -32,6 +33,11 @@ class SetPermissionController implements RequestHandlerInterface
|
||||
|
||||
Permission::where('permission', $permission)->delete();
|
||||
|
||||
// Permission set to no one.
|
||||
if (count($groupIds) === 1 && intval($groupIds[0]) === Group::NO_ONE_ID) {
|
||||
return new EmptyResponse(204);
|
||||
}
|
||||
|
||||
Permission::insert(array_map(function ($groupId) use ($permission) {
|
||||
return [
|
||||
'permission' => $permission,
|
||||
|
61
framework/core/src/Extend/Conditional.php
Normal file
61
framework/core/src/Extend/Conditional.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?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\Extend;
|
||||
|
||||
use Flarum\Extension\Extension;
|
||||
use Flarum\Extension\ExtensionManager;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class Conditional implements ExtenderInterface
|
||||
{
|
||||
/**
|
||||
* @var array<array{condition: bool|callable, extenders: ExtenderInterface[]}>
|
||||
*/
|
||||
protected $conditions = [];
|
||||
|
||||
/**
|
||||
* @param ExtenderInterface[] $extenders
|
||||
*/
|
||||
public function whenExtensionEnabled(string $extensionId, array $extenders): self
|
||||
{
|
||||
return $this->when(function (ExtensionManager $extensions) use ($extensionId) {
|
||||
return $extensions->isEnabled($extensionId);
|
||||
}, $extenders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|callable $condition
|
||||
* @param ExtenderInterface[] $extenders
|
||||
*/
|
||||
public function when($condition, array $extenders): self
|
||||
{
|
||||
$this->conditions[] = [
|
||||
'condition' => $condition,
|
||||
'extenders' => $extenders,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
foreach ($this->conditions as $condition) {
|
||||
if (is_callable($condition['condition'])) {
|
||||
$condition['condition'] = $container->call($condition['condition']);
|
||||
}
|
||||
|
||||
if ($condition['condition']) {
|
||||
foreach ($condition['extenders'] as $extender) {
|
||||
$extender->extend($container, $extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
framework/core/src/Extend/Permission.php
Normal file
29
framework/core/src/Extend/Permission.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?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\Extend;
|
||||
|
||||
use Flarum\Extension\Extension;
|
||||
use Flarum\User\Access\AdminPolicy;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class Permission implements ExtenderInterface
|
||||
{
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
// TODO: Implement extend() method.
|
||||
}
|
||||
|
||||
public function allowsNoOne(string $permission): self
|
||||
{
|
||||
AdminPolicy::allowNoOneOnPermission($permission);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -414,19 +414,19 @@ class Extension implements Arrayable
|
||||
$links['source'] = $sourceUrl;
|
||||
}
|
||||
|
||||
if (($discussUrl = $this->composerJsonAttribute('support.forum'))) {
|
||||
if ($discussUrl = $this->composerJsonAttribute('support.forum')) {
|
||||
$links['discuss'] = $discussUrl;
|
||||
}
|
||||
|
||||
if (($documentationUrl = $this->composerJsonAttribute('support.docs'))) {
|
||||
if ($documentationUrl = $this->composerJsonAttribute('support.docs')) {
|
||||
$links['documentation'] = $documentationUrl;
|
||||
}
|
||||
|
||||
if (($websiteUrl = $this->composerJsonAttribute('homepage'))) {
|
||||
if ($websiteUrl = $this->composerJsonAttribute('homepage')) {
|
||||
$links['website'] = $websiteUrl;
|
||||
}
|
||||
|
||||
if (($supportEmail = $this->composerJsonAttribute('support.email'))) {
|
||||
if ($supportEmail = $this->composerJsonAttribute('support.email')) {
|
||||
$links['support'] = "mailto:$supportEmail";
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ class Application
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '1.7.0-dev';
|
||||
const VERSION = '1.8.0-dev';
|
||||
|
||||
/**
|
||||
* The IoC container for the Flarum application.
|
||||
|
@@ -32,6 +32,11 @@ class Group extends AbstractModel
|
||||
use EventGeneratorTrait;
|
||||
use ScopeVisibilityTrait;
|
||||
|
||||
/**
|
||||
* The temporary ID for when no one can do something.
|
||||
*/
|
||||
const NO_ONE_ID = -1;
|
||||
|
||||
/**
|
||||
* The ID of the administrator group.
|
||||
*/
|
||||
|
42
framework/core/src/User/Access/AdminPolicy.php
Normal file
42
framework/core/src/User/Access/AdminPolicy.php
Normal file
@@ -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\User\Access;
|
||||
|
||||
use Flarum\User\User;
|
||||
|
||||
class AdminPolicy extends AbstractPolicy
|
||||
{
|
||||
public static array $allowNoOnePermissions = [];
|
||||
|
||||
/**
|
||||
* @param string|array<string> $permissions
|
||||
* @return void
|
||||
*/
|
||||
public static function allowNoOneOnPermission($permissions)
|
||||
{
|
||||
self::$allowNoOnePermissions[] = array_merge(
|
||||
static::$allowNoOnePermissions,
|
||||
(array) $permissions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @return bool|null
|
||||
*/
|
||||
public function can(User $actor, $ability)
|
||||
{
|
||||
if (! in_array($ability, static::$allowNoOnePermissions)
|
||||
&& $actor->isAdmin()) {
|
||||
return $this->forceAllow();
|
||||
}
|
||||
}
|
||||
}
|
@@ -65,7 +65,7 @@ class Gate
|
||||
$appliedPolicies = [];
|
||||
|
||||
if ($model) {
|
||||
$modelClasses = is_string($model) ? [$model] : array_merge(class_parents(($model)), [get_class($model)]);
|
||||
$modelClasses = is_string($model) ? [$model] : array_merge(class_parents($model), [get_class($model)]);
|
||||
|
||||
foreach ($modelClasses as $class) {
|
||||
$appliedPolicies = array_merge($appliedPolicies, $this->getPolicies($class));
|
||||
@@ -87,11 +87,7 @@ class Gate
|
||||
// If no policy covered this permission query, we will only grant
|
||||
// the permission if the actor's groups have it. Otherwise, we will
|
||||
// not allow the user to perform this action.
|
||||
if ($actor->isAdmin() || ($actor->hasPermission($ability))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $actor->hasPermission($ability);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -380,10 +380,6 @@ class User extends AbstractModel
|
||||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
if ($this->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return in_array($permission, $this->getPermissions());
|
||||
}
|
||||
|
||||
@@ -396,10 +392,6 @@ class User extends AbstractModel
|
||||
*/
|
||||
public function hasPermissionLike($match)
|
||||
{
|
||||
if ($this->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($this->getPermissions() as $permission) {
|
||||
if (substr($permission, -strlen($match)) === $match) {
|
||||
return true;
|
||||
|
@@ -20,6 +20,7 @@ use Flarum\Http\AccessToken;
|
||||
use Flarum\Post\Access\PostPolicy;
|
||||
use Flarum\Post\Post;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\Access\AdminPolicy;
|
||||
use Flarum\User\Access\ScopeUserVisibility;
|
||||
use Flarum\User\DisplayName\DriverInterface;
|
||||
use Flarum\User\DisplayName\UsernameDriver;
|
||||
@@ -49,7 +50,7 @@ class UserServiceProvider extends AbstractServiceProvider
|
||||
|
||||
$this->container->singleton('flarum.policies', function () {
|
||||
return [
|
||||
Access\AbstractPolicy::GLOBAL => [],
|
||||
Access\AbstractPolicy::GLOBAL => [AdminPolicy::class],
|
||||
AccessToken::class => [AccessTokenPolicy::class],
|
||||
Discussion::class => [DiscussionPolicy::class],
|
||||
Group::class => [GroupPolicy::class],
|
||||
|
162
framework/core/tests/integration/extenders/ConditionalTest.php
Normal file
162
framework/core/tests/integration/extenders/ConditionalTest.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?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\Tests\integration\extenders;
|
||||
|
||||
use Exception;
|
||||
use Flarum\Api\Serializer\ForumSerializer;
|
||||
use Flarum\Extend;
|
||||
use Flarum\Extension\ExtensionManager;
|
||||
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Testing\integration\TestCase;
|
||||
|
||||
class ConditionalTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
/** @test */
|
||||
public function conditional_works_if_condition_is_primitive_true()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Conditional())
|
||||
->when(true, [
|
||||
(new Extend\ApiSerializer(ForumSerializer::class))
|
||||
->attributes(function () {
|
||||
return [
|
||||
'customConditionalAttribute' => true
|
||||
];
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
$this->app();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$payload = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
$this->assertArrayHasKey('customConditionalAttribute', $payload['data']['attributes']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function conditional_does_not_work_if_condition_is_primitive_false()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Conditional())
|
||||
->when(false, [
|
||||
(new Extend\ApiSerializer(ForumSerializer::class))
|
||||
->attributes(function () {
|
||||
return [
|
||||
'customConditionalAttribute' => true
|
||||
];
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
$this->app();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$payload = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
$this->assertArrayNotHasKey('customConditionalAttribute', $payload['data']['attributes']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function conditional_works_if_condition_is_callable_true()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Conditional())
|
||||
->when(function () {
|
||||
return true;
|
||||
}, [
|
||||
(new Extend\ApiSerializer(ForumSerializer::class))
|
||||
->attributes(function () {
|
||||
return [
|
||||
'customConditionalAttribute' => true
|
||||
];
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
$this->app();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$payload = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
$this->assertArrayHasKey('customConditionalAttribute', $payload['data']['attributes']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function conditional_does_not_work_if_condition_is_callable_false()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Conditional())
|
||||
->when(function () {
|
||||
return false;
|
||||
}, [
|
||||
(new Extend\ApiSerializer(ForumSerializer::class))
|
||||
->attributes(function () {
|
||||
return [
|
||||
'customConditionalAttribute' => true
|
||||
];
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
$this->app();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$payload = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
$this->assertArrayNotHasKey('customConditionalAttribute', $payload['data']['attributes']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function conditional_injects_dependencies_to_condition_callable()
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
|
||||
$this->extend(
|
||||
(new Extend\Conditional())
|
||||
->when(function (?ExtensionManager $extensions) {
|
||||
if (! $extensions) {
|
||||
throw new Exception('ExtensionManager not injected');
|
||||
}
|
||||
}, [
|
||||
(new Extend\ApiSerializer(ForumSerializer::class))
|
||||
->attributes(function () {
|
||||
return [
|
||||
'customConditionalAttribute' => true
|
||||
];
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
$this->app();
|
||||
}
|
||||
}
|
@@ -42,7 +42,7 @@ class LocalesTest extends TestCase
|
||||
public function custom_translation_exists_if_added()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
|
||||
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
|
||||
);
|
||||
|
||||
$this->app()->getContainer()->make('flarum.locales');
|
||||
@@ -57,7 +57,7 @@ class LocalesTest extends TestCase
|
||||
public function custom_translation_exists_if_added_with_intl_suffix()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
|
||||
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
|
||||
);
|
||||
|
||||
$this->app()->getContainer()->make('flarum.locales');
|
||||
@@ -72,7 +72,7 @@ class LocalesTest extends TestCase
|
||||
public function messageformat_works_in_translations()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
|
||||
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
|
||||
);
|
||||
|
||||
$this->app()->getContainer()->make('flarum.locales');
|
||||
@@ -87,7 +87,7 @@ class LocalesTest extends TestCase
|
||||
public function laravel_interface_methods_work()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
|
||||
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
|
||||
);
|
||||
|
||||
$this->app()->getContainer()->make('flarum.locales');
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@flarum/jest-config",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Jest config for Flarum.",
|
||||
"main": "index.cjs",
|
||||
"author": "Flarum Team",
|
||||
@@ -9,6 +9,7 @@
|
||||
"prettier": "@flarum/prettier-config",
|
||||
"dependencies": {
|
||||
"@types/jest": "^29.2.2",
|
||||
"flarum-webpack-config": "^2.0.1",
|
||||
"flat": "^5.0.2",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "flarum-webpack-config",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"description": "Webpack config for Flarum JS and TS transpilation.",
|
||||
"main": "index.js",
|
||||
"author": "Flarum Team",
|
||||
|
Reference in New Issue
Block a user