1
0
mirror of https://github.com/flarum/core.git synced 2025-08-14 04:14:06 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Daniël Klabbers
9faf01f965 chore: introduce the env vars 2024-03-04 21:09:45 +01:00
Daniël Klabbers
88cce7d7cf chore: add support for postgres 2024-03-04 20:44:57 +01:00
1602 changed files with 20976 additions and 40007 deletions

View File

@@ -18,11 +18,8 @@ trim_trailing_whitespace = false
[*.{php,xml,json}]
indent_size = 4
[{tsconfig.json,prettierrc.json,package.json}]
[{tsconfig.json,prettierrc.json}]
indent_size = 2
[*.neon]
indent_style = tab
[{install,update}.php]
indent_size = 2

View File

@@ -40,7 +40,7 @@ body:
validations:
required: false
- type: textarea
id: environment
id: enironment
attributes:
label: Environment
value: |

View File

@@ -32,7 +32,7 @@ on:
type: string
required: false
# Keep PHP versions synced with build-install-packages.yml
default: '["8.2", "8.3", "8.4"]'
default: '["8.1", "8.2", "8.3"]'
php_extensions:
description: PHP extensions to install.
@@ -44,7 +44,7 @@ on:
description: Versions of databases to test with. Should be array of strings encoded as JSON array
type: string
required: false
default: '["mysql:5.7", "mysql:8.0.30", "mysql:8.1.0", "mariadb", "sqlite:3", "postgres:10"]'
default: '["mysql:5.7", "mysql:8.0.30", "mysql:8.1.0", "mariadb", "postgres:16"]'
php_ini_values:
description: PHP ini values
@@ -52,12 +52,6 @@ on:
required: false
default: error_reporting=E_ALL
runner_type:
description: The type of runner to use for the jobs. This should be one of the types supported by the `runs-on` keyword.
type: string
required: false
default: 'ubuntu-latest'
secrets:
composer_auth:
description: The Composer auth tokens to use for private packages.
@@ -68,13 +62,10 @@ env:
# `inputs.composer_directory` defaults to `inputs.backend_directory`
FLARUM_TEST_TMP_DIR_LOCAL: tests/integration/tmp
COMPOSER_AUTH: ${{ secrets.composer_auth }}
DB_DATABASE: flarum_test
DB_USERNAME: flarum
DB_PASSWORD: password
jobs:
test:
runs-on: ${{ inputs.runner_type }}
runs-on: ubuntu-latest
strategy:
matrix:
@@ -88,46 +79,32 @@ jobs:
# Expands the matrix by naming DBs.
- service: 'mysql:5.7'
db: MySQL 5.7
driver: mysql
- service: 'mysql:8.0.30'
db: MySQL 8.0
driver: mysql
- service: mariadb
db: MariaDB
driver: mariadb
- service: 'mysql:8.1.0'
db: MySQL 8.1
driver: mysql
- service: 'sqlite:3'
db: SQLite
driver: sqlite
- service: 'postgres:10'
db: PostgreSQL 10
driver: pgsql
# Include Database prefix tests with only one PHP version.
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'mysql:5.7'
db: MySQL 5.7
driver: mysql
prefix: flarum_
prefixStr: (prefix)
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'mysql:8.0.30'
db: MySQL 8.0
prefix: flarum_
prefixStr: (prefix)
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: mariadb
db: MariaDB
driver: mariadb
prefix: flarum_
prefixStr: (prefix)
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'sqlite:3'
db: SQLite
driver: sqlite
prefix: flarum_
prefixStr: (prefix)
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'postgres:10'
db: PostgreSQL 10
driver: pgsql
service: 'mysql:8.1.0'
db: MySQL 8.1
prefix: flarum_
prefixStr: (prefix)
@@ -135,57 +112,20 @@ jobs:
exclude:
- php: ${{ fromJSON(inputs.php_versions)[1] }}
service: 'mysql:8.0.30'
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: mariadb
- php: ${{ fromJSON(inputs.php_versions)[1] }}
service: mariadb
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'mysql:8.1.0'
- php: ${{ fromJSON(inputs.php_versions)[1] }}
service: 'mysql:8.1.0'
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'sqlite:3'
- php: ${{ fromJSON(inputs.php_versions)[1] }}
service: 'sqlite:3'
- php: ${{ fromJSON(inputs.php_versions)[0] }}
service: 'postgres:10'
- php: ${{ fromJSON(inputs.php_versions)[1] }}
service: 'postgres:10'
services:
mysql:
image: ${{ matrix.driver == 'mysql' && matrix.service || '' }}
env:
MYSQL_DATABASE: ${{ env.DB_DATABASE }}
MYSQL_USER: ${{ env.DB_USERNAME }}
MYSQL_PASSWORD: ${{ env.DB_PASSWORD }}
MYSQL_ROOT_PASSWORD: root
image: ${{ matrix.service }}
ports:
- 3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=10
mariadb:
image: ${{ matrix.driver == 'mariadb' && matrix.service || '' }}
env:
MARIADB_DATABASE: ${{ env.DB_DATABASE }}
MARIADB_USER: ${{ env.DB_USERNAME }}
MARIADB_PASSWORD: ${{ env.DB_PASSWORD }}
MARIADB_ROOT_PASSWORD: root
ports:
- 3306
options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3
- 13306:3306
postgres:
image: ${{ matrix.driver == 'pgsql' && matrix.service || '' }}
env:
POSTGRES_DB: ${{ env.DB_DATABASE }}
POSTGRES_USER: ${{ env.DB_USERNAME }}
POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }}
image: ${{ matrix.service }}
ports:
- 5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
- 13306:5432
env:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
POSTGRES_DB: flarum_test
name: 'PHP ${{ matrix.php }} / ${{ matrix.db }} ${{ matrix.prefixStr }}'
@@ -194,10 +134,7 @@ jobs:
((github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) || github.event_name != 'pull_request')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: actions/checkout@master
- name: Setup PHP
uses: shivammathur/setup-php@v2
@@ -208,6 +145,11 @@ jobs:
tools: phpunit, composer:v2
ini-values: ${{ matrix.php_ini_values }}
- name: Create MySQL Database
run: |
sudo systemctl start mysql
mysql -uroot -proot -e 'CREATE DATABASE flarum_test;' --port 13306
- name: Install Composer dependencies
run: composer install
working-directory: ${{ inputs.backend_directory }}
@@ -230,18 +172,23 @@ jobs:
fi
working-directory: ${{ inputs.backend_directory }}
env:
DB_HOST: 127.0.0.1
DB_PORT: ${{ (matrix.driver == 'mysql' && job.services.mysql.ports['3306']) || (matrix.driver == 'mariadb' && job.services.mariadb.ports['3306']) || (matrix.driver == 'pgsql' && job.services.postgres.ports['5432']) }}
DB_PORT: 13306
DB_PASSWORD: root
DB_PREFIX: ${{ matrix.prefix }}
DB_DRIVER: ${{ matrix.driver }}
COMPOSER_PROCESS_TIMEOUT: 600
phpstan:
runs-on: ${{ inputs.runner_type }}
runs-on: ubuntu-latest
strategy:
matrix:
php: ${{ fromJson(inputs.php_versions) }}
php: ${{ fromJSON(inputs.php_versions) }}
services:
mysql:
image: mysql:8.0.30
ports:
- 33306:3306
name: 'PHPStan PHP ${{ matrix.php }}'
@@ -268,13 +215,12 @@ jobs:
- name: Create MySQL Database
run: |
sudo systemctl start mysql
mysql -uroot -proot -e 'CREATE DATABASE flarum_test;' --port 3306
mysql -uroot -proot -e 'CREATE DATABASE flarum_test;' --port 33306
- name: Run PHPStan
run: composer analyse:phpstan
env:
DB_USERNAME: root
DB_PORT: 3306
DB_PORT: 33306
DB_PASSWORD: root
COMPOSER_PROCESS_TIMEOUT: 600
FLARUM_TEST_TMP_DIR_LOCAL: ./tmp

View File

@@ -74,7 +74,7 @@ on:
description: The node version to use for the workflow.
type: number
required: false
default: 20
default: 16
js_package_manager:
description: "Enable TypeScript?"
@@ -86,12 +86,6 @@ on:
type: string
required: false
runner_type:
description: The type of runner to use for the jobs. This should be one of the types supported by the `runs-on` keyword.
type: string
required: false
default: 'ubuntu-latest'
secrets:
bundlewatch_github_token:
description: The GitHub token to use for Bundlewatch.
@@ -105,22 +99,21 @@ env:
ci_script: ${{ inputs.js_package_manager == 'yarn' && 'yarn install --immutable' || 'npm ci' }}
cache_dependency_path: ${{ inputs.cache_dependency_path || format(inputs.js_package_manager == 'yarn' && '{0}/yarn.lock' || '{0}/package-lock.json', inputs.frontend_directory) }}
COMPOSER_AUTH: ${{ secrets.composer_auth }}
DISABLE_V8_COMPILE_CACHE: 1
jobs:
build:
name: Checks & Build
runs-on: ${{ inputs.runner_type }}
runs-on: ubuntu-latest
if: >-
((github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) || github.event_name != 'pull_request')
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: ${{ inputs.node_version }}
cache: ${{ inputs.js_package_manager }}
@@ -143,7 +136,7 @@ jobs:
working-directory: ${{ inputs.frontend_directory }}
- name: JS Checks & Production Build
uses: flarum/action-build@v4
uses: flarum/action-build@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: ${{ inputs.build_script }}

View File

@@ -8,4 +8,4 @@ jobs:
with:
enable_backend_testing: true
backend_directory: .
monorepo_tests: "framework/core extensions/akismet extensions/approval extensions/flags extensions/likes extensions/mentions extensions/nicknames extensions/statistics extensions/sticky extensions/subscriptions extensions/suspend extensions/tags extensions/messages php-packages/testing/tests"
monorepo_tests: "framework/core extensions/akismet extensions/approval extensions/flags extensions/likes extensions/mentions extensions/nicknames extensions/statistics extensions/sticky extensions/subscriptions extensions/suspend extensions/tags"

View File

@@ -6,7 +6,7 @@ on:
env:
VERSION: ${{ github.event.release.tag_name }}
PHP_VERSIONS: '8.2 8.3 8.4'
PHP_VERSIONS: '8.1 8.2 8.3'
INSTALL_PACKAGES_INPUTS: '{ "flarum_version": "{0}", "php_versions": "{1}" }'
jobs:

View File

