1
0
mirror of https://github.com/flarum/core.git synced 2025-08-17 22:01:44 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Sami Mazouz
d087396494 fix: title scoring issues with group by clause
Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
2023-03-04 16:54:09 +01:00
Sami Mazouz
0d53660eeb test: fulltext search scores properly and prioritizes titles
Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
2023-03-04 16:53:55 +01:00
47 changed files with 300 additions and 235 deletions

View File

@@ -1,75 +1,6 @@
# Changelog
## [v1.7.2](https://github.com/flarum/framework/compare/v1.7.1...v1.7.2)
### Fixed
- empty string displayed as SelectDropdown title (#3773)
## [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)
# [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).

View File

@@ -142,7 +142,8 @@
"mockery/mockery": "^1.4",
"phpunit/phpunit": "^9.0",
"phpstan/phpstan": ">=1.8.11 < 1.9.0",
"nunomaduro/larastan": "^1.0"
"nunomaduro/larastan": "^1.0",
"symfony/var-dumper": "*"
},
"config": {
"sort-packages": true

View File

@@ -19,8 +19,8 @@
}
],
"require": {
"flarum/core": "^1.7",
"flarum/approval": "^1.7"
"flarum/core": "^1.6",
"flarum/approval": "^1.2"
},
"autoload": {
"psr-4": {

View File

@@ -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 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})();
(()=>{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})();
//# sourceMappingURL=forum.js.map

View File

@@ -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,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":""}
{"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":""}

View File