@@ -1,148 +1,5 @@
# Changelog
## [v2.0.0-beta.2](https://github.com/flarum/framework/compare/v2.0.0-beta.1...v2.0.0-beta.2)
### Fixed
- (em) incorrect extension compatibility check [#4155]
- (webpack) produces incorrect ext namespace (a7d584f8e1ec650035dafd660a70586d1d0d6bb9)
- bad modal alert text alignment [#4152]
- beta.1 early bugs (a81d13e26c1c2191859493de2ad45a515ad07b90)
- code split fails with common module [#4151]
- composer no longer autofocusing [#4149]
- conditional renders 0 (1cd644d27feb4eeea5cbaedd009a3af2643af396)
- custom styles from 1.x can crash the app [#4159]
- discussion page renders before loading is finished [#4158]
- discussion posts not always properly loaded [#4156]
- fixed side nav missing top spacing [#4147]
- invisible dropdown text when header is colored (958dec594486cbc14cf8f922db324a8ffc0245e3)
- lazy module import always returns default module [#4148]
- mistakenly removed code (33121ed1cc260bf967f0b8c4d10ab5099410bac0)
- select input cuts off [#4157]
- tag selection icon alignment [#4153]
- unexpected subscription breaks rendering [#4150]
- use correct human time format key [#4154]
### Changed
- (mentions) only access related mentions if loaded (9fe17b3c24c5b9236e419a00c1230b2994b8c009)
- extensibility improvements (00426c85e38efc91554af33644b088e72b3b3c1b)
## [v2.0.0-beta.1](https://github.com/flarum/framework/compare/v1.8.9...v2.0.0-beta.1)
### Changed
- php 8.4 [#4103]
- JSON:API refactor [#3971]
- (mentions) allow renderer to be used without context [#3954]
- (flags) add pagination to flags list [#3931]
- (mentions) add integration test for reply approval notification [#3748]
- (mentions,emoji) tie autocomplete to editor instance [#3913]
- (phpstan) upgrade to be compatible with latest dependency updates [#3835]
- (tags) prevent loading tag state if loaded previously [#4009]
- (testing) run flarum/testing packages tests back again [#3844]
- Do not catch exceptions when testing Console commands [#3813]
- Patch vulnerability advisory [#3966]
- Search box improvements on tablet devices [#4076]
- Test using MySQL 8.1 [#3870]
- Upgrade dependencies [#3830], [#4012]
- Upgrade `intervention/image` to 3.2 [#3947]
- Upgrade Wikimedia/less.php to 4.1 [#3837]
- Upgrade Mithril to 2.2 [#3831]
- (tags) Wrong tag input width if contains CJK characters [#4127]
- allow custom actions runner to be defined [#3988]
- avoid using `.fa()` mixins and `@fa-var` vars [#3912]
- cleanup composer deps (40dcaf882cd017463ca792762d4aa11de8c5c7da)
- corrected typos in routes comments [#3840]
- extract `FormModal` from `Modal` [#3922]
- extract `buildSettingComponent` method into a `FormGroup` component [#3927]
- fix typos [#4021]
- function names (d15438846895a5cf7b5a584479ef63a6e3119925)
- handle deprecations from 1.x [#3909]
- ignore deprecation errors in prod [#4072]
- improve debugging experience [#3944]
- improve test suite [#3814]
- increase phpstan level to 6 [#3836]
- `HeaderPrimary.js` converted to typescript [#4052]
- merge the app with the container & implement the ApplicationContract [#3862]
- recover bundlewatch [#3829]
- remove ExtenderInterface[] as a conditional option, only support callable or ::class invoke [#3904]
- remove listing of posts in the show discussion endpoint [#4067]
- remove unused vars in catch [#3839]
- simplify if else conditions [#3843]
- simplify variable assignment using null coalescing operator [#4000]
- support composer auth in workflows [#3961]
- switch formatter to `format-message` [#4088]
- transpile js to es6 [#3699]
- unify frontend initializers naming [#4003]
- update FontAwesome v6 icon search link [#4036]
- use `::class` syntax to fetch class name instead of `get_class()` function [#3910]
- use `hex_color` rule for color validation [#3936]
- use `str_contains` instead of `strpos` [#3841]
- graceful failure from extend/override errors [#4134]
### Fixed
- (a11y) convert empty links to buttons [#3926]
- (approval) `PostWasApproved` event triggered incorrectly [#3930]
- (em) prevent use if missing php functions (94b0d67a4020e1b7027e0df53dee1d681dc822e1)
- (em) production ready check (f6e84a0dc576d1cfe8539b7438244edf156e3b1a)
- (testing) use cookie for testing authentication [#3924]
- 3 char hex color is incorrectly modified to 6 [#4013]
- Add conditional rendering for email status in MailPage.tsx [#3997]
- Logout controller allows open redirects [#3948], [#4091]
- allow use of an attribute named `relationships` (1ead69e9b66ae9bc335be663498b7ea706adbf73)
- cannot install without db prefix [#4001]
- change length of email field [#4118]
- color input changes while typing [#3919]
- console extender does not accept `::class` attribute for schedule [#3903]
- default labels with `SettingDropdown` and `SelectDropdown` [#3854]
- duplicated `mentionsUsers` in extend.php (2b56129d70d18686a73d044ff65b418eef83f388)
- handled API errors break preloaded content [#3920]
- improve the flarum validator [#4133]
- installation command config path can be null (07623afacde590c45a20537add3b72a919050819)
- larastan changed namespace [#3955]
- larastan changes frequently (af2a32a3a4f50874c63785f5168e1df60f947553)
- load event mentioned tags on show discussion endpoint [#3915]
- move `UserSearchResult` to common (35f76bce60361caac8001c41c421de30f567b221)
- notify for all posts switch field loading state [#3938]
- only set actor on events that have it [#3914]
- overflowing forum stats [#3940]
- paginated list limit hard to change [#3918]
- prevent wiping out existing database on install [#4092]
- reset save button state when an error occurs in admin page [#4010]
- usage of `aria-hidden=false` might cause inconsistent behavior [#4074]
- use dynamic viewport units for height of Modals [#3951]
- user pages history not registered [#3916]
- validate required cli install args [#4093]
- make `WelcomeHero` extensible [#3848]
- Update the scheduler info link in admin (#3826)
### Added
- Export Registry [#3842]
- Code Splitting [#3860]
- Fontawesome v6 [#4020]
- extension bisect [#3980]
- extension list UI [#4066]
- admin search UI [#4022]
- add support for `PgSQL` [#3985]
- add support for `SQLite` [#3984]
- separate `MariaDB` driver [#4132]
- advanced maintenance modes [#3977]
- notification unsubscribe links [#3872]
- email overhaul with HTML multipart [#3872]
- date time formats from locales [#4029]
- messages extension [#4028]
- search drivers (revamp search system) [#3893]
- search UI/UX revamp [#3941]
- post search adapted with global search [#4019]
- vanilla CSS color scheme changes [#3996]
- (emoji) allow the user to set the CDN address [#3908]
- (nicknames) allow OAuth to provide a nickname [#4004]
- (sticky) make excerpt optional in sticky [#4016]
- JS `Notification` extender [#3974]
- add `whenExtensionDisabled` to `Conditional` extender [#3847]
- add option for filtering read stickied on all discussions page [#4073]
- allow resetting settings to default [#3935]
- define `FLARUM_START` constant [#4082]
- dispatch event to `flarum/installation-packages` on release [#3625]
- eloquent factories (primarily for tests) [#3982]
- frontend content flexible order priorities [#3765]
- improve emoji autocomplete [#3923]
- recover support for ico favicon [#4126]
- theming and extensibility improvements [#3876]
## [v1.8.1](https://github.com/flarum/framework/compare/v1.8.0...v1.8.1)
### Fixed
* recover temporary solution for html entities in browser title (e72541e35de4f71f9d870bbd9bb46ddf586bdf1d)
@@ -613,7 +470,7 @@ looks rather complex and messy compared to the full list of changes made for thi
- Pass filter params to getApiDocument (https://github.com/flarum/framework/pull/3037)
- Use author filter instead of gambit to get a user's discussions (https://github.com/flarum/framework/pull/3068)
- [A11Y] Accessibility improvements for the Search component (https://github.com/flarum/framework/pull/3017)
- Add determinism to extension order resolution (https://github.com/flarum/framework/pull/3076)
- Add determinsm to extension order resolution (https://github.com/flarum/framework/pull/3076)
- Add cache control headers to the admin area (https://github.com/flarum/framework/pull/3097)
### Fixed

View File

@@ -1,5 +1,5 @@
<p align="center">
<a href="https://flarum.org/"><img src="https://flarum.org/images/flarum.svg"></a>
<a href="https://flarum.org/"><img src="https://flarum.org/assets/img/logo.png"></a>
</p>
<p align="center">
@@ -7,6 +7,7 @@
<a href="https://packagist.org/packages/flarum/core"><img src="https://img.shields.io/packagist/dt/flarum/core" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/flarum/core"><img src="https://img.shields.io/github/v/release/flarum/core?sort=semver" alt="Latest Version"></a>
<a href="https://packagist.org/packages/flarum/core"><img src="https://img.shields.io/packagist/l/flarum/core" alt="License"></a>
<a href="https://huntr.dev/bounties/disclose/?target=https://github.com/flarum/core"><img src="https://cdn.huntr.dev/huntr_security_badge_mono.svg" alt="huntr"></a>
<a href="https://github.styleci.io/repos/28257573"><img src="https://github.styleci.io/repos/28257573/shield?style=flat" alt="StyleCI"></a>
</p>
@@ -20,7 +21,7 @@
* **Powerful and extensible.** Customize, extend, and integrate Flarum to suit your community. Flarums architecture is amazingly flexible, with a powerful Extension API.
![Screenshot of a Flarum instance, showing multiple discussions and tags.](https://flarum.org/assets/flarum/home-screenshot.png)
![Screenshot of a Flarum instance, showing multiple discussions and tags.](https://flarum.org/assets/img/home-screenshot.png)
## Installation

View File

@@ -1,16 +0,0 @@
#!/bin/bash
MONOREPO_TEST="framework/core extensions/akismet extensions/approval extensions/flags extensions/likes extensions/mentions extensions/nicknames extensions/statistics extensions/sticky extensions/subscriptions extensions/suspend extensions/tags extensions/messages php-packages/testing/tests"
for test in $MONOREPO_TEST; do
echo ""
echo "===> Testing $test"
echo ""
# composer test:setup --working-dir=$test
composer test --working-dir=$test
echo ""
echo "===> Done testing $test"
echo ""
done

View File

@@ -53,7 +53,6 @@
"Flarum\\Subscriptions\\": "extensions/subscriptions/src",
"Flarum\\Suspend\\": "extensions/suspend/src",
"Flarum\\Tags\\": "extensions/tags/src",
"Flarum\\Messages\\": "extensions/messages/src",
"Flarum\\PHPStan\\": "php-packages/phpstan/src",
"Flarum\\Testing\\": "php-packages/testing/src"
},
@@ -78,7 +77,6 @@
"Flarum\\Subscriptions\\Tests\\": "extensions/subscriptions/tests",
"Flarum\\Suspend\\Tests\\": "extensions/suspend/tests",
"Flarum\\Tags\\Tests\\": "extensions/tags/tests",
"Flarum\\Messages\\Tests\\": "extensions/messages/tests",
"Flarum\\Testing\\Tests\\": "php-packages/testing/tests"
}
},
@@ -103,38 +101,35 @@
"flarum/subscriptions": "self.version",
"flarum/suspend": "self.version",
"flarum/tags": "self.version",
"flarum/messages": "self.version",
"flarum/phpstan": "self.version",
"flarum/testing": "self.version"
},
"require": {
"php": "^8.2",
"php": "^8.1",
"ext-json": "*",
"components/font-awesome": "^6.5.2",
"composer/composer": "^2.7",
"components/font-awesome": "^5.15.0",
"composer/composer": "^2.0",
"dflydev/fig-cookies": "^3.0",
"doctrine/dbal": "^3.6.2",
"dragonmantank/cron-expression": "^3.3",
"fakerphp/faker": "^1.9.1",
"flarum/json-api-server": "^0.1.0",
"franzl/whoops-middleware": "2.0",
"guzzlehttp/guzzle": "*",
"illuminate/bus": "^11.0",
"illuminate/cache": "^11.0",
"illuminate/config": "^11.0",
"illuminate/console": "^11.0",
"illuminate/container": "^11.0",
"illuminate/contracts": "^11.0",
"illuminate/database": "^11.0",
"illuminate/events": "^11.0",
"illuminate/filesystem": "^11.0",
"illuminate/hashing": "^11.0",
"illuminate/mail": "^11.0",
"illuminate/queue": "^11.0",
"illuminate/session": "^11.0",
"illuminate/support": "^11.0",
"illuminate/validation": "^11.0",
"illuminate/view": "^11.0",
"illuminate/bus": "^10.0",
"illuminate/cache": "^10.0",
"illuminate/config": "^10.0",
"illuminate/console": "^10.0",
"illuminate/container": "^10.0",
"illuminate/contracts": "^10.0",
"illuminate/database": "^10.0",
"illuminate/events": "^10.0",
"illuminate/filesystem": "^10.0",
"illuminate/hashing": "^10.0",
"illuminate/mail": "^10.0",
"illuminate/queue": "^10.0",
"illuminate/session": "^10.0",
"illuminate/support": "^10.0",
"illuminate/validation": "^10.0",
"illuminate/view": "^10.0",
"intervention/image": "^3.2",
"jenssegers/agent": "^2.6",
"laminas/laminas-diactoros": "^3.0",
@@ -147,33 +142,34 @@
"middlewares/base-path-router": "^2.0.1",
"middlewares/request-handler": "^2.0.2",
"monolog/monolog": "^3.3",
"nesbot/carbon": "^3.0",
"nesbot/carbon": "^2.66",
"nikic/fast-route": "^1.3",
"psr/http-message": "^1.1",
"psr/http-server-handler": "^1.0.2",
"psr/http-server-middleware": "^1.0.2",
"pusher/pusher-php-server": "^7.2",
"s9e/text-formatter": "^2.13",
"staudenmeir/eloquent-eager-limit": "^1.8.2",
"sycho/json-api": "^0.5.0",
"sycho/sourcemap": "^2.0.0",
"symfony/config": "^7.0",
"symfony/console": "^7.0",
"symfony/event-dispatcher": "^7.0",
"symfony/http-client": "^7.0",
"symfony/mailgun-mailer": "^7.0",
"symfony/mime": "^7.0",
"symfony/config": "^6.3",
"symfony/console": "^6.3",
"symfony/event-dispatcher": "^6.3",
"symfony/http-client": "^6.3",
"symfony/mailgun-mailer": "^6.3",
"symfony/mime": "^6.3",
"symfony/polyfill-intl-messageformatter": "^1.27",
"symfony/postmark-mailer": "^7.0",
"symfony/translation": "^7.0",
"symfony/yaml": "^7.0",
"symfony/postmark-mailer": "^6.3",
"symfony/translation": "^6.3",
"symfony/yaml": "^6.3",
"wikimedia/less.php": "^4.1"
},
"require-dev": {
"mockery/mockery": "^1.5",
"phpunit/phpunit": "^11.0",
"phpunit/phpunit": "^9.0",
"phpstan/phpstan": "^1.10.0",
"larastan/larastan": "2.9.14",
"symfony/var-dumper": "^7.0",
"flarum/testing-tests": "*@dev"
"larastan/larastan": "^2.7",
"symfony/var-dumper": "^6.3"
},
"config": {
"sort-packages": true
@@ -200,8 +196,7 @@
"extensions/sticky",
"extensions/subscriptions",
"extensions/suspend",
"extensions/tags",
"extensions/messages"
"extensions/tags"
],
"branch-alias": {
"dev-main": "2.x-dev"
@@ -218,11 +213,5 @@
},
"scripts-descriptions": {
"analyse:phpstan": "Run static analysis"
},
"repositories": [
{
"type": "path",
"url": "php-packages/testing/tests"
}
]
}
}

View File

@@ -4,7 +4,6 @@ composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.cache
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2024 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^2.0.0-beta.2",
"flarum/core": "^2.0",
"flarum/approval": "^2.0"
},
"autoload": {

View File

@@ -1,2 +0,0 @@
declare const _default: import("flarum/common/extenders/Admin").default[];
export default _default;

View File

@@ -1 +1 @@
export { default as extend } from './extend';
export {};

View File

@@ -1,2 +1,2 @@
(()=>{var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var s in a)e.o(a,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:a[s]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};(()=>{"use strict";e.r(t),e.d(t,{extend:()=>n});const a=flarum.reg.get("core","admin/app");var s=e.n(a);const r=flarum.reg.get("core","common/extenders"),n=[(new(e.n(r)().Admin)).setting((()=>({setting:"flarum-akismet.api_key",type:"text",label:s().translator.trans("flarum-akismet.admin.akismet_settings.api_key_label")}))).setting((()=>({setting:"flarum-akismet.delete_blatant_spam",type:"boolean",label:s().translator.trans("flarum-akismet.admin.akismet_settings.delete_blatant_spam_label"),help:s().translator.trans("flarum-akismet.admin.akismet_settings.delete_blatant_spam_help")}))).permission((()=>({icon:"fas fa-vote-yea",label:s().translator.trans("flarum-akismet.admin.permissions.bypass_akismet"),permission:"bypassAkismet"})),"start")];s().initializers.add("flarum-akismet",(()=>{}))})(),module.exports=t})();
(()=>{var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var r in a)e.o(a,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:a[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};(()=>{"use strict";e.r(t);const a=flarum.reg.get("core","admin/app");var r=e.n(a);r().initializers.add("flarum-akismet",(()=>{r().extensionData.for("flarum-akismet").registerSetting({setting:"flarum-akismet.api_key",type:"text",label:r().translator.trans("flarum-akismet.admin.akismet_settings.api_key_label")}).registerSetting({setting:"flarum-akismet.delete_blatant_spam",type:"boolean",label:r().translator.trans("flarum-akismet.admin.akismet_settings.delete_blatant_spam_label"),help:r().translator.trans("flarum-akismet.admin.akismet_settings.delete_blatant_spam_help")}).registerPermission({icon:"fas fa-vote-yea",label:r().translator.trans("flarum-akismet.admin.permissions.bypass_akismet"),permission:"bypassAkismet"},"start")}))})(),module.exports=t})();
//# sourceMappingURL=admin.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,IACzBH,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,qDCL9D,MAAM,EAA+BC,OAAOC,IAAIV,IAAI,OAAQ,a,aCA5D,MAAM,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,oBCE5D,IAAgB,I,MAAI,WAAeW,SAAQ,KAAM,CAC/CA,QAAS,yBACTC,KAAM,OACNC,MAAO,eAAeC,MAAM,2DAC1BH,SAAQ,KAAM,CAEhBA,QAAS,qCACTC,KAAM,UACNC,MAAO,eAAeC,MAAM,mEAC5BC,KAAM,eAAeD,MAAM,sEACzBE,YAAW,KAAM,CACnBC,KAAM,kBACNJ,MAAO,eAAeC,MAAM,mDAC5BE,WAAY,mBACV,UCdJ,iBAAiBE,IAAI,kBAAkB,Q","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.reg.get('core', 'admin/app')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', 'common/extenders')\"","webpack://@flarum/akismet/./src/admin/extend.tsx","webpack://@flarum/akismet/./src/admin/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.reg.get('core', 'admin/app');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'common/extenders');","import Extend from 'flarum/common/extenders';\nimport app from 'flarum/admin/app';\nexport default [new Extend.Admin().setting(() => ({\n setting: 'flarum-akismet.api_key',\n type: 'text',\n label: app.translator.trans('flarum-akismet.admin.akismet_settings.api_key_label')\n})).setting(() => ({\n // https://blog.akismet.com/2014/04/23/theres-a-ninja-in-your-akismet/\n setting: 'flarum-akismet.delete_blatant_spam',\n type: 'boolean',\n label: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_label'),\n help: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_help')\n})).permission(() => ({\n icon: 'fas fa-vote-yea',\n label: app.translator.trans('flarum-akismet.admin.permissions.bypass_akismet'),\n permission: 'bypassAkismet'\n}), 'start')];","import app from 'flarum/admin/app';\nexport { default as extend } from './extend';\napp.initializers.add('flarum-akismet', () => {\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","reg","setting","type","label","trans","help","permission","icon","add"],"sourceRoot":""}
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,IACzBH,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,IAAIV,IAAI,OAAQ,a,aCC5D,qBAAqB,kBAAkB,KACrC,sBAAsB,kBAAkBW,gBAAgB,CACtDC,QAAS,yBACTC,KAAM,OACNC,MAAO,qBAAqB,yDAC3BH,gBAAgB,CAEjBC,QAAS,qCACTC,KAAM,UACNC,MAAO,qBAAqB,mEAC5BC,KAAM,qBAAqB,oEAC1BC,mBAAmB,CACpBC,KAAM,kBACNH,MAAO,qBAAqB,mDAC5BI,WAAY,iBACX,QAAQ,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.reg.get('core', 'admin/app')\"","webpack://@flarum/akismet/./src/admin/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.reg.get('core', 'admin/app');","import app from 'flarum/admin/app';\napp.initializers.add('flarum-akismet', () => {\n app.extensionData.for('flarum-akismet').registerSetting({\n setting: 'flarum-akismet.api_key',\n type: 'text',\n label: app.translator.trans('flarum-akismet.admin.akismet_settings.api_key_label')\n }).registerSetting({\n //https://blog.akismet.com/2014/04/23/theres-a-ninja-in-your-akismet/\n setting: 'flarum-akismet.delete_blatant_spam',\n type: 'boolean',\n label: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_label'),\n help: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_help')\n }).registerPermission({\n icon: 'fas fa-vote-yea',\n label: app.translator.trans('flarum-akismet.admin.permissions.bypass_akismet'),\n permission: 'bypassAkismet'\n }, 'start');\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","reg","registerSetting","setting","type","label","help","registerPermission","icon","permission"],"sourceRoot":""}

View File

@@ -1,2 +1,2 @@
(()=>{var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};(()=>{"use strict";const t=flarum.reg.get("core","common/extend"),r=flarum.reg.get("core","forum/app");var o=e.n(r);const a=flarum.reg.get("core","forum/utils/PostControls");var n=e.n(a);const s=flarum.reg.get("core","forum/components/Post");var m=e.n(s);o().initializers.add("flarum-akismet",(()=>{(0,t.extend)(n(),"destructiveControls",(function(e,t){if(e.has("approve")){const r=t.flags();if(r&&r.some((e=>"akismet"===e?.type()))){const t=e.get("approve");t&&"object"==typeof t&&"children"in t&&(t.children=o().translator.trans("flarum-akismet.forum.post.not_spam_button"))}}})),(0,t.override)(m().prototype,"flagReason",(function(e,t){return"akismet"===t.type()?o().translator.trans("flarum-akismet.forum.post.akismet_flagged_text"):e(t)}))}))})(),module.exports={}})();
(()=>{var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};(()=>{"use strict";e.r(t);const r=flarum.reg.get("core","common/extend"),o=flarum.reg.get("core","forum/app");var a=e.n(o);const n=flarum.reg.get("core","forum/utils/PostControls");var s=e.n(n);const l=flarum.reg.get("core","forum/components/Post");var u=e.n(l);a().initializers.add("flarum-akismet",(()=>{(0,r.extend)(s(),"destructiveControls",(function(e,t){if(e.has("approve")){const r=t.flags();if(r&&r.some((e=>"akismet"===(null==e?void 0:e.type())))){const t=e.get("approve");t&&"object"==typeof t&&"children"in t&&(t.children=a().translator.trans("flarum-akismet.forum.post.not_spam_button"))}}})),(0,r.override)(u().prototype,"flagReason",(function(e,t){return"akismet"===t.type()?a().translator.trans("flarum-akismet.forum.post.akismet_flagged_text"):e(t)}))}))})(),module.exports=t})();
//# 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,I,mBCAlF,MAAM,EAA+BI,OAAOC,IAAIP,IAAI,OAAQ,iBCAtD,EAA+BM,OAAOC,IAAIP,IAAI,OAAQ,a,aCA5D,MAAM,EAA+BM,OAAOC,IAAIP,IAAI,OAAQ,4B,aCA5D,MAAM,EAA+BM,OAAOC,IAAIP,IAAI,OAAQ,yB,aCI5D,iBAAiBQ,IAAI,kBAAkB,MACrC,IAAAC,QAAO,IAAc,uBAAuB,SAAUC,EAAOC,GAC3D,GAAID,EAAME,IAAI,WAAY,CACxB,MAAMC,EAAQF,EAAKE,QACnB,GAAIA,GAASA,EAAMC,MAAKC,GAAyB,YAAjBA,GAAMC,SAAuB,CAC3D,MAAMC,EAAcP,EAAMV,IAAI,WAC1BiB,GAAsC,iBAAhBA,GAA4B,aAAcA,IAClEA,EAAYC,SAAW,eAAeC,MAAM,6CAEhD,CACF,CACF,KACA,IAAAC,UAAS,cAAyB,cAAc,SAAUC,EAAUN,GAClE,MAAoB,YAAhBA,EAAKC,OACA,eAAeG,MAAM,kDAEvBE,EAASN,EAClB,GAAE,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/external root \"flarum.reg.get('core', 'common/extend')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', 'forum/app')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', 'forum/utils/PostControls')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', '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))","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'common/extend');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'forum/app');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'forum/utils/PostControls');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'forum/components/Post');","import { extend, override } from 'flarum/common/extend';\nimport app from 'flarum/forum/app';\nimport PostControls from 'flarum/forum/utils/PostControls';\nimport PostComponent from 'flarum/forum/components/Post';\napp.initializers.add('flarum-akismet', () => {\n extend(PostControls, 'destructiveControls', function (items, post) {\n if (items.has('approve')) {\n const flags = post.flags();\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 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 return original(flag);\n });\n});"],"names":["__webpack_require__","module","getter","__esModule","d","a","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","flarum","reg","add","extend","items","post","has","flags","some","flag","type","approveItem","children","trans","override","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,IAAIV,IAAI,OAAQ,iBCAtD,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,a,aCA5D,MAAM,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,4B,aCA5D,MAAM,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,yB,aCI5D,qBAAqB,kBAAkB,MACrC,IAAAW,QAAO,IAAc,uBAAuB,SAAUC,EAAOC,GAC3D,GAAID,EAAME,IAAI,WAAY,CACxB,MAAMC,EAAQF,EAAKE,QACnB,GAAIA,GAASA,EAAMC,MAAKC,GAAkD,aAAjC,MAARA,OAAe,EAASA,EAAKC,UAAwB,CACpF,MAAMC,EAAcP,EAAMZ,IAAI,WAC1BmB,GAAsC,iBAAhBA,GAA4B,aAAcA,IAClEA,EAAYC,SAAW,qBAAqB,6CAEhD,CACF,CACF,KACA,IAAAC,UAAS,cAAyB,cAAc,SAAUC,EAAUL,GAClE,MAAoB,YAAhBA,EAAKC,OACA,qBAAqB,kDAEvBI,EAASL,EAClB,GAAE,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.reg.get('core', 'common/extend')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', 'forum/app')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', 'forum/utils/PostControls')\"","webpack://@flarum/akismet/external root \"flarum.reg.get('core', '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.reg.get('core', 'common/extend');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'forum/app');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'forum/utils/PostControls');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'forum/components/Post');","import { extend, override } from 'flarum/common/extend';\nimport app from 'flarum/forum/app';\nimport PostControls from 'flarum/forum/utils/PostControls';\nimport PostComponent from 'flarum/forum/components/Post';\napp.initializers.add('flarum-akismet', () => {\n extend(PostControls, 'destructiveControls', function (items, post) {\n if (items.has('approve')) {\n const flags = post.flags();\n if (flags && flags.some(flag => (flag == null ? void 0 : 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 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 return original(flag);\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","reg","extend","items","post","has","flags","some","flag","type","approveItem","children","override","original"],"sourceRoot":""}

View File

@@ -17,9 +17,9 @@
},
"devDependencies": {
"@flarum/prettier-config": "^1.0.0",
"flarum-tsconfig": "^2.0.0",
"flarum-tsconfig": "^1.0.2",
"prettier": "^2.5.1",
"flarum-webpack-config": "^3.0.0",
"flarum-webpack-config": "^2.0.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.9.1",
"typescript": "^4.5.4",

View File

@@ -1,26 +0,0 @@
import Extend from 'flarum/common/extenders';
import app from 'flarum/admin/app';
export default [
new Extend.Admin()
.setting(() => ({
setting: 'flarum-akismet.api_key',
type: 'text',
label: app.translator.trans('flarum-akismet.admin.akismet_settings.api_key_label'),
}))
.setting(() => ({
// https://blog.akismet.com/2014/04/23/theres-a-ninja-in-your-akismet/
setting: 'flarum-akismet.delete_blatant_spam',
type: 'boolean',
label: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_label'),
help: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_help'),
}))
.permission(
() => ({
icon: 'fas fa-vote-yea',
label: app.translator.trans('flarum-akismet.admin.permissions.bypass_akismet'),
permission: 'bypassAkismet',
}),
'start'
),
];

View File

@@ -1,7 +1,26 @@
import app from 'flarum/admin/app';
export { default as extend } from './extend';
app.initializers.add('flarum-akismet', () => {
// ...
app.extensionData
.for('flarum-akismet')
.registerSetting({
setting: 'flarum-akismet.api_key',
type: 'text',
label: app.translator.trans('flarum-akismet.admin.akismet_settings.api_key_label'),
})
.registerSetting({
//https://blog.akismet.com/2014/04/23/theres-a-ninja-in-your-akismet/
setting: 'flarum-akismet.delete_blatant_spam',
type: 'boolean',
label: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_label'),
help: app.translator.trans('flarum-akismet.admin.akismet_settings.delete_blatant_spam_help'),
})
.registerPermission(
{
icon: 'fas fa-vote-yea',
label: app.translator.trans('flarum-akismet.admin.permissions.bypass_akismet'),
permission: 'bypassAkismet',
},
'start'
);
});

View File

@@ -1,20 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false"
bootstrap="../../../php-packages/testing/bootstrap/monorepo.php"
>
<source>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src/</directory>
</include>
</source>
</coverage>
<testsuites>
<testsuite name="Flarum Integration Tests">
<directory suffix="Test.php">./integration</directory>

View File

@@ -1,23 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="../../../php-packages/testing/bootstrap/monorepo.php"
>
<source>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src/</directory>
</include>
</source>
</coverage>
<testsuites>
<testsuite name="Flarum Unit Tests">
<directory suffix="Test.php">./unit</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener" />
</listeners>
</phpunit>

View File

@@ -4,7 +4,6 @@ composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.cache
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2024 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^2.0.0-beta.2",
"flarum/core": "^2.0",
"flarum/flags": "^2.0"
},
"autoload": {

View File

@@ -7,10 +7,9 @@
* LICENSE file that was distributed with this source code.
*/
use Flarum\Api\Resource;
use Flarum\Api\Schema;
use Flarum\Api\Serializer\BasicDiscussionSerializer;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Approval\Access;
use Flarum\Approval\Api\PostResourceFields;
use Flarum\Approval\Event\PostWasApproved;
use Flarum\Approval\Listener;
use Flarum\Discussion\Discussion;
@@ -37,13 +36,17 @@ return [
->default('is_approved', true)
->cast('is_approved', 'bool'),
(new Extend\ApiResource(Resource\DiscussionResource::class))
->fields(fn () => [
Schema\Boolean::make('isApproved'),
]),
(new Extend\ApiSerializer(BasicDiscussionSerializer::class))
->attribute('isApproved', function (BasicDiscussionSerializer $serializer, Discussion $discussion): bool {
return $discussion->is_approved;
}),
(new Extend\ApiResource(Resource\PostResource::class))
->fields(PostResourceFields::class),
(new Extend\ApiSerializer(PostSerializer::class))
->attribute('isApproved', function ($serializer, Post $post) {
return (bool) $post->is_approved;
})->attribute('canApprove', function (PostSerializer $serializer, Post $post) {
return (bool) $serializer->getActor()->can('approvePosts', $post->discussion);
}),
new Extend\Locales(__DIR__.'/locale'),

View File

@@ -1 +0,0 @@
export * from './src/admin';

View File

@@ -1,2 +1,2 @@
(()=>{var e={n:r=>{var s=r&&r.__esModule?()=>r.default:()=>r;return e.d(s,{a:s}),s},d:(r,s)=>{for(var o in s)e.o(s,o)&&!e.o(r,o)&&Object.defineProperty(r,o,{enumerable:!0,get:s[o]})},o:(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},r={};(()=>{"use strict";e.r(r),e.d(r,{extend:()=>i});const s=flarum.reg.get("core","common/extend"),o=flarum.reg.get("core","admin/app");var a=e.n(o);const t=flarum.reg.get("core","common/extenders"),i=[(new(e.n(t)().Admin)).permission((()=>({icon:"fas fa-check",label:a().translator.trans("flarum-approval.admin.permissions.start_discussions_without_approval_label"),permission:"discussion.startWithoutApproval"})),"start",95).permission((()=>({icon:"fas fa-check",label:a().translator.trans("flarum-approval.admin.permissions.reply_without_approval_label"),permission:"discussion.replyWithoutApproval"})),"reply",95).permission((()=>({icon:"fas fa-check",label:a().translator.trans("flarum-approval.admin.permissions.approve_posts_label"),permission:"discussion.approvePosts"})),"moderate",65)];a().initializers.add("flarum-approval",(()=>{(0,s.extend)(a(),"getRequiredPermissions",(function(e,r){"discussion.startWithoutApproval"===r&&e.push("startDiscussion"),"discussion.replyWithoutApproval"===r&&e.push("discussion.reply")}))}))})(),module.exports=r})();
(()=>{var r={n:e=>{var s=e&&e.__esModule?()=>e.default:()=>e;return r.d(s,{a:s}),s},d:(e,s)=>{for(var a in s)r.o(s,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:s[a]})},o:(r,e)=>Object.prototype.hasOwnProperty.call(r,e),r:r=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})}},e={};(()=>{"use strict";r.r(e);const s=flarum.reg.get("core","common/extend"),a=flarum.reg.get("core","admin/app");var o=r.n(a);o().initializers.add("flarum-approval",(()=>{(0,s.extend)(o(),"getRequiredPermissions",(function(r,e){"discussion.startWithoutApproval"===e&&r.push("startDiscussion"),"discussion.replyWithoutApproval"===e&&r.push("discussion.reply")})),o().extensionData.for("flarum-approval").registerPermission({icon:"fas fa-check",label:o().translator.trans("flarum-approval.admin.permissions.start_discussions_without_approval_label"),permission:"discussion.startWithoutApproval"},"start",95).registerPermission({icon:"fas fa-check",label:o().translator.trans("flarum-approval.admin.permissions.reply_without_approval_label"),permission:"discussion.replyWithoutApproval"},"reply",95).registerPermission({icon:"fas fa-check",label:o().translator.trans("flarum-approval.admin.permissions.approve_posts_label"),permission:"discussion.approvePosts"},"moderate",65)}))})(),module.exports=e})();
//# sourceMappingURL=admin.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,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,qDCL9D,MAAM,EAA+BC,OAAOC,IAAIV,IAAI,OAAQ,iBCAtD,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,a,aCA5D,MAAM,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,oBCE5D,IAAgB,I,MAAI,WAAeW,YAAW,KAAM,CAClDC,KAAM,eACNC,MAAO,eAAeC,MAAM,8EAC5BH,WAAY,qCACV,QAAS,IAAIA,YAAW,KAAM,CAChCC,KAAM,eACNC,MAAO,eAAeC,MAAM,kEAC5BH,WAAY,qCACV,QAAS,IAAIA,YAAW,KAAM,CAChCC,KAAM,eACNC,MAAO,eAAeC,MAAM,yDAC5BH,WAAY,6BACV,WAAY,KCXhB,iBAAiBI,IAAI,mBAAmB,MACtC,IAAAC,QAAO,IAAK,0BAA0B,SAAUC,EAAUN,GACrC,oCAAfA,GACFM,EAASC,KAAK,mBAEG,oCAAfP,GACFM,EAASC,KAAK,mBAElB,GAAE,G","sources":["webpack://@flarum/approval/webpack/bootstrap","webpack://@flarum/approval/webpack/runtime/compat get default export","webpack://@flarum/approval/webpack/runtime/define property getters","webpack://@flarum/approval/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/approval/webpack/runtime/make namespace object","webpack://@flarum/approval/external root \"flarum.reg.get('core', 'common/extend')\"","webpack://@flarum/approval/external root \"flarum.reg.get('core', 'admin/app')\"","webpack://@flarum/approval/external root \"flarum.reg.get('core', 'common/extenders')\"","webpack://@flarum/approval/./src/admin/extend.tsx","webpack://@flarum/approval/./src/admin/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.reg.get('core', 'common/extend');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'admin/app');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'common/extenders');","import Extend from 'flarum/common/extenders';\nimport app from 'flarum/admin/app';\nexport default [new Extend.Admin().permission(() => ({\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),\n permission: 'discussion.startWithoutApproval'\n}), 'start', 95).permission(() => ({\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),\n permission: 'discussion.replyWithoutApproval'\n}), 'reply', 95).permission(() => ({\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),\n permission: 'discussion.approvePosts'\n}), 'moderate', 65)];","import { extend } from 'flarum/common/extend';\nimport app from 'flarum/admin/app';\nexport { default as extend } from './extend';\napp.initializers.add('flarum-approval', () => {\n extend(app, 'getRequiredPermissions', function (required, permission) {\n if (permission === 'discussion.startWithoutApproval') {\n required.push('startDiscussion');\n }\n if (permission === 'discussion.replyWithoutApproval') {\n required.push('discussion.reply');\n }\n });\n});"],"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","reg","permission","icon","label","trans","add","extend","required","push"],"sourceRoot":""}
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,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,IAAIV,IAAI,OAAQ,iBCAtD,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,a,aCE5D,qBAAqB,mBAAmB,MACtC,IAAAW,QAAO,IAAK,0BAA0B,SAAUC,EAAUC,GACrC,oCAAfA,GACFD,EAASE,KAAK,mBAEG,oCAAfD,GACFD,EAASE,KAAK,mBAElB,IACA,sBAAsB,mBAAmBC,mBAAmB,CAC1DC,KAAM,eACNC,MAAO,qBAAqB,8EAC5BJ,WAAY,mCACX,QAAS,IAAIE,mBAAmB,CACjCC,KAAM,eACNC,MAAO,qBAAqB,kEAC5BJ,WAAY,mCACX,QAAS,IAAIE,mBAAmB,CACjCC,KAAM,eACNC,MAAO,qBAAqB,yDAC5BJ,WAAY,2BACX,WAAY,GAAG,G","sources":["webpack://@flarum/approval/webpack/bootstrap","webpack://@flarum/approval/webpack/runtime/compat get default export","webpack://@flarum/approval/webpack/runtime/define property getters","webpack://@flarum/approval/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/approval/webpack/runtime/make namespace object","webpack://@flarum/approval/external root \"flarum.reg.get('core', 'common/extend')\"","webpack://@flarum/approval/external root \"flarum.reg.get('core', 'admin/app')\"","webpack://@flarum/approval/./src/admin/index.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'common/extend');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'admin/app');","import { extend } from 'flarum/common/extend';\nimport app from 'flarum/admin/app';\napp.initializers.add('flarum-approval', () => {\n extend(app, 'getRequiredPermissions', function (required, permission) {\n if (permission === 'discussion.startWithoutApproval') {\n required.push('startDiscussion');\n }\n if (permission === 'discussion.replyWithoutApproval') {\n required.push('discussion.reply');\n }\n });\n app.extensionData.for('flarum-approval').registerPermission({\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),\n permission: 'discussion.startWithoutApproval'\n }, 'start', 95).registerPermission({\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),\n permission: 'discussion.replyWithoutApproval'\n }, 'reply', 95).registerPermission({\n icon: 'fas fa-check',\n label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),\n permission: 'discussion.approvePosts'\n }, 'moderate', 65);\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","reg","extend","required","permission","push","registerPermission","icon","label"],"sourceRoot":""}

View File

@@ -1,2 +1,2 @@
(()=>{var t={n:o=>{var r=o&&o.__esModule?()=>o.default:()=>o;return t.d(r,{a:r}),r},d:(o,r)=>{for(var e in r)t.o(r,e)&&!t.o(o,e)&&Object.defineProperty(o,e,{enumerable:!0,get:r[e]})},o:(t,o)=>Object.prototype.hasOwnProperty.call(t,o)};(()=>{"use strict";const o=flarum.reg.get("core","common/extend"),r=flarum.reg.get("core","forum/app");var e=t.n(r);const a=flarum.reg.get("core","common/models/Discussion");var n=t.n(a);const p=flarum.reg.get("core","common/models/Post");var s=t.n(p);const i=flarum.reg.get("core","common/components/Badge");var c=t.n(i);const u=flarum.reg.get("core","forum/components/DiscussionListItem");var l=t.n(u);const d=flarum.reg.get("core","forum/components/Post");var v=t.n(d);const f=flarum.reg.get("core","forum/components/CommentPost");var g=t.n(f);const A=flarum.reg.get("core","common/components/Button");var h=t.n(A);const b=flarum.reg.get("core","forum/utils/PostControls");var y=t.n(b);e().initializers.add("flarum-approval",(()=>{n().prototype.isApproved=n().attribute("isApproved"),(0,o.extend)(n().prototype,"badges",(function(t){this.isApproved()||t.has("hidden")||t.add("awaitingApproval",m(c(),{type:"awaitingApproval",icon:"fas fa-gavel",label:e().translator.trans("flarum-approval.forum.badge.awaiting_approval_tooltip")}))})),s().prototype.isApproved=s().attribute("isApproved"),s().prototype.canApprove=s().attribute("canApprove"),(0,o.extend)(l().prototype,"elementAttrs",(function(t){this.attrs.discussion.isApproved()||(t.className+=" DiscussionListItem--unapproved")})),(0,o.extend)(v().prototype,"elementAttrs",(function(t){this.attrs.post.isApproved()||(t.className+=" Post--unapproved")})),(0,o.extend)(g().prototype,"headerItems",(function(t){this.attrs.post.isApproved()||this.attrs.post.isHidden()||t.add("unapproved",e().translator.trans("flarum-approval.forum.post.awaiting_approval_text"))})),(0,o.override)(v().prototype,"flagReason",(function(t,o){return"approval"===o.type()?e().translator.trans("flarum-approval.forum.post.awaiting_approval_text"):t(o)})),(0,o.extend)(y(),"destructiveControls",(function(t,o){!o.isApproved()&&o.canApprove()&&t.add("approve",m(h(),{icon:"fas fa-check",onclick:y().approveAction.bind(o)},e().translator.trans("flarum-approval.forum.post_controls.approve_button")),10)})),y().approveAction=function(){this.save({isApproved:!0}),1===this.number()&&this.discussion().pushAttributes({isApproved:!0})}}),-10)})(),module.exports={}})();
(()=>{var o={n:t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return o.d(e,{a:e}),e},d:(t,e)=>{for(var r in e)o.o(e,r)&&!o.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},o:(o,t)=>Object.prototype.hasOwnProperty.call(o,t),r:o=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})}},t={};(()=>{"use strict";o.r(t);const e=flarum.reg.get("core","common/extend"),r=flarum.reg.get("core","forum/app");var a=o.n(r);const n=flarum.reg.get("core","common/models/Discussion");var p=o.n(n);const s=flarum.reg.get("core","common/models/Post");var i=o.n(s);const c=flarum.reg.get("core","common/components/Badge");var u=o.n(c);const l=flarum.reg.get("core","forum/components/DiscussionListItem");var d=o.n(l);const v=flarum.reg.get("core","forum/components/Post");var f=o.n(v);const g=flarum.reg.get("core","forum/components/CommentPost");var A=o.n(g);const y=flarum.reg.get("core","common/components/Button");var b=o.n(y);const h=flarum.reg.get("core","forum/utils/PostControls");var _=o.n(h);a().initializers.add("flarum-approval",(()=>{p().prototype.isApproved=p().attribute("isApproved"),(0,e.extend)(p().prototype,"badges",(function(o){this.isApproved()||o.has("hidden")||o.add("awaitingApproval",m(u(),{type:"awaitingApproval",icon:"fas fa-gavel",label:a().translator.trans("flarum-approval.forum.badge.awaiting_approval_tooltip")}))})),i().prototype.isApproved=i().attribute("isApproved"),i().prototype.canApprove=i().attribute("canApprove"),(0,e.extend)(d().prototype,"elementAttrs",(function(o){this.attrs.discussion.isApproved()||(o.className+=" DiscussionListItem--unapproved")})),(0,e.extend)(f().prototype,"elementAttrs",(function(o){this.attrs.post.isApproved()||(o.className+=" Post--unapproved")})),(0,e.extend)(A().prototype,"headerItems",(function(o){this.attrs.post.isApproved()||this.attrs.post.isHidden()||o.add("unapproved",a().translator.trans("flarum-approval.forum.post.awaiting_approval_text"))})),(0,e.override)(f().prototype,"flagReason",(function(o,t){return"approval"===t.type()?a().translator.trans("flarum-approval.forum.post.awaiting_approval_text"):o(t)})),(0,e.extend)(_(),"destructiveControls",(function(o,t){!t.isApproved()&&t.canApprove()&&o.add("approve",m(b(),{icon:"fas fa-check",onclick:_().approveAction.bind(t)},a().translator.trans("flarum-approval.forum.post_controls.approve_button")),10)})),_().approveAction=function(){this.save({isApproved:!0}),1===this.number()&&this.discussion().pushAttributes({isApproved:!0})}}),-10)})(),module.exports=t})();
//# sourceMappingURL=forum.js.map

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
"prettier": "@flarum/prettier-config",
"devDependencies": {
"prettier": "^2.5.1",
"flarum-webpack-config": "^3.0.0",
"flarum-webpack-config": "^2.0.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.9.1",
"@flarum/prettier-config": "^1.0.0"

View File

@@ -1,33 +1,43 @@
import Extend from 'flarum/common/extenders';
import { extend } from 'flarum/common/extend';
import app from 'flarum/admin/app';
export default [
new Extend.Admin()
.permission(
() => ({
app.initializers.add('flarum-approval', () => {
extend(app, 'getRequiredPermissions', function (required, permission) {
if (permission === 'discussion.startWithoutApproval') {
required.push('startDiscussion');
}
if (permission === 'discussion.replyWithoutApproval') {
required.push('discussion.reply');
}
});
app.extensionData
.for('flarum-approval')
.registerPermission(
{
icon: 'fas fa-check',
label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),
permission: 'discussion.startWithoutApproval',
}),
},
'start',
95
)
.permission(
() => ({
.registerPermission(
{
icon: 'fas fa-check',
label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),
permission: 'discussion.replyWithoutApproval',
}),
},
'reply',
95
)
.permission(
() => ({
.registerPermission(
{
icon: 'fas fa-check',
label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),
permission: 'discussion.approvePosts',
}),
},
'moderate',
65
),
];
);
});

View File

@@ -1,15 +0,0 @@
import { extend } from 'flarum/common/extend';
import app from 'flarum/admin/app';
export { default as extend } from './extend';
app.initializers.add('flarum-approval', () => {
extend(app, 'getRequiredPermissions', function (required, permission) {
if (permission === 'discussion.startWithoutApproval') {
required.push('startDiscussion');
}
if (permission === 'discussion.replyWithoutApproval') {
required.push('discussion.reply');
}
});
});

View File

@@ -1,15 +0,0 @@
{
// Use Flarum's tsconfig as a starting point
"extends": "flarum-tsconfig",
// This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder
// and also tells your Typescript server to read core's global typings for
// access to `dayjs` and `$` in the global namespace.
"include": ["src/**/*", "../../../*/*/js/dist-typings/@types/**/*", "@types/**/*"],
"compilerOptions": {
// This will output typings to `dist-typings`
"declarationDir": "./dist-typings",
"paths": {
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
}
}
}

View File

@@ -1,29 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Approval\Api;
use Flarum\Api\Context;
use Flarum\Api\Schema;
use Flarum\Post\Post;
class PostResourceFields
{
public function __invoke(): array
{
return [
Schema\Boolean::make('isApproved')
->writable(fn (Post $post, Context $context) => $context->getActor()->can('approve', $post))
// set by the ApproveContent listener.
->set(fn () => null),
Schema\Boolean::make('canApprove')
->get(fn (Post $post, Context $context) => $context->getActor()->can('approvePosts', $post->discussion)),
];
}
}

View File

@@ -10,23 +10,19 @@
namespace Flarum\Approval\Tests\integration;
use Carbon\Carbon;
use Flarum\Discussion\Discussion;
use Flarum\Group\Group;
use Flarum\Post\Post;
use Flarum\User\User;
trait InteractsWithUnapprovedContent
{
protected function prepareUnapprovedDatabaseContent()
{
$this->prepareDatabase([
User::class => [
'users' => [
['id' => 1, 'username' => 'Muralf', 'email' => 'muralf@machine.local', 'is_email_confirmed' => 1],
$this->normalUser(),
['id' => 3, 'username' => 'acme', 'email' => 'acme@machine.local', 'is_email_confirmed' => 1],
['id' => 4, 'username' => 'luceos', 'email' => 'luceos@machine.local', 'is_email_confirmed' => 1],
],
Discussion::class => [
'discussions' => [
['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 1, 'comment_count' => 1, 'is_approved' => 1, 'is_private' => 0],
['id' => 2, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 2, 'comment_count' => 1, 'is_approved' => 0, 'is_private' => 1],
['id' => 3, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 3, 'comment_count' => 1, 'is_approved' => 0, 'is_private' => 1],
@@ -35,7 +31,7 @@ trait InteractsWithUnapprovedContent
['id' => 6, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 6, 'comment_count' => 1, 'is_approved' => 0, 'is_private' => 1],
['id' => 7, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 7, 'comment_count' => 1, 'is_approved' => 1, 'is_private' => 0],
],
Post::class => [
'posts' => [
['id' => 1, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 1],
['id' => 2, 'discussion_id' => 2, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 1],
['id' => 3, 'discussion_id' => 3, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 1],
@@ -49,7 +45,7 @@ trait InteractsWithUnapprovedContent
['id' => 10, 'discussion_id' => 7, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 4],
['id' => 11, 'discussion_id' => 7, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 1, 'is_approved' => 0, 'number' => 5],
],
Group::class => [
'groups' => [
['id' => 4, 'name_singular' => 'Acme', 'name_plural' => 'Acme', 'is_hidden' => 0]
],
'group_user' => [
@@ -64,7 +60,7 @@ trait InteractsWithUnapprovedContent
/**
* null: Guest, 2: Normal User.
*/
public static function unallowedUsers(): array
public function unallowedUsers(): array
{
return [[null], [2]];
}
@@ -72,7 +68,7 @@ trait InteractsWithUnapprovedContent
/**
* 1: Admin, 3: Permission Given, 4: Discussions Author.
*/
public static function allowedUsers(): array
public function allowedUsers(): array
{
return [[1], [3], [4]];
}

View File

@@ -1,122 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Approval\Tests\integration\api;
use Carbon\Carbon;
use Flarum\Approval\Tests\integration\InteractsWithUnapprovedContent;
use Flarum\Discussion\Discussion;
use Flarum\Group\Group;
use Flarum\Post\Post;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
use PHPUnit\Framework\Attributes\Test;
class ApprovePostsTest extends TestCase
{
use RetrievesAuthorizedUsers;
use InteractsWithUnapprovedContent;
protected function setUp(): void
{
parent::setUp();
$this->extension('flarum-approval');
$this->prepareDatabase([
User::class => [
['id' => 1, 'username' => 'Muralf', 'email' => 'muralf@machine.local', 'is_email_confirmed' => 1],
$this->normalUser(),
['id' => 3, 'username' => 'acme', 'email' => 'acme@machine.local', 'is_email_confirmed' => 1],
['id' => 4, 'username' => 'luceos', 'email' => 'luceos@machine.local', 'is_email_confirmed' => 1],
],
Discussion::class => [
['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 1, 'comment_count' => 1, 'is_approved' => 1],
],
Post::class => [
['id' => 1, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'hidden_at' => null, 'is_approved' => 1, 'number' => 1],
['id' => 2, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'hidden_at' => null, 'is_approved' => 1, 'number' => 2],
['id' => 3, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'hidden_at' => null, 'is_approved' => 0, 'number' => 3],
['id' => 4, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'hidden_at' => Carbon::now(), 'is_approved' => 1, 'number' => 4],
['id' => 5, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'hidden_at' => null, 'is_approved' => 0, 'number' => 5],
],
Group::class => [
['id' => 4, 'name_singular' => 'Acme', 'name_plural' => 'Acme', 'is_hidden' => 0],
['id' => 5, 'name_singular' => 'Acme', 'name_plural' => 'Acme', 'is_hidden' => 0],
],
'group_user' => [
['user_id' => 3, 'group_id' => 4],
],
'group_permission' => [
['group_id' => 4, 'permission' => 'discussion.approvePosts'],
]
]);
}
#[Test]
public function can_approve_unapproved_post()
{
$response = $this->send(
$this->request('PATCH', '/api/posts/3', [
'authenticatedAs' => 3,
'json' => [
'data' => [
'attributes' => [
'isApproved' => true
]
]
]
])
);
$this->assertEquals(200, $response->getStatusCode(), $response->getBody()->getContents());
$this->assertEquals(1, $this->database()->table('posts')->where('id', 3)->where('is_approved', 1)->count());
}
#[Test]
public function cannot_approve_post_without_permission()
{
$response = $this->send(
$this->request('PATCH', '/api/posts/3', [
'authenticatedAs' => 4,
'json' => [
'data' => [
'attributes' => [
'isApproved' => true
]
]
]
])
);
$this->assertEquals(403, $response->getStatusCode(), $response->getBody()->getContents());
$this->assertEquals(0, $this->database()->table('posts')->where('id', 3)->where('is_approved', 1)->count());
}
#[Test]
public function hiding_post_silently_approves_it()
{
$response = $this->send(
$this->request('PATCH', '/api/posts/5', [
'authenticatedAs' => 3,
'json' => [
'data' => [
'attributes' => [
'isHidden' => true
]
]
]
])
);
$this->assertEquals(200, $response->getStatusCode(), $response->getBody()->getContents());
$this->assertEquals(1, $this->database()->table('posts')->where('id', 5)->where('is_approved', 1)->count());
}
}

View File

@@ -1,155 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Approval\Tests\integration\api;
use Carbon\Carbon;
use Flarum\Approval\Tests\integration\InteractsWithUnapprovedContent;
use Flarum\Discussion\Discussion;
use Flarum\Group\Group;
use Flarum\Post\Post;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
class CreatePostsTest extends TestCase
{
use RetrievesAuthorizedUsers;
use InteractsWithUnapprovedContent;
protected function setUp(): void
{
parent::setUp();
$this->extension('flarum-flags', 'flarum-approval');
$this->prepareDatabase([
User::class => [
['id' => 1, 'username' => 'Muralf', 'email' => 'muralf@machine.local', 'is_email_confirmed' => 1],
$this->normalUser(),
['id' => 3, 'username' => 'acme', 'email' => 'acme@machine.local', 'is_email_confirmed' => 1],
['id' => 4, 'username' => 'luceos', 'email' => 'luceos@machine.local', 'is_email_confirmed' => 1],
],
Discussion::class => [
['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 1, 'comment_count' => 1, 'is_approved' => 1],
['id' => 2, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 2, 'comment_count' => 1, 'is_approved' => 0],
['id' => 3, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 4, 'first_post_id' => 3, 'comment_count' => 1, 'is_approved' => 0],
],
Post::class => [
['id' => 1, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 1],
['id' => 2, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 2],
['id' => 3, 'discussion_id' => 1, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 3],
['id' => 4, 'discussion_id' => 2, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 1],
['id' => 5, 'discussion_id' => 2, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 2],
['id' => 6, 'discussion_id' => 2, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 3],
['id' => 7, 'discussion_id' => 3, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 1],
['id' => 8, 'discussion_id' => 3, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 1, 'number' => 2],
['id' => 9, 'discussion_id' => 3, 'user_id' => 4, 'type' => 'comment', 'content' => '<t><p>Text</p></t>', 'is_private' => 0, 'is_approved' => 0, 'number' => 3],
],
Group::class => [
['id' => 4, 'name_singular' => 'Acme', 'name_plural' => 'Acme', 'is_hidden' => 0],
['id' => 5, 'name_singular' => 'Acme', 'name_plural' => 'Acme', 'is_hidden' => 0],
],
'group_user' => [
['user_id' => 3, 'group_id' => 4],
['user_id' => 2, 'group_id' => 5],
],
'group_permission' => [
['group_id' => 4, 'permission' => 'discussion.startWithoutApproval'],
['group_id' => 5, 'permission' => 'discussion.replyWithoutApproval'],
['group_id' => Group::MEMBER_ID, 'permission' => 'postWithoutThrottle'],
]
]);
}
#[Test]
#[DataProvider('startDiscussionDataProvider')]
public function can_start_discussion_without_approval_when_allowed(int $authenticatedAs, bool $allowed)
{
$this->database()->table('group_permission')->where('group_id', Group::MEMBER_ID)->where('permission', 'discussion.startWithoutApproval')->delete();
$response = $this->send(
$this->request('POST', '/api/discussions', [
'authenticatedAs' => $authenticatedAs,
'json' => [
'data' => [
'type' => 'discussions',
'attributes' => [
'title' => 'This is a new discussion',
'content' => 'This is a new discussion',
]
]
]
])
);
$body = $response->getBody()->getContents();
$json = json_decode($body, true);
$this->assertEquals(201, $response->getStatusCode(), $body);
$this->assertEquals($allowed ? 1 : 0, $this->database()->table('discussions')->where('id', $json['data']['id'])->value('is_approved'));
}
#[Test]
#[DataProvider('replyToDiscussionDataProvider')]
public function can_reply_without_approval_when_allowed(?int $authenticatedAs, bool $allowed)
{
$this->database()->table('group_permission')->where('group_id', Group::MEMBER_ID)->where('permission', 'discussion.replyWithoutApproval')->delete();
$response = $this->send(
$this->request('POST', '/api/posts', [
'authenticatedAs' => $authenticatedAs,
'json' => [
'data' => [
'type' => 'posts',
'attributes' => [
'content' => 'This is a new reply',
],
'relationships' => [
'discussion' => [
'data' => [
'type' => 'discussions',
'id' => 1
]
]
]
]
]
])
);
$body = $response->getBody()->getContents();
$json = json_decode($body, true);
$this->assertEquals(201, $response->getStatusCode(), $body);
$this->assertEquals($allowed ? 1 : 0, $this->database()->table('posts')->where('id', $json['data']['id'])->value('is_approved'));
}
public static function startDiscussionDataProvider(): array
{
return [
'Admin' => [1, true],
'User without permission' => [2, false],
'Permission Given' => [3, true],
'Another user without permission' => [4, false],
];
}
public static function replyToDiscussionDataProvider(): array
{
return [
'Admin' => [1, true],
'User without permission' => [3, false],
'Permission Given' => [2, true],
'Another user without permission' => [4, false],
];
}
}

View File

@@ -13,8 +13,6 @@ use Flarum\Approval\Tests\integration\InteractsWithUnapprovedContent;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Illuminate\Support\Arr;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
class ListDiscussionsTest extends TestCase
{
@@ -30,8 +28,10 @@ class ListDiscussionsTest extends TestCase
$this->prepareUnapprovedDatabaseContent();
}
#[Test]
#[DataProvider('unallowedUsers')]
/**
* @dataProvider unallowedUsers
* @test
*/
public function can_only_see_approved_if_not_allowed_to_approve(?int $authenticatedAs)
{
$response = $this->send(
@@ -44,8 +44,10 @@ class ListDiscussionsTest extends TestCase
$this->assertEqualsCanonicalizing([1, 4, 5, 7], Arr::pluck($body['data'], 'id'));
}
#[Test]
#[DataProvider('allowedUsers')]
/**
* @dataProvider allowedUsers
* @test
*/
public function can_see_unapproved_if_allowed_to_approve(int $authenticatedAs)
{
$response = $this->send(

View File

@@ -13,8 +13,6 @@ use Flarum\Approval\Tests\integration\InteractsWithUnapprovedContent;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Illuminate\Support\Arr;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
class ListPostsTest extends TestCase
{
@@ -30,8 +28,10 @@ class ListPostsTest extends TestCase
$this->prepareUnapprovedDatabaseContent();
}
#[Test]
#[DataProvider('unallowedUsers')]
/**
* @dataProvider unallowedUsers
* @test
*/
public function can_only_see_approved_if_not_allowed_to_approve(?int $authenticatedAs)
{
$response = $this->send(
@@ -50,8 +50,10 @@ class ListPostsTest extends TestCase
$this->assertEqualsCanonicalizing([7, 8, 10], Arr::pluck($body['data'], 'id'));
}
#[Test]
#[DataProvider('allowedUsers')]
/**
* @dataProvider allowedUsers
* @test
*/
public function can_see_unapproved_if_allowed_to_approve(int $authenticatedAs)
{
$response = $this->send(

View File

@@ -1,20 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false"
bootstrap="../../../php-packages/testing/bootstrap/monorepo.php"
>
<source>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src/</directory>
</include>
</source>
</coverage>
<testsuites>
<testsuite name="Flarum Integration Tests">
<directory suffix="Test.php">./integration</directory>

View File

@@ -1,23 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="../../../php-packages/testing/bootstrap/monorepo.php"
>
<source>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src/</directory>
</include>
</source>
</coverage>
<testsuites>
<testsuite name="Flarum Unit Tests">
<directory suffix="Test.php">./unit</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener" />
</listeners>
</phpunit>

View File

@@ -4,7 +4,6 @@ composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.cache
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2024 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^2.0.0-beta.2"
"flarum/core": "^2.0"
},
"autoload": {
"psr-4": {

View File

@@ -4,7 +4,6 @@ composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.cache
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2024 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^2.0.0-beta.2"
"flarum/core": "^2.0"
},
"autoload": {
"psr-4": {

2
extensions/embed/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

@@ -8,7 +8,7 @@
},
"devDependencies": {
"prettier": "^2.5.1",
"flarum-webpack-config": "^3.0.0",
"flarum-webpack-config": "^2.0.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.9.1",
"@flarum/prettier-config": "^1.0.0"

View File

@@ -4,7 +4,6 @@ composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.cache
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2024 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^2.0.0-beta.2"
"flarum/core": "^2.0"
},
"extra": {
"branch-alias": {

View File

@@ -11,9 +11,6 @@ use Flarum\Extend;
use s9e\TextFormatter\Configurator;
return [
(new Extend\Frontend('admin'))
->js(__DIR__.'/js/dist/admin.js'),
(new Extend\Frontend('forum'))
->js(__DIR__.'/js/dist/forum.js')
->css(__DIR__.'/less/forum.less')
@@ -33,8 +30,4 @@ return [
}),
new Extend\Locales(__DIR__.'/locale'),
(new Extend\Settings)
->serializeToForum('flarum-emoji.cdn', 'flarum-emoji.cdn')
->default('flarum-emoji.cdn', 'https://cdn.jsdelivr.net/gh/twitter/twemoji@[version]/assets/'),
];

2
extensions/emoji/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
extensions/emoji/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

File diff suppressed because one or more lines are too long

View File

@@ -9,8 +9,8 @@
},
"devDependencies": {
"@flarum/prettier-config": "^1.0.0",
"flarum-tsconfig": "^2.0.0",
"flarum-webpack-config": "^3.0.0",
"flarum-tsconfig": "^1.0.2",
"flarum-webpack-config": "^2.0.0",
"prettier": "^2.5.1",
"typescript": "^4.5.4",
"typescript-coverage-report": "^0.6.1",

View File

@@ -1,14 +0,0 @@
import Extend from 'flarum/common/extenders';
import app from 'flarum/admin/app';
import { version } from '../common/cdn';
export default [
new Extend.Admin().setting(() => ({
setting: 'flarum-emoji.cdn',
type: 'text',
label: app.translator.trans('flarum-emoji.admin.settings.cdn_label'),
help: app.translator.trans('flarum-emoji.admin.settings.cdn_help', {
version: version,
}),
})),
];

View File

@@ -1,7 +0,0 @@
import app from 'flarum/admin/app';
export { default as extend } from './extend';
app.initializers.add('flarum-emoji', () => {
// ...
});

View File

@@ -1,7 +0,0 @@
import twemoji from 'twemoji';
export const version = /([0-9]+).[0-9]+.[0-9]+/g.exec(twemoji.base)[1];
export default function () {
return app.forum.attribute('flarum-emoji.cdn').replace('[version]', version);
}

View File

@@ -6,7 +6,7 @@ import AutocompleteReader from 'flarum/common/utils/AutocompleteReader';
import AutocompleteDropdown from './fragments/AutocompleteDropdown';
import getEmojiIconCode from './helpers/getEmojiIconCode';
import cdn from '../common/cdn';
import cdn from './cdn';
export default function addComposerAutocomplete() {
let emojiMap = null;
@@ -40,7 +40,6 @@ export default function addComposerAutocomplete() {
extend('flarum/common/components/TextEditor', 'buildEditorParams', function (params) {
const emojiKeys = Object.keys(emojiMap);
const resolvedCdn = cdn();
const autocompleteReader = new AutocompleteReader(':');
@@ -76,7 +75,7 @@ export default function addComposerAutocomplete() {
emojiDropdown.setIndex($(this).parent().index() - 1);
}}
>
<img alt={emoji} className="emoji" draggable="false" loading="lazy" src={`${resolvedCdn}72x72/${code}.png`} title={name} />
<img alt={emoji} className="emoji" draggable="false" loading="lazy" src={`${cdn}72x72/${code}.png`} title={name} />
</button>
</Tooltip>
);

View File

@@ -0,0 +1,5 @@
import twemoji from 'twemoji';
export const version = /([0-9]+).[0-9]+.[0-9]+/g.exec(twemoji.base)[1];
export default `https://cdn.jsdelivr.net/gh/twitter/twemoji@${version}/assets/`;

View File

@@ -3,16 +3,14 @@ import twemoji from 'twemoji';
import { override } from 'flarum/common/extend';
import Post from 'flarum/common/models/Post';
import cdn from '../common/cdn';
import base from './cdn';
function options() {
return {
base: cdn(),
attributes: () => ({
loading: 'lazy',
}),
};
}
const options = {
base,
attributes: () => ({
loading: 'lazy',
}),
};
/**
* Parses an HTML string into a `<body>` node containing the HTML content.
@@ -42,7 +40,7 @@ export default function renderEmoji() {
// element. This gets stripped below.
//
// See https://github.com/flarum/core/issues/2958
const emojifiedDom = twemoji.parse(parseHTML(contentHtml), options());
const emojifiedDom = twemoji.parse(parseHTML(contentHtml), options);
// Steal the HTML string inside the emojified DOM `<body>` tag.
this.emojifiedContentHtml = emojifiedDom.innerHTML;
@@ -56,6 +54,6 @@ export default function renderEmoji() {
override(s9e.TextFormatter, 'preview', (original, text, element) => {
original(text, element);
twemoji.parse(element, options());
twemoji.parse(element, options);
});
}

View File

@@ -1,15 +0,0 @@
{
// Use Flarum's tsconfig as a starting point
"extends": "flarum-tsconfig",
// This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder
// and also tells your Typescript server to read core's global typings for
// access to `dayjs` and `$` in the global namespace.
"include": ["src/**/*", "../../../*/*/js/dist-typings/@types/**/*", "@types/**/*"],
"compilerOptions": {
// This will output typings to `dist-typings`
"declarationDir": "./dist-typings",
"paths": {
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
}
}
}

View File

@@ -4,14 +4,6 @@ flarum-emoji:
# UNIQUE KEYS - The following keys are used in only one location each.
##
# Translations in this namespace are used by the admin interface.
admin:
# These translations are used in the Settings page of the admin interface.
settings:
cdn_label: CDN mirror address
cdn_help: "e.g. https://cdn.jsdelivr.net/gh/twitter/twemoji@[version]/assets/, The current version is: {version}"
# Translations in this namespace are used by the forum user interface.
forum:

View File

@@ -4,7 +4,6 @@ composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.cache
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2024 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -19,7 +19,7 @@
}
],
"require": {
"flarum/core": "^2.0.0-beta.2"
"flarum/core": "^2.0"
},
"autoload": {
"psr-4": {

View File

@@ -7,17 +7,25 @@
* LICENSE file that was distributed with this source code.
*/
use Flarum\Api\Endpoint;
use Flarum\Api\Resource;
use Flarum\Api\Controller\AbstractSerializeController;
use Flarum\Api\Controller\ListPostsController;
use Flarum\Api\Controller\ShowDiscussionController;
use Flarum\Api\Controller\ShowPostController;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Extend;
use Flarum\Flags\Access\ScopeFlagVisibility;
use Flarum\Flags\AddCanFlagAttribute;
use Flarum\Flags\AddFlagsApiAttributes;
use Flarum\Flags\AddNewFlagCountAttribute;
use Flarum\Flags\Api\Controller\CreateFlagController;
use Flarum\Flags\Api\Controller\DeleteFlagsController;
use Flarum\Flags\Api\ForumResourceFields;
use Flarum\Flags\Api\PostResourceFields;
use Flarum\Flags\Api\Resource\FlagResource;
use Flarum\Flags\Api\UserResourceFields;
use Flarum\Flags\Api\Controller\ListFlagsController;
use Flarum\Flags\Api\Serializer\FlagSerializer;
use Flarum\Flags\Flag;
use Flarum\Flags\Listener;
use Flarum\Flags\PrepareFlagsApiData;
use Flarum\Forum\Content\AssertRegistered;
use Flarum\Post\Event\Deleted;
use Flarum\Post\Post;
@@ -33,6 +41,8 @@ return [
->js(__DIR__.'/js/dist/admin.js'),
(new Extend\Routes('api'))
->get('/flags', 'flags.index', ListFlagsController::class)
->post('/flags', 'flags.create', CreateFlagController::class)
->delete('/posts/{id}/flags', 'flags.delete', DeleteFlagsController::class),
(new Extend\Model(User::class))
@@ -41,21 +51,27 @@ return [
(new Extend\Model(Post::class))
->hasMany('flags', Flag::class, 'post_id'),
new Extend\ApiResource(FlagResource::class),
(new Extend\ApiSerializer(PostSerializer::class))
->hasMany('flags', FlagSerializer::class)
->attribute('canFlag', AddCanFlagAttribute::class),
(new Extend\ApiResource(Resource\PostResource::class))
->fields(PostResourceFields::class),
(new Extend\ApiSerializer(CurrentUserSerializer::class))
->attribute('newFlagCount', AddNewFlagCountAttribute::class),
(new Extend\ApiResource(Resource\UserResource::class))
->fields(UserResourceFields::class),
(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(AddFlagsApiAttributes::class),
(new Extend\ApiResource(Resource\ForumResource::class))
->fields(ForumResourceFields::class),
(new Extend\ApiController(ShowDiscussionController::class))
->addInclude(['posts.flags', 'posts.flags.user']),
(new Extend\ApiResource(Resource\PostResource::class))
->endpoint([Endpoint\Index::class, Endpoint\Show::class], function (Endpoint\Index|Endpoint\Show $endpoint) {
return $endpoint->addDefaultInclude(['flags', 'flags.user']);
}),
(new Extend\ApiController(ListPostsController::class))
->addInclude(['flags', 'flags.user']),
(new Extend\ApiController(ShowPostController::class))
->addInclude(['flags', 'flags.user']),
(new Extend\ApiController(AbstractSerializeController::class))
->prepareDataForSerialization(PrepareFlagsApiData::class),
(new Extend\Settings())
->serializeToForum('guidelinesUrl', 'flarum-flags.guidelines_url'),

View File

@@ -1,2 +0,0 @@
declare const _default: import("flarum/common/extenders/Admin").default[];
export default _default;

View File

@@ -1 +1 @@
export { default as extend } from './extend';
export {};

View File

@@ -2,13 +2,11 @@ import Component from 'flarum/common/Component';
import type { ComponentAttrs } from 'flarum/common/Component';
import type Mithril from 'mithril';
import type FlagListState from '../states/FlagListState';
import ItemList from 'flarum/common/utils/ItemList';
export interface IFlagListAttrs extends ComponentAttrs {
state: FlagListState;
}
export default class FlagList<CustomAttrs extends IFlagListAttrs = IFlagListAttrs> extends Component<CustomAttrs, FlagListState> {
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
view(): JSX.Element;
controlItems(): ItemList<unknown>;
content(state: FlagListState): JSX.Element[][] | null;
}

View File

@@ -1,10 +1,11 @@
/// <reference types="flarum/@types/translator-icu-rich" />
export default class FlagPostModal extends FormModal<import("flarum/common/components/FormModal").IFormModalAttrs, undefined> {
constructor();
oninit(vnode: any): void;
success: boolean | undefined;
reason: Stream<string> | undefined;
reasonDetail: Stream<string> | undefined;
title(): string | any[];
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): JSX.Element;
flagReasons(): ItemList<any>;
onsubmit(e: any): void;

View File

@@ -1,2 +1,2 @@
declare const _default: (import("flarum/common/extenders/Routes").default | import("flarum/common/extenders/Store").default | import("flarum/common/extenders/Model").default)[];
declare const _default: (import("flarum/common/extenders/Model").default | import("flarum/common/extenders/Routes").default | import("flarum/common/extenders/Store").default)[];
export default _default;

2
extensions/flags/js/dist/admin.js generated vendored
View File

@@ -1,2 +1,2 @@
(()=>{var e={n:a=>{var s=a&&a.__esModule?()=>a.default:()=>a;return e.d(s,{a:s}),s},d:(a,s)=>{for(var l in s)e.o(s,l)&&!e.o(a,l)&&Object.defineProperty(a,l,{enumerable:!0,get:s[l]})},o:(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},a={};(()=>{"use strict";e.r(a),e.d(a,{extend:()=>t});const s=flarum.reg.get("core","admin/app");var l=e.n(s);const r=flarum.reg.get("core","common/extenders"),t=[(new(e.n(r)().Admin)).setting((()=>({setting:"flarum-flags.guidelines_url",type:"text",label:l().translator.trans("flarum-flags.admin.settings.guidelines_url_label")})),15).setting((()=>({setting:"flarum-flags.can_flag_own",type:"boolean",label:l().translator.trans("flarum-flags.admin.settings.flag_own_posts_label")}))).permission((()=>({icon:"fas fa-flag",label:l().translator.trans("flarum-flags.admin.permissions.view_flags_label"),permission:"discussion.viewFlags"})),"moderate",65).permission((()=>({icon:"fas fa-flag",label:l().translator.trans("flarum-flags.admin.permissions.flag_posts_label"),permission:"discussion.flagPosts"})),"reply",65)];l().initializers.add("flarum-flags",(()=>{}))})(),module.exports=a})();
(()=>{var e={n:a=>{var s=a&&a.__esModule?()=>a.default:()=>a;return e.d(s,{a:s}),s},d:(a,s)=>{for(var r in s)e.o(s,r)&&!e.o(a,r)&&Object.defineProperty(a,r,{enumerable:!0,get:s[r]})},o:(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},a={};(()=>{"use strict";e.r(a);const s=flarum.reg.get("core","admin/app");var r=e.n(s);r().initializers.add("flarum-flags",(()=>{r().extensionData.for("flarum-flags").registerSetting({setting:"flarum-flags.guidelines_url",type:"text",label:r().translator.trans("flarum-flags.admin.settings.guidelines_url_label")},15).registerSetting({setting:"flarum-flags.can_flag_own",type:"boolean",label:r().translator.trans("flarum-flags.admin.settings.flag_own_posts_label")}).registerPermission({icon:"fas fa-flag",label:r().translator.trans("flarum-flags.admin.permissions.view_flags_label"),permission:"discussion.viewFlags"},"moderate",65).registerPermission({icon:"fas fa-flag",label:r().translator.trans("flarum-flags.admin.permissions.flag_posts_label"),permission:"discussion.flagPosts"},"reply",65)}))})(),module.exports=a})();
//# sourceMappingURL=admin.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,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,qDCL9D,MAAM,EAA+BC,OAAOC,IAAIV,IAAI,OAAQ,a,aCA5D,MAAM,EAA+BS,OAAOC,IAAIV,IAAI,OAAQ,oBCE5D,IAAgB,I,MAAI,WAAeW,SAAQ,KAAM,CAC/CA,QAAS,8BACTC,KAAM,OACNC,MAAO,eAAeC,MAAM,uDAC1B,IAAIH,SAAQ,KAAM,CACpBA,QAAS,4BACTC,KAAM,UACNC,MAAO,eAAeC,MAAM,wDAC1BC,YAAW,KAAM,CACnBC,KAAM,cACNH,MAAO,eAAeC,MAAM,mDAC5BC,WAAY,0BACV,WAAY,IAAIA,YAAW,KAAM,CACnCC,KAAM,cACNH,MAAO,eAAeC,MAAM,mDAC5BC,WAAY,0BACV,QAAS,KChBb,iBAAiBE,IAAI,gBAAgB,Q","sources":["webpack://@flarum/flags/webpack/bootstrap","webpack://@flarum/flags/webpack/runtime/compat get default export","webpack://@flarum/flags/webpack/runtime/define property getters","webpack://@flarum/flags/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/flags/webpack/runtime/make namespace object","webpack://@flarum/flags/external root \"flarum.reg.get('core', 'admin/app')\"","webpack://@flarum/flags/external root \"flarum.reg.get('core', 'common/extenders')\"","webpack://@flarum/flags/./src/admin/extend.tsx","webpack://@flarum/flags/./src/admin/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.reg.get('core', 'admin/app');","const __WEBPACK_NAMESPACE_OBJECT__ = flarum.reg.get('core', 'common/extenders');","import Extend from 'flarum/common/extenders';\nimport app from 'flarum/admin/app';\nexport default [new Extend.Admin().setting(() => ({\n setting: 'flarum-flags.guidelines_url',\n type: 'text',\n label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')\n}), 15).setting(() => ({\n setting: 'flarum-flags.can_flag_own',\n type: 'boolean',\n label: app.translator.trans('flarum-flags.admin.settings.flag_own_posts_label')\n})).permission(() => ({\n icon: 'fas fa-flag',\n label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),\n permission: 'discussion.viewFlags'\n}), 'moderate', 65).permission(() => ({\n icon: 'fas fa-flag',\n label: app.translator.trans('flarum-flags.admin.permissions.flag_posts_label'),\n permission: 'discussion.flagPosts'\n}), 'reply', 65)];","import app from 'flarum/admin/app';\nexport { default as extend } from './extend';\napp.initializers.add('flarum-flags', () => {\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","reg","setting","type","label","trans","permission","icon","add"],"sourceRoot":""}
{"version":3,"file":"admin.js","mappings":"MACA,IAAIA,EAAsB,CCA1BA,EAAyBC,IACxB,IAAIC,EAASD,GAAUA,EAAOE,WAC7B,IAAOF,EAAiB,QACxB,IAAM,EAEP,OADAD,EAAoBI,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,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,IAAIV,IAAI,OAAQ,a,aCC5D,qBAAqB,gBAAgB,KACnC,sBAAsB,gBAAgBW,gBAAgB,CACpDC,QAAS,8BACTC,KAAM,OACNC,MAAO,qBAAqB,qDAC3B,IAAIH,gBAAgB,CACrBC,QAAS,4BACTC,KAAM,UACNC,MAAO,qBAAqB,sDAC3BC,mBAAmB,CACpBC,KAAM,cACNF,MAAO,qBAAqB,mDAC5BG,WAAY,wBACX,WAAY,IAAIF,mBAAmB,CACpCC,KAAM,cACNF,MAAO,qBAAqB,mDAC5BG,WAAY,wBACX,QAAS,GAAG,G","sources":["webpack://@flarum/flags/webpack/bootstrap","webpack://@flarum/flags/webpack/runtime/compat get default export","webpack://@flarum/flags/webpack/runtime/define property getters","webpack://@flarum/flags/webpack/runtime/hasOwnProperty shorthand","webpack://@flarum/flags/webpack/runtime/make namespace object","webpack://@flarum/flags/external root \"flarum.reg.get('core', 'admin/app')\"","webpack://@flarum/flags/./src/admin/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.reg.get('core', 'admin/app');","import app from 'flarum/admin/app';\napp.initializers.add('flarum-flags', () => {\n app.extensionData.for('flarum-flags').registerSetting({\n setting: 'flarum-flags.guidelines_url',\n type: 'text',\n label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')\n }, 15).registerSetting({\n setting: 'flarum-flags.can_flag_own',\n type: 'boolean',\n label: app.translator.trans('flarum-flags.admin.settings.flag_own_posts_label')\n }).registerPermission({\n icon: 'fas fa-flag',\n label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),\n permission: 'discussion.viewFlags'\n }, 'moderate', 65).registerPermission({\n icon: 'fas fa-flag',\n label: app.translator.trans('flarum-flags.admin.permissions.flag_posts_label'),\n permission: 'discussion.flagPosts'\n }, 'reply', 65);\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","reg","registerSetting","setting","type","label","registerPermission","icon","permission"],"sourceRoot":""}

2
extensions/flags/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

@@ -6,11 +6,11 @@
"devDependencies": {
"@types/mithril": "^2.0.8",
"prettier": "^2.5.1",
"flarum-webpack-config": "^3.0.0",
"flarum-webpack-config": "^2.0.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.9.1",
"@flarum/prettier-config": "^1.0.0",
"flarum-tsconfig": "^2.0.0",
"flarum-tsconfig": "^1.0.2",
"typescript": "^4.5.4",
"typescript-coverage-report": "^0.6.1"
},

View File

@@ -1,37 +0,0 @@
import Extend from 'flarum/common/extenders';
import app from 'flarum/admin/app';
export default [
new Extend.Admin()
.setting(
() => ({
setting: 'flarum-flags.guidelines_url',
type: 'text',
label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label'),
}),
15
)
.setting(() => ({
setting: 'flarum-flags.can_flag_own',
type: 'boolean',
label: app.translator.trans('flarum-flags.admin.settings.flag_own_posts_label'),
}))
.permission(
() => ({
icon: 'fas fa-flag',
label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),
permission: 'discussion.viewFlags',
}),
'moderate',
65
)
.permission(
() => ({
icon: 'fas fa-flag',
label: app.translator.trans('flarum-flags.admin.permissions.flag_posts_label'),
permission: 'discussion.flagPosts',
}),
'reply',
65
),
];

View File

@@ -1,7 +1,38 @@
import app from 'flarum/admin/app';
export { default as extend } from './extend';
app.initializers.add('flarum-flags', () => {
// ...
app.extensionData
.for('flarum-flags')
.registerSetting(
{
setting: 'flarum-flags.guidelines_url',
type: 'text',
label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label'),
},
15
)
.registerSetting({
setting: 'flarum-flags.can_flag_own',
type: 'boolean',
label: app.translator.trans('flarum-flags.admin.settings.flag_own_posts_label'),
})
.registerPermission(
{
icon: 'fas fa-flag',
label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),
permission: 'discussion.viewFlags',
},
'moderate',
65
)
.registerPermission(
{
icon: 'fas fa-flag',
label: app.translator.trans('flarum-flags.admin.permissions.flag_posts_label'),
permission: 'discussion.flagPosts',
},
'reply',
65
);
});

View File

@@ -10,7 +10,6 @@ import type Post from 'flarum/common/models/Post';
import type FlagListState from '../states/FlagListState';
import type Flag from '../models/Flag';
import { Page } from 'flarum/common/states/PaginatedListState';
import ItemList from 'flarum/common/utils/ItemList';
export interface IFlagListAttrs extends ComponentAttrs {
state: FlagListState;
@@ -28,7 +27,6 @@ export default class FlagList<CustomAttrs extends IFlagListAttrs = IFlagListAttr
<HeaderList
className="FlagList"
title={app.translator.trans('flarum-flags.forum.flagged_posts.title')}
controls={this.controlItems()}
hasItems={state.hasItems()}
loading={state.isLoading()}
emptyText={app.translator.trans('flarum-flags.forum.flagged_posts.empty_text')}
@@ -39,12 +37,6 @@ export default class FlagList<CustomAttrs extends IFlagListAttrs = IFlagListAttr
);
}
controlItems() {
const items = new ItemList();
return items;
}
content(state: FlagListState) {
if (!state.isLoading() && state.hasItems()) {
return state.getPages().map((page: Page<Flag>) => {

View File

@@ -151,6 +151,7 @@ export default class FlagPostModal extends FormModal {
reason: this.reason() === 'other' ? null : this.reason(),
reasonDetail: this.reasonDetail(),
relationships: {
user: app.session.user,
post: this.attrs.post,
},
},

View File

@@ -1,11 +1,3 @@
[data-theme^=light] {
.light-contents-vars(@color: @body-bg-light; @control-color: @body-bg-light; @name: 'flagged-post');
}
[data-theme^=dark] {
.light-contents-vars(@color: @body-bg-dark; @control-color: @body-bg-dark; @name: 'flagged-post');
}
.Post--flagged {
--border-width: 2px;
padding-top: 0 !important;
@@ -24,7 +16,7 @@
padding: 10px;
border-radius: var(--border-radius) var(--border-radius) 0 0;
overflow: hidden;
.light-contents(@name: 'flagged-post');
.light-contents(@color: @body-bg; @control-color: @body-bg);
display: flex;
align-items: center;

View File

@@ -13,13 +13,13 @@ use Illuminate\Database\Schema\Builder;
return [
'up' => function (Builder $schema) {
$schema->table('flags', function (Blueprint $table) {
$table->text('reason_detail')->nullable()->change();
$table->text('reason_detail')->change();
});
},
'down' => function (Builder $schema) {
$schema->table('flags', function (Blueprint $table) {
$table->string('reason_detail')->nullable()->change();
$table->string('reason_detail')->change();
});
}
];

View File

@@ -10,6 +10,7 @@
namespace Flarum\Flags\Access;
use Flarum\Extension\ExtensionManager;
use Flarum\Tags\Tag;
use Flarum\User\User;
use Illuminate\Database\Eloquent\Builder;
@@ -22,24 +23,31 @@ class ScopeFlagVisibility
public function __invoke(User $actor, Builder $query): void
{
$query
->whereHas('post', function (Builder $query) use ($actor) {
$query->whereVisibleTo($actor);
})
->where(function (Builder $query) use ($actor) {
if ($this->extensions->isEnabled('flarum-tags')) {
$query
->select('flags.*')
->whereHas('post.discussion.tags', function ($query) use ($actor) {
$query->whereHasPermission($actor, 'discussion.viewFlags');
});
if ($this->extensions->isEnabled('flarum-tags')) {
$query
->select('flags.*')
->leftJoin('posts', 'posts.id', '=', 'flags.post_id')
->leftJoin('discussions', 'discussions.id', '=', 'posts.discussion_id')
->whereNotExists(function ($query) use ($actor) {
return $query->selectRaw('1')
->from('discussion_tag')
->whereNotIn('tag_id', function ($query) use ($actor) {
Tag::query()->setQuery($query->from('tags'))->whereHasPermission($actor, 'discussion.viewFlags')->select('tags.id');
})
->whereColumn('discussions.id', 'discussion_id');
});
if ($actor->hasPermission('discussion.viewFlags')) {
$query->orWhereDoesntHave('post.discussion.tags');
}
} elseif (! $actor->hasPermission('discussion.viewFlags')) {
$query->whereRaw('1 = 0');
}
});
if (! $actor->hasPermission('discussion.viewFlags')) {
$query->whereExists(function ($query) {
return $query->selectRaw('1')
->from('discussion_tag')
->whereColumn('discussions.id', 'discussion_id');
});
}
}
if (! $actor->hasPermission('discussion.viewFlags')) {
$query->orWhere('flags.user_id', $actor->id);
}
}
}

View File

@@ -0,0 +1,39 @@
<?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\Flags;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Post\Post;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\User;
class AddCanFlagAttribute
{
public function __construct(
protected SettingsRepositoryInterface $settings
) {
}
public function __invoke(PostSerializer $serializer, Post $post): bool
{
return $serializer->getActor()->can('flag', $post) && $this->checkFlagOwnPostSetting($serializer->getActor(), $post);
}
protected function checkFlagOwnPostSetting(User $actor, Post $post): bool
{
if ($actor->id === $post->user_id) {
// If $actor is the post author, check to see if the setting is enabled
return (bool) $this->settings->get('flarum-flags.can_flag_own');
}
// $actor is not the post author
return true;
}
}

View File

@@ -0,0 +1,40 @@
<?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\Flags;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\User;
class AddFlagsApiAttributes
{
public function __construct(
protected SettingsRepositoryInterface $settings
) {
}
public function __invoke(ForumSerializer $serializer): array
{
$attributes = [
'canViewFlags' => $serializer->getActor()->hasPermissionLike('discussion.viewFlags')
];
if ($attributes['canViewFlags']) {
$attributes['flagCount'] = (int) $this->getFlagCount($serializer->getActor());
}
return $attributes;
}
protected function getFlagCount(User $actor): int
{
return Flag::whereVisibleTo($actor)->distinct()->count('flags.post_id');
}
}

View File

@@ -0,0 +1,32 @@
<?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\Flags;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\User\User;
class AddNewFlagCountAttribute
{
public function __invoke(CurrentUserSerializer $serializer, User $user): int
{
return $this->getNewFlagCount($user);
}
protected function getNewFlagCount(User $actor): int
{
$query = Flag::whereVisibleTo($actor);
if ($time = $actor->read_flags_at) {
$query->where('flags.created_at', '>', $time);
}
return $query->distinct()->count('flags.post_id');
}
}

View File

@@ -0,0 +1,43 @@
<?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\Flags\Api\Controller;
use Flarum\Api\Controller\AbstractCreateController;
use Flarum\Flags\Api\Serializer\FlagSerializer;
use Flarum\Flags\Command\CreateFlag;
use Flarum\Flags\Flag;
use Flarum\Http\RequestUtil;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class CreateFlagController extends AbstractCreateController
{
public ?string $serializer = FlagSerializer::class;
public array $include = [
'post',
'post.flags',
'user'
];
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): Flag
{
return $this->bus->dispatch(
new CreateFlag(RequestUtil::getActor($request), Arr::get($request->getParsedBody(), 'data', []))
);
}
}

View File

@@ -0,0 +1,81 @@
<?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\Flags\Api\Controller;
use Carbon\Carbon;
use Flarum\Api\Controller\AbstractListController;
use Flarum\Flags\Api\Serializer\FlagSerializer;
use Flarum\Flags\Flag;
use Flarum\Http\RequestUtil;
use Flarum\Http\UrlGenerator;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ListFlagsController extends AbstractListController
{
public ?string $serializer = FlagSerializer::class;
public array $include = [
'user',
'post',
'post.user',
'post.discussion'
];
public function __construct(
protected UrlGenerator $url
) {
}
protected function data(ServerRequestInterface $request, Document $document): iterable
{
$actor = RequestUtil::getActor($request);
$actor->assertRegistered();
$actor->read_flags_at = Carbon::now();
$actor->save();
$limit = $this->extractLimit($request);
$offset = $this->extractOffset($request);
$include = $this->extractInclude($request);
if (in_array('post.user', $include)) {
$include[] = 'post.user.groups';
}
$flags = Flag::whereVisibleTo($actor)
->latest('flags.created_at')
->groupBy('post_id')
->limit($limit + 1)
->offset($offset)
->get();
$this->loadRelations($flags, $include, $request);
$flags = $flags->all();
$areMoreResults = false;
if (count($flags) > $limit) {
array_pop($flags);
$areMoreResults = true;
}
$this->addPaginationData(
$document,
$request,
$this->url->to('api')->route('flags.index'),
$areMoreResults ? null : 0
);
return $flags;
}
}

Some files were not shown because too many files have changed in this diff Show More