@@ -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 PostComponent from 'flarum/forum/components/Post';
import CommentPost from 'flarum/forum/components/CommentPost';
import type Mithril from 'mithril';
app.initializers.add('flarum-akismet', () => {
@@ -21,7 +21,7 @@ app.initializers.add('flarum-akismet', () => {
}
});
override(PostComponent.prototype, 'flagReason', function (original, flag) {
override(CommentPost.prototype, 'flagReason', function (original, flag) {
if (flag.type() === 'akismet') {
return app.translator.trans('flarum-akismet.forum.post.akismet_flagged_text');
}

View File

@@ -19,8 +19,8 @@
}
],
"require": {
"flarum/core": "^1.7",
"flarum/flags": "^1.7"
"flarum/core": "^1.6",
"flarum/flags": "^1.2"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"extra": {
"branch-alias": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"extra": {
"branch-alias": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -7,7 +7,7 @@
],
"license": "MIT",
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"extra": {
"branch-alias": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"extra": {
"branch-alias": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6.3"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7",
"flarum/core": "^1.6",
"pusher/pusher-php-server": "^2.2"
},
"require-dev": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6.3"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^1.7"
"flarum/core": "^1.6"
},
"autoload": {
"psr-4": {

2
extensions/tags/js/dist/forum.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -27,11 +27,11 @@ export default class TagDiscussionModal extends TagSelectionModal<TagDiscussionM
attrs.limits = {
allowBypassing: attrs.allowResetting,
max: {
primary: app.forum.attribute<number>('maxPrimaryTags'),
primary: app.forum.attribute<number>('minPrimaryTags'),
secondary: app.forum.attribute<number>('maxSecondaryTags'),
},
min: {
primary: app.forum.attribute<number>('minPrimaryTags'),
primary: app.forum.attribute<number>('maxPrimaryTags'),
secondary: app.forum.attribute<number>('minSecondaryTags'),
},
};

View File

@@ -10,7 +10,7 @@ export default class TagHero extends Component {
return (
<header
className={classList('Hero', 'TagHero', { 'TagHero--colored': color, [textContrastClass(color)]: color })}
className={classList('Hero', 'TagHero', { 'TagHero--colored': color }, textContrastClass(color))}
style={color ? { '--hero-bg': color } : ''}
>
<div className="container">

View File

@@ -36,7 +36,7 @@
"chat": "https://flarum.org/chat"
},
"require": {
"php": ">=7.3 || ^8.0",
"php": ">=7.3",
"components/font-awesome": "^5.14.0",
"dflydev/fig-cookies": "^3.0.0",
"doctrine/dbal": "^2.7",
@@ -88,7 +88,8 @@
"wikimedia/less.php": "^3.2"
},
"require-dev": {
"flarum/testing": "^1.0.0"
"flarum/testing": "^1.0.0",
"symfony/var-dumper": "*"
},
"autoload": {
"psr-4": {

2
framework/core/js/dist/admin.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
framework/core/js/dist/forum.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -39,7 +39,7 @@ export default class StatusWidget extends DashboardWidget {
'schedule-status',
[
<span>
<strong>{app.translator.trans('core.admin.dashboard.status.headers.scheduler-status')}</strong>{' '}
<strong>Scheduler</strong>{' '}
<LinkButton href="https://discuss.flarum.org/d/24118" external={true} target="_blank" icon="fas fa-info-circle" />
</span>,
<br />,
@@ -49,16 +49,8 @@ export default class StatusWidget extends DashboardWidget {
);
}
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
);
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);
return items;
}

View File

@@ -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()?.split('?')[0] === attrs.href?.split('?')[0];
return typeof attrs.active !== 'undefined' ? attrs.active : m.route.get() === attrs.href;
}
}

View File

@@ -1,5 +1,6 @@
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';
@@ -49,8 +50,7 @@ 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;
// @ts-ignore
if (Array.isArray(label)) label = label[0];
label = extractText(label);
return [<span className="Button-label">{label}</span>, this.attrs.caretIcon ? icon(this.attrs.caretIcon, { className: 'Button-caret' }) : null];
}

View File

@@ -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', { title: name, token: value });
return app.translator.trans('core.forum.security.token_item_title', { name, value });
}
tokenValueDisplay(token: AccessToken): Mithril.Children {

View File

@@ -51,27 +51,17 @@ export default class UserSecurityPage<CustomAttrs extends IUserPageAttrs = IUser
settingsItems() {
const items = new ItemList<Mithril.Children>();
if (
app.forum.attribute('canCreateAccessToken') ||
app.forum.attribute('canModerateAccessTokens') ||
(this.state.hasLoadedTokens() && this.state.getDeveloperTokens()?.length)
) {
['developerTokens', 'sessions'].forEach((section) => {
const sectionName = `${section}Items` as 'developerTokensItems' | 'sessionsItems';
const sectionLocale = camelCaseToSnakeCase(section);
items.add(
'developerTokens',
<FieldSet className="UserSecurityPage-developerTokens" label={app.translator.trans(`core.forum.security.developer_tokens_heading`)}>
{this.developerTokensItems().toArray()}
section,
<FieldSet className={`UserSecurityPage-${section}`} label={app.translator.trans(`core.forum.security.${sectionLocale}_heading`)}>
{this[sectionName]().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(

View File

@@ -40,7 +40,7 @@
--yiq-threshold: 108;
}
& when (@config-dark-mode = false) {
--yiq-threshold: 150;
--yiq-threshold: 138;
}
// ---------------------------------

View File

@@ -16,6 +16,10 @@
border-radius: var(--border-radius);
overflow: hidden;
> *:not(:first-child) {
margin-left: 1px;
}
&-item {
display: flex;
padding: 16px 16px 16px 0;
@@ -61,19 +65,26 @@
@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: auto;
width: 100%;
}
}
}

View File

@@ -18,7 +18,6 @@ core:
custom_footer_text: => core.ref.custom_footer_text
custom_header_heading: Custom Header
custom_header_text: => core.ref.custom_header_text
custom_styles_cannot_use_less_features: "The @import and data-uri features are not allowed in custom LESS."
custom_styles_heading: Custom Styles
custom_styles_text: Customize your forum's appearance by adding your own Less/CSS code to be applied on top of Flarum's default styles.
dark_mode_label: Dark Mode
@@ -58,10 +57,6 @@ 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
@@ -69,7 +64,7 @@ core:
title: Dashboard
tools_button: Tools
# These translations are used in the debug warning widget.
# These translations are usin 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.

View File

@@ -30,7 +30,8 @@ class FulltextGambit implements GambitInterface
$query = $search->getQuery();
$grammar = $query->getGrammar();
$discussionSubquery = Discussion::select('id')
$discussionSubquery = Discussion::query()
->selectRaw('id as discussion_id')
->selectRaw('NULL as score')
->selectRaw('first_post_id as most_relevant_post_id')
->whereRaw('MATCH('.$grammar->wrap('discussions.title').') AGAINST (? IN BOOLEAN MODE)', [$bit]);
@@ -52,17 +53,19 @@ class FulltextGambit implements GambitInterface
// discussions that have a relevant title or that contain relevant posts.
$query
->addSelect('posts_ft.most_relevant_post_id')
->addSelect('posts_ft.score')
->selectRaw('MATCH('.$grammar->wrap('discussions.title').') AGAINST (?) as title_score', [$bit])
->join(
new Expression('('.$subquery->toSql().') '.$grammar->wrapTable('posts_ft')),
'posts_ft.discussion_id',
'=',
'discussions.id'
)
->groupBy('discussions.id')
->groupBy('posts_ft.discussion_id', 'title_score')
->addBinding($subquery->getBindings(), 'join');
$search->setDefaultSort(function ($query) use ($grammar, $bit) {
$query->orderByRaw('MATCH('.$grammar->wrap('discussions.title').') AGAINST (?) desc', [$bit]);
$search->setDefaultSort(function ($query) {
$query->orderBy('title_score', 'desc');
$query->orderBy('posts_ft.score', 'desc');
});

View File

@@ -21,7 +21,6 @@ use Illuminate\Filesystem\FilesystemAdapter;
use League\Flysystem\Adapter\NullAdapter;
use League\Flysystem\Filesystem;
use Less_Exception_Parser;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
@@ -62,15 +61,6 @@ class ValidateCustomLess
return;
}
// Restrict what features can be used in custom LESS
if (isset($event->settings['custom_less']) && preg_match('/@import|data-uri\s*\(/i', $event->settings['custom_less'])) {
$translator = $this->container->make(TranslatorInterface::class);
throw new ValidationException([
'custom_less' => $translator->trans('core.admin.appearance.custom_styles_cannot_use_less_features')
]);
}
// We haven't saved the settings yet, but we want to trial a full
// recompile of the CSS to see if this custom LESS will break
// anything. In order to do that, we will temporarily override the

View File

@@ -21,7 +21,7 @@ class Application
*
* @var string
*/
const VERSION = '1.7.2';
const VERSION = '1.7.0-dev';
/**
* The IoC container for the Flarum application.

View File

@@ -27,9 +27,21 @@ class ListWithFulltextSearchTest extends TestCase
$this->database()->rollBack();
$this->populateSimpleTestData();
$this->populateRealDataForScoreTests();
// We need to call these again, since we rolled back the transaction started by `::app()`.
$this->database()->beginTransaction();
$this->populateDatabase();
}
private function populateSimpleTestData(): void
{
// We need to insert these outside of a transaction, because FULLTEXT indexing,
// which is needed for search, doesn't happen in transactions.
// We clean it up explcitly at the end.
// We clean it up explicitly at the end.
$this->database()->table('discussions')->insert([
['id' => 1, 'title' => 'lightsail in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1],
['id' => 2, 'title' => 'lightsail in title too', 'created_at' => Carbon::createFromDate(2020, 01, 01)->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1],
@@ -48,11 +60,130 @@ class ListWithFulltextSearchTest extends TestCase
['id' => 6, 'discussion_id' => 4, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>తెలుగు</p></t>'],
['id' => 7, 'discussion_id' => 2, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>支持中文吗</p></t>'],
]);
}
// We need to call these again, since we rolled back the transaction started by `::app()`.
$this->database()->beginTransaction();
private function populateRealDataForScoreTests(): void
{
// Disable forign key constraints temporarily
$this->database()->statement('SET FOREIGN_KEY_CHECKS=0');
$this->populateDatabase();
$this->database()->table('discussions')->insert([
['id' => 7, 'title' => 'User should be able to promote the visible, foreground, non-saved window to a saved window', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1, 'first_post_id' => 8],
['id' => 8, 'title' => 'Moving Tab in Saved Window to New Window Destroys Non-Saved Window', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1, 'first_post_id' => 16],
['id' => 9, 'title' => 'Current saved window is renamed when moving normal window to saved window area', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1, 'first_post_id' => 18],
['id' => 10, 'title' => 'Save bookmarks edit page window position is not saved', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1, 'first_post_id' => 19],
['id' => 11, 'title' => 'Favicons in the saved bookmarks flash on and off', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1, 'first_post_id' => 20],
['id' => 12, 'title' => 'User should be able to switch \'in-place\' between non-saved windows', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1, 'first_post_id' => 23],
]);
$this->database()->table('posts')->insert([
['id' => 8, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>Unless I\'m missing something, currently there does not appear to be a way to promote a non-saved window to a saved window. A user must be click the \'+\' button in the window menu dropdown, then re-open all open tabs in the current window in the new saved window. That doesn\'t sound fun if one has multiple tabs open.</p>
<p>This would be ameliorated if it was possible move tabs to saved windows without physical drag and drop but that doesn\'t seem possible as well, see User should be able to move tabs from visible window to non-visible saved windows</p></t>'],
['id' => 9, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>open sidebar<br/>
switch to either Tabs or Windows view in sidebar<br/>
right click on window title in side bar (eg. "3 Tabs")<br/>
click "Save..."<br/>
OR<br/>
click once on window title in sidebar (eg. "3 Tabs")<br/>
rename window in-place<br/>
I think this is how it is supposed to work.</p>
<p>For me, at least, this funcionality doesn\'t work due to (I imagine) a bug...<br/>
Unless I\'ve misunderstood you?</p></t>'],
['id' => 10, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<r><p>Are you refering to this?</p>
<p><URL url="https://orionfeedback.org/d/4258-window-switcher-i-am-able-to-drag-the-unsaved-window-into-saved-windows-and-it-breaks-the-ui-until-restart">https://orionfeedback.org/d/4258-window-switcher-i-am-able-to-drag-the-unsaved-window-into-saved-windows-and-it-breaks-the-ui-until-restart</URL></p></r>'],
['id' => 11, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>robrecord Yes! Wasn\'t apparent that was the trick. Thanks for pointing it out.<br/>
Vlad My other logged issue seems related to that one</p></t>'],
['id' => 12, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>b3noit Which one?</p>
<p>Is there anything still being asked here?</p></t>'],
['id' => 13, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<r><p>Vlad This one <URL url="https://orionfeedback.org/d/4288-moving-tab-in-saved-window-to-new-window-destroys-non-saved-window">https://orionfeedback.org/d/4288-moving-tab-in-saved-window-to-new-window-destroys-non-saved-window</URL></p>
<p>The post above yours clarified how the UI is supposed to be used here</p></r>'],
['id' => 14, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t>
<p>b3noit So is there an ask here or I can close this?</p></t>'],
['id' => 15, 'discussion_id' => 7, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t>
<p>b3noit ping</p></t>'],
['id' => 26, 'discussion_id' => 12, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => "<t><p>Visible, non-saved windows cannot participate in 'in-place' window switching, they can only be switched via the OS window manager. Its unclear why only saved windows can participate, at the least non-saved windows should be able to opt-in so one window can switch between both saved and non-saved windows.</p></t>"],
['id' => 25, 'discussion_id' => 12, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>@dino can you explain why we decided this?</p>
</t>'],
['id' => 24, 'discussion_id' => 12, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>Vlad b3noit Because when anyone creates new Window (by New Window menu), user will always expect, there will be a separate Window as per any native app. So when having separate Window (for unsaved windows), why in-place switching needed. Lots of users still prefer working with Windows (as this term is very obvious for any OS), sometime side-by-side, sometime by using external display.</p>
<p>Also any modern browser uses Tab-Groups for in-place switching, but they treat traditional Windows in same way. So instead of breaking Native terminology and flow of OS, we preferred to continue with Windows.</p>
<p>Also if some user still feels to use all in-place switching, then that user can create new Windows as new in-place group by clicking "+" from window manager &#128578;</p></t>'],
['id' => 23, 'discussion_id' => 12, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => "<t><p>dino Vlad My thing about the solution of 'well, make a new saved window that does participate in in-place switching' is that:</p>
<p>there's no convenient affordance to move tabs from a visible, non-saved window to a saved window<br/>
there's no convenient affordance to simply transform a non-saved, visible window to a saved window that can interact with in-place switching<br/>
I don't see a reason why a user can't opt in a window into being able to be switched in-place<br/>
From where I'm standing, unless I'm missing something, the abstraction of a window and a group of tabs are two different things; it appears that in the case of Orion, there's an assumption about the relationship between a collection of tabs and windows such that, just like in programming languages with different 'colored' functions (e.g. async in JS, C#, etc), here you have the case of 'colored' windows.</p></t>"],
['id' => 22, 'discussion_id' => 11, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => "<t><p>No and actually it's OK I found it. It was some corrupted pref files. The ones relating to the web icons. I had to reestablish some of my preferences for the app but otherwise not much hassle!</p>
</t>"],
['id' => 21, 'discussion_id' => 11, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>can u provide a video?</p>
</t>'],
['id' => 20, 'discussion_id' => 11, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>Steps to reproduce:<br/>
&lt;Include steps to reproduce the bug; Did you try using Compatibility mode? If applicable, does Safari behave in the same way?&gt;</p>
<p>Expected behavior:<br/>
&lt;What you expected to happen?&gt;</p>
<p>Orion, OS version; hardware type:<br/>
Orion version Version 0.99.121-beta (WebKit 614.1.20)<br/>
MacOS version 12.6 (21G115) Monterey<br/>
M1 Mac mini (M1, 2020)<br/>
Image/Video:<br/>
&lt;Copy/paste or drag and drop to upload images or videos (up to 20MB)&gt;</p>
<p>The bookmarks in my Orion usually show favicons of the sites after I visit them. Today even after clearing cache and restarting the browser several times they are still flashing. Any ideas?</p></t>'],
['id' => 19, 'discussion_id' => 10, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>Steps to reproduce:<br/>
&lt;Include steps to reproduce the bug; Did you try using Compatibility mode? If applicable, does Safari behave in the same way?&gt;</p>
<p>Expected behavior:<br/>
Position is saved.</p>
<p>Orion and macOS:<br/>
&lt;Version&gt;</p>
<p>Image/Video:</p></t>'],
['id' => 18, 'discussion_id' => 9, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => "<t><p>Steps to reproduce:</p>
<p>Have one open window.<br/>
Have a saved window.<br/>
Using the toolbar icon, move the regular window to the saved window<br/>
Expected behavior:<br/>
Window is moved to saved area, doesn't affect other saved windows.<br/>
Orion, OS version; hardware type:<br/>
Version 0.99.123.1-beta (WebKit 615.1.16.1)<br/>
MacBook Pro (macOS Monterey 12.6.2 build 21G320)</p>
<p>Image/Video:</p>
</t>"],
['id' => 17, 'discussion_id' => 8, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>b3noit Can you please record a video of this?</p></t>'],
['id' => 16, 'discussion_id' => 8, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>Steps to reproduce:</p>
<p>Initialized a new non-saved window one tab<br/>
Initialize a new saved window with one tab<br/>
Switch in-place to saved window<br/>
Right tab and select move tab to New Window<br/>
Tab moves to non-saved window and replaces previously open tab in non-saved window<br/>
Expected behavior:<br/>
Tab should not replace non-saved window tab</p>
<p>Orion, OS version; hardware type:<br/>
0.99.123 on 12.6.3</p></t>'],
]);
}
/**
@@ -87,6 +218,27 @@ class ListWithFulltextSearchTest extends TestCase
$this->assertEqualsCanonicalizing(['2', '1', '3'], $ids, 'IDs do not match');
}
/**
* @test
*/
public function search_prioritizes_title_search_score_over_post()
{
$response = $this->send(
$this->request('GET', '/api/discussions')
->withQueryParams([
'filter' => ['q' => 'saved bookmarks'],
'include' => 'mostRelevantPost',
])
);
$data = json_decode($response->getBody()->getContents(), true);
$ids = array_map(function ($row) {
return $row['id'];
}, $data['data']);
$this->assertEquals(['11', '10', '7', '8', '9', '12'], $ids, 'IDs do not match');
}
/**
* @test
*/

View File

@@ -74,43 +74,43 @@ class GroupSearchTest extends TestCase
]);
$response = $this->createRequest(['admin'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$response = $this->createRequest(['mod'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
$response = $this->createRequest(['admins'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$response = $this->createRequest(['mods'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
$response = $this->createRequest(['1'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$response = $this->createRequest(['4'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
}
/**
@@ -126,10 +126,10 @@ class GroupSearchTest extends TestCase
$this->createHiddenUser();
$response = $this->createRequest(['99'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
}
/**
@@ -144,13 +144,13 @@ class GroupSearchTest extends TestCase
]);
$this->createMultipleUsersAndGroups();
$response = $this->createRequest(['1', '4', '5', '6', '99'], 2);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$this->assertCount(4, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(4, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertEquals(4, $responseBodyContents['included'][1]['id']);
$this->assertEquals(5, $responseBodyContents['included'][2]['id']);
$this->assertEquals(6, $responseBodyContents['included'][3]['id']);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(4, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(4, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$this->assertEquals(4, $responseBodyContents->included[1]->id);
$this->assertEquals(5, $responseBodyContents->included[2]->id);
$this->assertEquals(6, $responseBodyContents->included[3]->id);
}
/**
@@ -159,43 +159,43 @@ class GroupSearchTest extends TestCase
public function admin_gets_correct_results_group()
{
$response = $this->createRequest(['admin'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$response = $this->createRequest(['mod'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
$response = $this->createRequest(['admins'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$response = $this->createRequest(['mods'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
$response = $this->createRequest(['1'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$response = $this->createRequest(['4'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(0, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertArrayNotHasKey('included', $responseBodyContents, json_encode($responseBodyContents));
$this->assertCount(0, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertObjectNotHasAttribute('included', $responseBodyContents, json_encode($responseBodyContents));
}
/**
@@ -205,11 +205,11 @@ class GroupSearchTest extends TestCase
{
$this->createHiddenUser();
$response = $this->createRequest(['99'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(1, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(99, $responseBodyContents['included'][0]['id']);
$this->assertCount(1, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(1, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(99, $responseBodyContents->included[0]->id);
}
/**
@@ -220,14 +220,14 @@ class GroupSearchTest extends TestCase
$this->createMultipleUsersAndGroups();
$this->createHiddenUser();
$response = $this->createRequest(['1', '4', '5', '6', '99'], 1);
$responseBodyContents = json_decode($response->getBody()->getContents(), true);
$this->assertCount(5, $responseBodyContents['data'], json_encode($responseBodyContents));
$this->assertCount(5, $responseBodyContents['included'], json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents['included'][0]['id']);
$this->assertEquals(99, $responseBodyContents['included'][1]['id']);
$this->assertEquals(4, $responseBodyContents['included'][2]['id']);
$this->assertEquals(5, $responseBodyContents['included'][3]['id']);
$this->assertEquals(6, $responseBodyContents['included'][4]['id']);
$responseBodyContents = json_decode($response->getBody()->getContents());
$this->assertCount(5, $responseBodyContents->data, json_encode($responseBodyContents));
$this->assertCount(5, $responseBodyContents->included, json_encode($responseBodyContents));
$this->assertEquals(1, $responseBodyContents->included[0]->id);
$this->assertEquals(99, $responseBodyContents->included[1]->id);
$this->assertEquals(4, $responseBodyContents->included[2]->id);
$this->assertEquals(5, $responseBodyContents->included[3]->id);
$this->assertEquals(6, $responseBodyContents->included[4]->id);
}
private function createRequest(array $group, int $userId = null)

View File

@@ -1,6 +1,6 @@
{
"name": "@flarum/jest-config",
"version": "1.0.1",
"version": "1.0.0",
"description": "Jest config for Flarum.",
"main": "index.cjs",
"author": "Flarum Team",
@@ -9,7 +9,6 @@
"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",

View File

@@ -1,6 +1,6 @@
{
"name": "flarum-webpack-config",
"version": "2.0.1",
"version": "2.0.0",
"description": "Webpack config for Flarum JS and TS transpilation.",
"main": "index.js",
"author": "Flarum Team",