Merge branch 'master' into 1236-user-preferences

This commit is contained in:
Daniël Klabbers 2019-07-09 21:19:41 +02:00
commit 0acab8f1c7
149 changed files with 1346 additions and 460 deletions

View File

@ -3,9 +3,6 @@ name: "🐛 Bug Report"
about: "If something isn't working as expected"
---
<!--
IMPORTANT: If you discover a security vulnerability within Flarum, please send an email to [security@flarum.org](mailto:security@flarum.org) instead. We will address these with the utmost urgency and it will prevent vulnerabilities, which may be abused, from popping up on our issue tracker.
-->
## Bug Report
**Current Behavior**

View File

@ -1,8 +0,0 @@
---
name: "🔒 Security Vulnerability"
about: "When you discover a security issue"
---
If you discover a security vulnerability within Flarum, please send an email to [security@flarum.org](mailto:security@flarum.org) instead.
**DO NOT open an issue on this repository.**
We will address these with the utmost urgency and it will prevent vulnerabilities, which may be abused, from popping up on our issue tracker.

13
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
During the beta phase, we will only patch security vulnerabilities in the latest beta release.
## Reporting a Vulnerability
If you discover a security vulnerability within Flarum, please send an email to security@flarum.org so we can address it promptly.
We will get back to you as time allows.
Discussions may commence internally, so you may not hear back immediately.
When reporting a vulnerability, please provide your GitHub username (if available), so that we can invite you to collaborate on a [security advisory on GitHub](https://help.github.com/en/articles/about-maintainer-security-advisories).

View File

@ -45,6 +45,14 @@ jobs:
- php: 7.2
env: DB=mysql PREFIX=forum_
- php: 7.4snapshot
env: DB=mysql
- php: 7.4snapshot
addons:
mariadb: '10.2'
env: DB=mariadb
- stage: build
language: generic
if: branch = master AND type = push
@ -53,3 +61,7 @@ jobs:
-k $encrypted_678139e2bc67_key
-i $encrypted_678139e2bc67_iv
after_success: skip
matrix:
allow_failures:
- php: 7.4snapshot

View File

@ -1,6 +1,6 @@
# Changelog
## Unreleased
## [0.1.0-beta.9](https://github.com/flarum/core/compare/v0.1.0-beta.8.2...v0.1.0-beta.9)
### Added
- New `hasPermission()` helper method for `Group` objects ([9684fbc](https://github.com/flarum/core/commit/9684fbc4da07d32aa322d9228302a23418412cb9))
@ -11,6 +11,7 @@
- Check and enforce minimum MariaDB ([7ff9a90](https://github.com/flarum/core/commit/7ff9a90204923293adc520d3c02dc984845d4f9f))
- Revert publication of assets when installation fails ([ed9591c](https://github.com/flarum/core/commit/ed9591c16fb2ea7a4be3387b805d855a53e0a7d5))
- Benefit from Laravel's database reconnection logic in long-running tasks ([e0becd0](https://github.com/flarum/core/commit/e0becd0c7bda939048923c1f86648793feee78d5))
- The "vendor path" (where Composer dependencies can be found) can now be configured ([5e1680c](https://github.com/flarum/core/commit/5e1680c458cd3ba274faeb92de3ac2053789131e))
### Changed
- Performance: Actually cache translations on disk ([0d16fac](https://github.com/flarum/core/commit/0d16fac001bb735ee66e82871183516aeac269b7))
@ -32,9 +33,19 @@
- Admins could not reset user passwords ([c67fb2d](https://github.com/flarum/core/commit/c67fb2d4b6a128c71d65dc6703310c0b62f91be2))
- Several down migrations were invalid
- Validation errors on reset password page resulted in HTTP 404 ([4611abe](https://github.com/flarum/core/commit/4611abe5db8b94ca3dc7bf9c447fca7c67358ee3))
- `is:unread` gambit generated an invalid query ([e17bb0b](https://github.com/flarum/core/commit/e17bb0b4331f2c92459292195c6b7db8cde1f9f3))
- Entire forum was breaking when the `custom_less` setting was missing from the database ([bf2c5a5](https://github.com/flarum/core/commit/bf2c5a5564dff3f5ef13efe7a8d69f2617570ce6))
- Dropdown icon was not showing in user card when on user page ([12fdfc9](https://github.com/flarum/core/commit/12fdfc9b544a27f6fe59c82ad6bddd3420cc0181))
- Requests were missing the `original*` attributes, which broke installations in subfolders ([56fde28](https://github.com/flarum/core/commit/56fde28e436f52fee0c03c538f0a6049bc584b53))
- Special characters such as `%` and `_` could return incorrect results ([ee3640e](https://github.com/flarum/core/commit/ee3640e1605ff67fef4b3d5cd0596f14a6ae73c9))
- FontAwesome component package changed paths in version 5.9.0 ([5eb69e1](https://github.com/flarum/core/commit/5eb69e1f59fa73fdfd5badbf41a05a6a040e7426))
- Some server environments had problems accessing the system-wide tmp path for storing JS file maps ([54660eb](https://github.com/flarum/core/commit/54660ebd6311f9ea142f1b573263d0d907400786))
- Content length of posts.content was not migrated to mediumText in 2017 ([590b311](https://github.com/flarum/core/commit/590b3115708bf94a9c7f169d98c6126380c7056e))
- An error occurred when going to the previous route if there was no previous route found ([985b87da](https://github.com/flarum/core/commit/985b87da6c9942c568a1a192e2fdcfde72e030ee))
### Removed
- `php flarum install --defaults` - this was meant to be used in our old development VM ([44c9109](https://github.com/flarum/core/commit/44c91099cd77138bb5fc29f14fb1e81a9781272d))
- Obsolete `id` attributes in JSON-API responses ([ecc3b5e](https://github.com/flarum/core/commit/ecc3b5e2271f8d9b38d52cd54476d86995dbe32e) and [7a44086](https://github.com/flarum/core/commit/7a44086bf3a0e3ba907dceb13d07ac695eca05ea))
## [0.1.0-beta.8.1](https://github.com/flarum/core/compare/v0.1.0-beta.8...v0.1.0-beta.8.1)

View File

@ -1,3 +0,0 @@
# Contributing to Flarum
Thank you for considering contributing to Flarum! Please read the **[Contributing guide](https://flarum.org/docs/contributing.html)** to learn how you can help.

View File

@ -22,7 +22,7 @@
"require": {
"php": ">=7.1",
"axy/sourcemap": "^0.1.4",
"components/font-awesome": "^5.4.2",
"components/font-awesome": "5.9.*",
"dflydev/fig-cookies": "^1.0.2",
"doctrine/dbal": "^2.7",
"franzl/whoops-middleware": "^0.4.0",
@ -63,8 +63,8 @@
"zendframework/zend-stratigility": "^3.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^6.0"
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.0"
},
"autoload": {
"psr-4": {
@ -95,5 +95,11 @@
"test:unit": "phpunit -c tests/phpunit.unit.xml",
"test:integration": "phpunit -c tests/phpunit.integration.xml",
"test:setup": "@php tests/integration/setup.php"
},
"scripts-descriptions": {
"test": "Runs all tests.",
"test:unit": "Runs all unit tests.",
"test:integration": "Runs all integration tests.",
"test:setup": "Sets up a database for use with integration tests. Execute this only once."
}
}

22
js/dist/admin.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

24
js/dist/forum.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
js/package-lock.json generated
View File

@ -3107,9 +3107,9 @@
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
"integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw=="
},
"jquery.hotkeys": {
"version": "0.1.0",

View File

@ -7,7 +7,7 @@
"color-thief-browser": "^2.0.2",
"expose-loader": "^0.7.5",
"flarum-webpack-config": "0.1.0-beta.10",
"jquery": "^3.3.1",
"jquery": "^3.4.1",
"jquery.hotkeys": "^0.1.0",
"lodash-es": "^4.17.11",
"m.attrs.bidi": "github:tobscure/m.attrs.bidi",

View File

@ -2,36 +2,55 @@ import Page from './Page';
import FieldSet from '../../common/components/FieldSet';
import Button from '../../common/components/Button';
import Alert from '../../common/components/Alert';
import Select from '../../common/components/Select';
import LoadingIndicator from '../../common/components/LoadingIndicator';
import saveSettings from '../utils/saveSettings';
export default class MailPage extends Page {
init() {
super.init();
this.loading = false;
this.loading = true;
this.saving = false;
this.fields = [
'mail_driver',
'mail_host',
'mail_from',
'mail_port',
'mail_username',
'mail_password',
'mail_encryption'
];
this.driverFields = {};
this.fields = ['mail_driver', 'mail_from'];
this.values = {};
const settings = app.data.settings;
this.fields.forEach(key => this.values[key] = m.prop(settings[key]));
this.localeOptions = {};
const locales = app.locales;
for (const i in locales) {
this.localeOptions[i] = `${locales[i]} (${i})`;
}
app.request({
method: 'GET',
url: app.forum.attribute('apiUrl') + '/mail-drivers'
}).then(response => {
this.driverFields = response['data'].reduce(
(hash, driver) => ({...hash, [driver['id']]: driver['attributes']['fields']}),
{}
);
Object.keys(this.driverFields).flatMap(key => this.driverFields[key]).forEach(
key => {
this.fields.push(key);
this.values[key] = m.prop(settings[key]);
}
);
this.loading = false;
m.redraw();
});
}
view() {
if (this.loading) {
return (
<div className="MailPage">
<div className="container">
<LoadingIndicator />
</div>
</div>
);
}
return (
<div className="MailPage">
<div className="container">
@ -41,36 +60,6 @@ export default class MailPage extends Page {
{app.translator.trans('core.admin.email.text')}
</div>
{FieldSet.component({
label: app.translator.trans('core.admin.email.server_heading'),
className: 'MailPage-MailSettings',
children: [
<div className="MailPage-MailSettings-input">
<label>{app.translator.trans('core.admin.email.driver_label')}</label>
<input className="FormControl" value={this.values.mail_driver() || ''} oninput={m.withAttr('value', this.values.mail_driver)} />
<label>{app.translator.trans('core.admin.email.host_label')}</label>
<input className="FormControl" value={this.values.mail_host() || ''} oninput={m.withAttr('value', this.values.mail_host)} />
<label>{app.translator.trans('core.admin.email.port_label')}</label>
<input className="FormControl" value={this.values.mail_port() || ''} oninput={m.withAttr('value', this.values.mail_port)} />
<label>{app.translator.trans('core.admin.email.encryption_label')}</label>
<input className="FormControl" value={this.values.mail_encryption() || ''} oninput={m.withAttr('value', this.values.mail_encryption)} />
</div>
]
})}
{FieldSet.component({
label: app.translator.trans('core.admin.email.account_heading'),
className: 'MailPage-MailSettings',
children: [
<div className="MailPage-MailSettings-input">
<label>{app.translator.trans('core.admin.email.username_label')}</label>
<input className="FormControl" value={this.values.mail_username() || ''} oninput={m.withAttr('value', this.values.mail_username)} />
<label>{app.translator.trans('core.admin.email.password_label')}</label>
<input className="FormControl" value={this.values.mail_password() || ''} oninput={m.withAttr('value', this.values.mail_password)} />
</div>
]
})}
{FieldSet.component({
label: app.translator.trans('core.admin.email.addresses_heading'),
className: 'MailPage-MailSettings',
@ -82,11 +71,35 @@ export default class MailPage extends Page {
]
})}
{FieldSet.component({
label: app.translator.trans('core.admin.email.driver_heading'),
className: 'MailPage-MailSettings',
children: [
<div className="MailPage-MailSettings-input">
<label>{app.translator.trans('core.admin.email.driver_label')}</label>
<Select value={this.values.mail_driver()} options={Object.keys(this.driverFields).reduce((memo, val) => ({...memo, [val]: val}), {})} onchange={this.values.mail_driver} />
</div>
]
})}
{Object.keys(this.driverFields[this.values.mail_driver()]).length > 0 && FieldSet.component({
label: app.translator.trans(`core.admin.email.${this.values.mail_driver()}_heading`),
className: 'MailPage-MailSettings',
children: [
<div className="MailPage-MailSettings-input">
{this.driverFields[this.values.mail_driver()].flatMap(field => [
<label>{app.translator.trans(`core.admin.email.${field}_label`)}</label>,
<input className="FormControl" value={this.values[field]() || ''} oninput={m.withAttr('value', this.values[field])} />
])}
</div>
]
})}
{Button.component({
type: 'submit',
className: 'Button Button--primary',
children: app.translator.trans('core.admin.email.submit_button'),
loading: this.loading,
loading: this.saving,
disabled: !this.changed()
})}
</form>
@ -102,9 +115,9 @@ export default class MailPage extends Page {
onsubmit(e) {
e.preventDefault();
if (this.loading) return;
if (this.saving) return;
this.loading = true;
this.saving = true;
app.alerts.dismiss(this.successAlert);
const settings = {};
@ -117,7 +130,7 @@ export default class MailPage extends Page {
})
.catch(() => {})
.then(() => {
this.loading = false;
this.saving = false;
m.redraw();
});
}

View File

@ -86,6 +86,10 @@ export default class History {
* @public
*/
back() {
if (! this.canGoBack()) {
return this.home();
}
this.stack.pop();
m.route(this.getCurrent().url);

View File

@ -29,6 +29,10 @@
margin-bottom: 7px;
}
.Select {
display: block;
}
:last-child {
margin-bottom: 0;
}

View File

@ -1,7 +1,7 @@
@import "fontawesome";
@import "fa-brands";
@import "fa-regular";
@import "fa-solid";
@import "brands";
@import "regular";
@import "solid";
@fa-font-path: "./fonts";
@import "normalize";

View File

@ -1,10 +1,5 @@
.UserPage {
.UserCard-controls {
float: right;
.Dropdown-toggle .Button-icon {
display: none;
}
.UserHero .Dropdown-toggle .Button-icon {
display: none;
}
}

View File

@ -12,16 +12,17 @@
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Schema\Builder;
// https://github.com/doctrine/dbal/issues/2566#issuecomment-480217999
return [
'up' => function (Builder $schema) {
$schema->table('posts', function (Blueprint $table) {
$table->mediumText('content')->change();
$table->mediumText('content')->comment(' ')->change();
});
},
'down' => function (Builder $schema) {
$schema->table('posts', function (Blueprint $table) {
$table->text('content')->change();
$table->text('content')->comment('')->change();
});
}
];

View File

@ -61,6 +61,7 @@ class AdminServiceProvider extends AbstractServiceProvider
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
$pipe->pipe($app->make(Middleware\RequireAdministrateAbility::class));

View File

@ -14,6 +14,7 @@ namespace Flarum\Api;
use Carbon\Carbon;
use Flarum\Database\AbstractModel;
use Flarum\User\User;
use Illuminate\Support\Str;
/**
* @property int $id
@ -38,7 +39,7 @@ class ApiKey extends AbstractModel
{
$key = new static;
$key->key = str_random(40);
$key->key = Str::random(40);
return $key;
}

View File

@ -57,6 +57,7 @@ class ApiServiceProvider extends AbstractServiceProvider
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithHeader::class));
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
event(new ConfigureMiddleware($pipe, 'api'));

View File

@ -16,6 +16,7 @@ use Flarum\Discussion\Command\ReadDiscussion;
use Flarum\Discussion\Command\StartDiscussion;
use Flarum\Post\Floodgate;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -63,14 +64,14 @@ class CreateDiscussionController extends AbstractCreateController
protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');
$ipAddress = array_get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
$ipAddress = Arr::get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
if (! $request->getAttribute('bypassFloodgate')) {
$this->floodgate->assertNotFlooding($actor);
}
$discussion = $this->bus->dispatch(
new StartDiscussion($actor, array_get($request->getParsedBody(), 'data', []), $ipAddress)
new StartDiscussion($actor, Arr::get($request->getParsedBody(), 'data', []), $ipAddress)
);
// After creating the discussion, we assume that the user has seen all

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\GroupSerializer;
use Flarum\Group\Command\CreateGroup;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -43,7 +44,7 @@ class CreateGroupController extends AbstractCreateController
protected function data(ServerRequestInterface $request, Document $document)
{
return $this->bus->dispatch(
new CreateGroup($request->getAttribute('actor'), array_get($request->getParsedBody(), 'data', []))
new CreateGroup($request->getAttribute('actor'), Arr::get($request->getParsedBody(), 'data', []))
);
}
}

View File

@ -16,6 +16,7 @@ use Flarum\Discussion\Command\ReadDiscussion;
use Flarum\Post\Command\PostReply;
use Flarum\Post\Floodgate;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -62,9 +63,9 @@ class CreatePostController extends AbstractCreateController
protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');
$data = array_get($request->getParsedBody(), 'data', []);
$discussionId = array_get($data, 'relationships.discussion.data.id');
$ipAddress = array_get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
$data = Arr::get($request->getParsedBody(), 'data', []);
$discussionId = Arr::get($data, 'relationships.discussion.data.id');
$ipAddress = Arr::get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
if (! $request->getAttribute('bypassFloodgate')) {
$this->floodgate->assertNotFlooding($actor);

View File

@ -16,6 +16,7 @@ use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\UserRepository;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -57,9 +58,9 @@ class CreateTokenController implements RequestHandlerInterface
{
$body = $request->getParsedBody();
$identification = array_get($body, 'identification');
$password = array_get($body, 'password');
$lifetime = array_get($body, 'lifetime', 3600);
$identification = Arr::get($body, 'identification');
$password = Arr::get($body, 'password');
$lifetime = Arr::get($body, 'lifetime', 3600);
$user = $this->users->findByIdentification($identification);

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\User\Command\RegisterUser;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -43,7 +44,7 @@ class CreateUserController extends AbstractCreateController
protected function data(ServerRequestInterface $request, Document $document)
{
return $this->bus->dispatch(
new RegisterUser($request->getAttribute('actor'), array_get($request->getParsedBody(), 'data', []))
new RegisterUser($request->getAttribute('actor'), Arr::get($request->getParsedBody(), 'data', []))
);
}
}

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\User\Command\DeleteAvatar;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -43,7 +44,7 @@ class DeleteAvatarController extends AbstractShowController
protected function data(ServerRequestInterface $request, Document $document)
{
return $this->bus->dispatch(
new DeleteAvatar(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
new DeleteAvatar(Arr::get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);
}
}

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Discussion\Command\DeleteDiscussion;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeleteDiscussionController extends AbstractDeleteController
@ -35,7 +36,7 @@ class DeleteDiscussionController extends AbstractDeleteController
*/
protected function delete(ServerRequestInterface $request)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$input = $request->getParsedBody();

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Group\Command\DeleteGroup;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeleteGroupController extends AbstractDeleteController
@ -36,7 +37,7 @@ class DeleteGroupController extends AbstractDeleteController
protected function delete(ServerRequestInterface $request)
{
$this->bus->dispatch(
new DeleteGroup(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
new DeleteGroup(Arr::get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);
}
}

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Post\Command\DeletePost;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeletePostController extends AbstractDeleteController
@ -36,7 +37,7 @@ class DeletePostController extends AbstractDeleteController
protected function delete(ServerRequestInterface $request)
{
$this->bus->dispatch(
new DeletePost(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
new DeletePost(Arr::get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);
}
}

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\User\Command\DeleteUser;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeleteUserController extends AbstractDeleteController
@ -36,7 +37,7 @@ class DeleteUserController extends AbstractDeleteController
protected function delete(ServerRequestInterface $request)
{
$this->bus->dispatch(
new DeleteUser(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
new DeleteUser(Arr::get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);
}
}

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\User\Command\RequestPasswordReset;
use Flarum\User\UserRepository;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -46,7 +47,7 @@ class ForgotPasswordController implements RequestHandlerInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$email = array_get($request->getParsedBody(), 'email');
$email = Arr::get($request->getParsedBody(), 'email');
$this->bus->dispatch(
new RequestPasswordReset($email)

View File

@ -16,6 +16,7 @@ use Flarum\Discussion\Discussion;
use Flarum\Discussion\Search\DiscussionSearcher;
use Flarum\Http\UrlGenerator;
use Flarum\Search\SearchCriteria;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -75,7 +76,7 @@ class ListDiscussionsController extends AbstractListController
protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');
$query = array_get($this->extractFilter($request), 'q');
$query = Arr::get($this->extractFilter($request), 'q');
$sort = $this->extractSort($request);
$criteria = new SearchCriteria($actor, $query, $sort);

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\MailDriverSerializer;
use Flarum\User\AssertPermissionTrait;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ListMailDriversController extends AbstractListController
{
use AssertPermissionTrait;
/**
* {@inheritdoc}
*/
public $serializer = MailDriverSerializer::class;
/**
* {@inheritdoc}
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$this->assertAdmin($request->getAttribute('actor'));
$drivers = self::$container->make('mail.supported_drivers');
array_walk($drivers, function (&$driver, $key) {
$driver = [
'id' => $key,
'driver' => self::$container->make($driver),
];
});
return $drivers;
}
}

View File

@ -15,6 +15,8 @@ use Flarum\Api\Serializer\PostSerializer;
use Flarum\Event\ConfigurePostsQuery;
use Flarum\Post\PostRepository;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
use Tobscure\JsonApi\Exception\InvalidParameterException;
@ -64,7 +66,7 @@ class ListPostsController extends AbstractListController
$filter = $this->extractFilter($request);
$include = $this->extractInclude($request);
if ($postIds = array_get($filter, 'id')) {
if ($postIds = Arr::get($filter, 'id')) {
$postIds = explode(',', $postIds);
} else {
$postIds = $this->getPostIds($request);
@ -86,7 +88,7 @@ class ListPostsController extends AbstractListController
$limit = $this->extractLimit($request);
$filter = $this->extractFilter($request);
if (($near = array_get($queryParams, 'page.near')) > 1) {
if (($near = Arr::get($queryParams, 'page.near')) > 1) {
if (count($filter) > 1 || ! isset($filter['discussion']) || $sort) {
throw new InvalidParameterException(
'You can only use page[near] with filter[discussion] and the default sort order'
@ -120,7 +122,7 @@ class ListPostsController extends AbstractListController
$query->skip($offset)->take($limit);
foreach ((array) $sort as $field => $order) {
$query->orderBy(snake_case($field), $order);
$query->orderBy(Str::snake($field), $order);
}
return $query->pluck('id')->all();
@ -132,19 +134,19 @@ class ListPostsController extends AbstractListController
*/
private function applyFilters(Builder $query, array $filter)
{
if ($discussionId = array_get($filter, 'discussion')) {
if ($discussionId = Arr::get($filter, 'discussion')) {
$query->where('discussion_id', $discussionId);
}
if ($number = array_get($filter, 'number')) {
if ($number = Arr::get($filter, 'number')) {
$query->where('number', $number);
}
if ($userId = array_get($filter, 'user')) {
if ($userId = Arr::get($filter, 'user')) {
$query->where('user_id', $userId);
}
if ($type = array_get($filter, 'type')) {
if ($type = Arr::get($filter, 'type')) {
$query->where('type', $type);
}

View File

@ -16,6 +16,7 @@ use Flarum\Http\UrlGenerator;
use Flarum\Search\SearchCriteria;
use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\Search\UserSearcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -73,7 +74,7 @@ class ListUsersController extends AbstractListController
throw new PermissionDeniedException;
}
$query = array_get($this->extractFilter($request), 'q');
$query = Arr::get($this->extractFilter($request), 'q');
$sort = $this->extractSort($request);
$criteria = new SearchCriteria($actor, $query, $sort);

View File

@ -18,6 +18,7 @@ use Flarum\User\EmailToken;
use Flarum\User\Exception\PermissionDeniedException;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Mail\Message;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -67,7 +68,7 @@ class SendConfirmationEmailController implements RequestHandlerInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$this->assertRegistered($actor);

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Group\Permission;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -30,8 +31,8 @@ class SetPermissionController implements RequestHandlerInterface
$this->assertAdmin($request->getAttribute('actor'));
$body = $request->getParsedBody();
$permission = array_get($body, 'permission');
$groupIds = array_get($body, 'groupIds');
$permission = Arr::get($body, 'permission');
$groupIds = Arr::get($body, 'groupIds');
Permission::where('permission', $permission)->delete();

View File

@ -16,6 +16,8 @@ use Flarum\Discussion\Discussion;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Post\PostRepository;
use Flarum\User\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -73,7 +75,7 @@ class ShowDiscussionController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$discussionId = array_get($request->getQueryParams(), 'id');
$discussionId = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$include = $this->extractInclude($request);
@ -86,7 +88,7 @@ class ShowDiscussionController extends AbstractShowController
}
$discussion->load(array_filter($include, function ($relationship) {
return ! starts_with($relationship, 'posts');
return ! Str::startsWith($relationship, 'posts');
}));
return $discussion;
@ -150,7 +152,7 @@ class ShowDiscussionController extends AbstractShowController
$queryParams = $request->getQueryParams();
$actor = $request->getAttribute('actor');
if (($near = array_get($queryParams, 'page.near')) > 1) {
if (($near = Arr::get($queryParams, 'page.near')) > 1) {
$offset = $this->posts->getIndexForNumber($discussion->id, $near, $actor);
$offset = max(0, $offset - $limit / 2);
} else {

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Post\PostRepository;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -52,6 +53,6 @@ class ShowPostController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
return $this->posts->findOrFail(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'));
return $this->posts->findOrFail(Arr::get($request->getQueryParams(), 'id'), $request->getAttribute('actor'));
}
}

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\User\UserRepository;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -47,7 +48,7 @@ class ShowUserController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
if (! is_numeric($id)) {
$id = $this->users->getIdForUsername($id);

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Extension\ExtensionManager;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class UninstallExtensionController extends AbstractDeleteController
@ -36,7 +37,7 @@ class UninstallExtensionController extends AbstractDeleteController
{
$this->assertAdmin($request->getAttribute('actor'));
$name = array_get($request->getQueryParams(), 'name');
$name = Arr::get($request->getQueryParams(), 'name');
if ($this->extensions->getExtension($name) == null) {
return;

View File

@ -16,6 +16,7 @@ use Flarum\Discussion\Command\EditDiscussion;
use Flarum\Discussion\Command\ReadDiscussion;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -45,8 +46,8 @@ class UpdateDiscussionController extends AbstractShowController
protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');
$discussionId = array_get($request->getQueryParams(), 'id');
$data = array_get($request->getParsedBody(), 'data', []);
$discussionId = Arr::get($request->getQueryParams(), 'id');
$data = Arr::get($request->getParsedBody(), 'data', []);
$discussion = $this->bus->dispatch(
new EditDiscussion($discussionId, $actor, $data)
@ -54,7 +55,7 @@ class UpdateDiscussionController extends AbstractShowController
// TODO: Refactor the ReadDiscussion (state) command into EditDiscussion?
// That's what extensions will do anyway.
if ($readNumber = array_get($data, 'attributes.lastReadPostNumber')) {
if ($readNumber = Arr::get($data, 'attributes.lastReadPostNumber')) {
$state = $this->bus->dispatch(
new ReadDiscussion($discussionId, $actor, $readNumber)
);

View File

@ -13,6 +13,7 @@ namespace Flarum\Api\Controller;
use Flarum\Extension\ExtensionManager;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -42,8 +43,8 @@ class UpdateExtensionController implements RequestHandlerInterface
{
$this->assertAdmin($request->getAttribute('actor'));
$enabled = array_get($request->getParsedBody(), 'enabled');
$name = array_get($request->getQueryParams(), 'name');
$enabled = Arr::get($request->getParsedBody(), 'enabled');
$name = Arr::get($request->getQueryParams(), 'name');
if ($enabled === true) {
$this->extensions->enable($name);

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\GroupSerializer;
use Flarum\Group\Command\EditGroup;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -42,9 +43,9 @@ class UpdateGroupController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$data = array_get($request->getParsedBody(), 'data', []);
$data = Arr::get($request->getParsedBody(), 'data', []);
return $this->bus->dispatch(
new EditGroup($id, $actor, $data)

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\NotificationSerializer;
use Flarum\Notification\Command\ReadNotification;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -42,7 +43,7 @@ class UpdateNotificationController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
return $this->bus->dispatch(

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Post\Command\EditPost;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -50,9 +51,9 @@ class UpdatePostController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$data = array_get($request->getParsedBody(), 'data', []);
$data = Arr::get($request->getParsedBody(), 'data', []);
return $this->bus->dispatch(
new EditPost($id, $actor, $data)

View File

@ -16,6 +16,7 @@ use Flarum\Api\Serializer\UserSerializer;
use Flarum\User\Command\EditUser;
use Flarum\User\Exception\PermissionDeniedException;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -49,9 +50,9 @@ class UpdateUserController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$data = array_get($request->getParsedBody(), 'data', []);
$data = Arr::get($request->getParsedBody(), 'data', []);
if ($actor->id == $id) {
$this->serializer = CurrentUserSerializer::class;
@ -60,7 +61,7 @@ class UpdateUserController extends AbstractShowController
// Require the user's current password if they are attempting to change
// their own email address.
if (isset($data['attributes']['email']) && $actor->id == $id) {
$password = array_get($request->getParsedBody(), 'meta.password');
$password = Arr::get($request->getParsedBody(), 'meta.password');
if (! $actor->checkPassword($password)) {
throw new PermissionDeniedException;

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\User\Command\UploadAvatar;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
@ -42,9 +43,9 @@ class UploadAvatarController extends AbstractShowController
*/
protected function data(ServerRequestInterface $request, Document $document)
{
$id = array_get($request->getQueryParams(), 'id');
$id = Arr::get($request->getQueryParams(), 'id');
$actor = $request->getAttribute('actor');
$file = array_get($request->getUploadedFiles(), 'avatar');
$file = Arr::get($request->getUploadedFiles(), 'avatar');
return $this->bus->dispatch(
new UploadAvatar($id, $file, $actor)

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Foundation\Application;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Intervention\Image\ImageManager;
use League\Flysystem\Adapter\Local;
@ -52,7 +53,7 @@ class UploadFaviconController extends ShowForumController
{
$this->assertAdmin($request->getAttribute('actor'));
$file = array_get($request->getUploadedFiles(), 'favicon');
$file = Arr::get($request->getUploadedFiles(), 'favicon');
$tmpFile = tempnam($this->app->storagePath().'/tmp', 'favicon');
$file->moveTo($tmpFile);

View File

@ -14,6 +14,7 @@ namespace Flarum\Api\Controller;
use Flarum\Foundation\Application;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Intervention\Image\ImageManager;
use League\Flysystem\Adapter\Local;
@ -52,7 +53,7 @@ class UploadLogoController extends ShowForumController
{
$this->assertAdmin($request->getAttribute('actor'));
$file = array_get($request->getUploadedFiles(), 'logo');
$file = Arr::get($request->getUploadedFiles(), 'logo');
$tmpFile = tempnam($this->app->storagePath().'/tmp', 'logo');
$file->moveTo($tmpFile);

View File

@ -12,6 +12,7 @@
namespace Flarum\Api\Event;
use Flarum\Api\Controller\AbstractSerializeController;
use Illuminate\Support\Arr;
class WillGetData
{
@ -64,7 +65,7 @@ class WillGetData
*/
public function removeInclude($name)
{
array_forget($this->controller->include, $name);
Arr::forget($this->controller->include, $name);
}
/**
@ -84,7 +85,7 @@ class WillGetData
*/
public function removeOptionalInclude($name)
{
array_forget($this->controller->optionalInclude, $name);
Arr::forget($this->controller->optionalInclude, $name);
}
/**
@ -124,7 +125,7 @@ class WillGetData
*/
public function removeSortField($field)
{
array_forget($this->controller->sortFields, $field);
Arr::forget($this->controller->sortFields, $field);
}
/**

View File

@ -37,7 +37,6 @@ class BasicPostSerializer extends AbstractSerializer
}
$attributes = [
'id' => (int) $post->id,
'number' => (int) $post->number,
'createdAt' => $this->formatDate($post->created_at),
'contentType' => $post->type

View File

@ -0,0 +1,49 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Api\Serializer;
use Flarum\Mail\DriverInterface;
use InvalidArgumentException;
class MailDriverSerializer extends AbstractSerializer
{
/**
* {@inheritdoc}
*/
protected $type = 'mail-drivers';
/**
* {@inheritdoc}
*
* @param \Flarum\Mail\DriverInterface $driver
* @throws InvalidArgumentException
*/
protected function getDefaultAttributes($driver)
{
if (! ($driver['driver'] instanceof DriverInterface)) {
throw new InvalidArgumentException(
get_class($this).' can only serialize instances of '.DriverInterface::class
);
}
$driver = $driver['driver'];
return [
'fields' => $driver->availableSettings(),
];
}
public function getId($model)
{
return $model['id'];
}
}

View File

@ -44,7 +44,6 @@ class NotificationSerializer extends AbstractSerializer
}
return [
'id' => (int) $notification->id,
'contentType' => $notification->type,
'content' => $notification->data,
'createdAt' => $this->formatDate($notification->created_at),

View File

@ -308,4 +308,11 @@ return function (RouteCollection $map, RouteHandlerFactory $route) {
'cache.clear',
$route->toController(Controller\ClearCacheController::class)
);
// List available mail drivers and their configuration fields
$map->get(
'/mail-drivers',
'mailDrivers.index',
$route->toController(Controller\ListMailDriversController::class)
);
};

View File

@ -55,13 +55,13 @@ abstract class AbstractModel extends Eloquent
{
parent::boot();
static::saved(function (AbstractModel $model) {
static::saved(function (self $model) {
foreach ($model->releaseAfterSaveCallbacks() as $callback) {
$callback($model);
}
});
static::deleted(function (AbstractModel $model) {
static::deleted(function (self $model) {
foreach ($model->releaseAfterDeleteCallbacks() as $callback) {
$callback($model);
}

View File

@ -12,21 +12,26 @@
namespace Flarum\Database\Console;
use Flarum\Console\AbstractCommand;
use Illuminate\Contracts\Container\Container;
use Flarum\Database\Migrator;
use Flarum\Extension\ExtensionManager;
use Flarum\Foundation\Application;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Schema\Builder;
class MigrateCommand extends AbstractCommand
{
/**
* @var Container
* @var Application
*/
protected $container;
protected $app;
/**
* @param Container $container
* @param Application $application
*/
public function __construct(Container $container)
public function __construct(Application $application)
{
$this->container = $container;
$this->app = $application;
parent::__construct();
}
@ -55,16 +60,16 @@ class MigrateCommand extends AbstractCommand
public function upgrade()
{
$this->container->bind('Illuminate\Database\Schema\Builder', function ($container) {
return $container->make('Illuminate\Database\ConnectionInterface')->getSchemaBuilder();
$this->app->bind(Builder::class, function ($app) {
return $app->make(ConnectionInterface::class)->getSchemaBuilder();
});
$migrator = $this->container->make('Flarum\Database\Migrator');
$migrator = $this->app->make(Migrator::class);
$migrator->setOutput($this->output);
$migrator->run(__DIR__.'/../../../migrations');
$extensions = $this->container->make('Flarum\Extension\ExtensionManager');
$extensions = $this->app->make(ExtensionManager::class);
$extensions->getMigrator()->setOutput($this->output);
foreach ($extensions->getEnabledExtensions() as $name => $extension) {
@ -75,13 +80,13 @@ class MigrateCommand extends AbstractCommand
}
}
$this->container->make('Flarum\Settings\SettingsRepositoryInterface')->set('version', $this->container->version());
$this->app->make(SettingsRepositoryInterface::class)->set('version', $this->app->version());
$this->info('Publishing assets...');
$this->container->make('files')->copyDirectory(
base_path().'/vendor/components/font-awesome/webfonts',
public_path().'/assets/fonts'
$this->app->make('files')->copyDirectory(
$this->app->vendorPath().'/components/font-awesome/webfonts',
$this->app->publicPath().'/assets/fonts'
);
}
}

View File

@ -17,6 +17,7 @@ use Flarum\Discussion\Event\Saving;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class EditDiscussionHandler
{
@ -54,7 +55,7 @@ class EditDiscussionHandler
{
$actor = $command->actor;
$data = $command->data;
$attributes = array_get($data, 'attributes', []);
$attributes = Arr::get($data, 'attributes', []);
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);

View File

@ -20,6 +20,7 @@ use Flarum\Post\Command\PostReply;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Support\Arr;
class StartDiscussionHandler
{
@ -66,7 +67,7 @@ class StartDiscussionHandler
// an opportunity to alter the discussion entity based on data in the
// command they may have passed through in the controller.
$discussion = Discussion::start(
array_get($data, 'attributes.title'),
Arr::get($data, 'attributes.title'),
$actor
);

View File

@ -98,7 +98,7 @@ class Discussion extends AbstractModel
{
parent::boot();
static::deleting(function (Discussion $discussion) {
static::deleting(function (self $discussion) {
Notification::whereSubjectModel(Post::class)
->whereIn('subject_id', function ($query) use ($discussion) {
$query->select('id')->from('posts')->where('discussion_id', $discussion->id);
@ -106,13 +106,13 @@ class Discussion extends AbstractModel
->delete();
});
static::deleted(function (Discussion $discussion) {
static::deleted(function (self $discussion) {
$discussion->raise(new Deleted($discussion));
Notification::whereSubject($discussion)->delete();
});
static::saving(function (Discussion $discussion) {
static::saving(function (self $discussion) {
$event = new GetModelIsPrivate($discussion);
$discussion->is_private = static::$dispatcher->until($event) === true;

View File

@ -49,8 +49,8 @@ class DiscussionRepository
*/
public function getReadIds(User $user)
{
return Discussion::leftJoin('discussions_users', 'discussions_users.discussion_id', '=', 'discussions.id')
->where('user_id', $user->id)
return Discussion::leftJoin('discussion_user', 'discussion_user.discussion_id', '=', 'discussions.id')
->where('discussion_user.user_id', $user->id)
->whereColumn('last_read_post_number', '>=', 'last_post_number')
->pluck('id')
->all();

View File

@ -13,6 +13,7 @@ namespace Flarum\Event;
use DirectoryIterator;
use Flarum\Locale\LocaleManager;
use Illuminate\Support\Arr;
use RuntimeException;
/**
@ -49,8 +50,8 @@ class ConfigureLocales
throw new RuntimeException("Error parsing composer.json in $name: ".json_last_error_msg());
}
$locale = array_get($json, 'extra.flarum-locale.code');
$title = array_get($json, 'extra.flarum-locale.title', $title);
$locale = Arr::get($json, 'extra.flarum-locale.code');
$title = Arr::get($json, 'extra.flarum-locale.title', $title);
}
if (! isset($locale)) {

View File

@ -14,6 +14,7 @@ namespace Flarum\Extension;
use Flarum\Extension\Event\Disabling;
use Flarum\Http\Exception\ForbiddenException;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Support\Arr;
class DefaultLanguagePackGuard
{
@ -34,7 +35,7 @@ class DefaultLanguagePackGuard
}
$defaultLocale = $this->settings->get('default_locale');
$locale = array_get($event->extension->extra, 'flarum-locale.code');
$locale = Arr::get($event->extension->extra, 'flarum-locale.code');
if ($locale === $defaultLocale) {
throw new ForbiddenException('You cannot disable the default language pack!');

View File

@ -257,9 +257,9 @@ class Extension implements Arrayable
private function getExtenders(): array
{
$extenderFile = $this->getExtenderFile();
$extenderFile = "{$this->path}/extend.php";
if (! $extenderFile) {
if (! file_exists($extenderFile)) {
return [];
}
@ -285,24 +285,6 @@ class Extension implements Arrayable
);
}
private function getExtenderFile(): ?string
{
$filename = "{$this->path}/extend.php";
if (file_exists($filename)) {
return $filename;
}
// To give extension authors some time to migrate to the new extension
// format, we will also fallback to the old bootstrap.php name. Consider
// this feature deprecated.
$deprecatedFilename = "{$this->path}/bootstrap.php";
if (file_exists($deprecatedFilename)) {
return $deprecatedFilename;
}
}
/**
* Tests whether the extension has assets.
*

View File

@ -21,6 +21,8 @@ use Flarum\Foundation\Application;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Schema\Builder;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
@ -67,11 +69,11 @@ class ExtensionManager
*/
public function getExtensions()
{
if (is_null($this->extensions) && $this->filesystem->exists($this->app->basePath().'/vendor/composer/installed.json')) {
if (is_null($this->extensions) && $this->filesystem->exists($this->app->vendorPath().'/composer/installed.json')) {
$extensions = new Collection();
// Load all packages installed by composer.
$installed = json_decode($this->filesystem->get($this->app->basePath().'/vendor/composer/installed.json'), true);
$installed = json_decode($this->filesystem->get($this->app->vendorPath().'/composer/installed.json'), true);
foreach ($installed as $package) {
if (Arr::get($package, 'type') != 'flarum-extension' || empty(Arr::get($package, 'name'))) {
@ -227,8 +229,8 @@ class ExtensionManager
*/
public function migrate(Extension $extension, $direction = 'up')
{
$this->app->bind('Illuminate\Database\Schema\Builder', function ($container) {
return $container->make('Illuminate\Database\ConnectionInterface')->getSchemaBuilder();
$this->app->bind(Builder::class, function ($container) {
return $container->make(ConnectionInterface::class)->getSchemaBuilder();
});
$extension->migrate($this->migrator, $direction);
@ -293,7 +295,7 @@ class ExtensionManager
*/
public function getEnabled()
{
return json_decode($this->config->get('extensions_enabled'), true);
return json_decode($this->config->get('extensions_enabled'), true) ?? [];
}
/**
@ -326,6 +328,6 @@ class ExtensionManager
*/
protected function getExtensionsDir()
{
return $this->app->basePath().'/vendor';
return $this->app->vendorPath();
}
}

View File

@ -15,6 +15,7 @@ use Flarum\Http\Rememberer;
use Flarum\User\LoginProvider;
use Flarum\User\RegistrationToken;
use Flarum\User\User;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response\HtmlResponse;
@ -43,7 +44,7 @@ class ResponseFactory
$provided = $registration->getProvided();
if (! empty($provided['email']) && $user = User::where(array_only($provided, 'email'))->first()) {
if (! empty($provided['email']) && $user = User::where(Arr::only($provided, 'email'))->first()) {
$user->loginProviders()->create(compact('provider', 'identifier'));
return $this->makeLoggedInResponse($user);

View File

@ -17,6 +17,7 @@ use Flarum\Http\Exception\RouteNotFoundException;
use Flarum\Http\UrlGenerator;
use Flarum\User\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface as Request;
class Discussion
@ -51,12 +52,12 @@ class Discussion
public function __invoke(Document $document, Request $request)
{
$queryParams = $request->getQueryParams();
$page = max(1, array_get($queryParams, 'page'));
$page = max(1, Arr::get($queryParams, 'page'));
$params = [
'id' => (int) array_get($queryParams, 'id'),
'id' => (int) Arr::get($queryParams, 'id'),
'page' => [
'near' => array_get($queryParams, 'near'),
'near' => Arr::get($queryParams, 'near'),
'offset' => ($page - 1) * 20,
'limit' => 20
]
@ -65,7 +66,7 @@ class Discussion
$apiDocument = $this->getApiDocument($request->getAttribute('actor'), $params);
$getResource = function ($link) use ($apiDocument) {
return array_first($apiDocument->included, function ($value) use ($link) {
return Arr::first($apiDocument->included, function ($value) use ($link) {
return $value->type === $link->type && $value->id === $link->id;
});
};

View File

@ -16,6 +16,7 @@ use Flarum\Api\Controller\ListDiscussionsController;
use Flarum\Frontend\Document;
use Flarum\User\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface as Request;
class Index
@ -44,9 +45,9 @@ class Index
{
$queryParams = $request->getQueryParams();
$sort = array_pull($queryParams, 'sort');
$q = array_pull($queryParams, 'q');
$page = array_pull($queryParams, 'page', 1);
$sort = Arr::pull($queryParams, 'sort');
$q = Arr::pull($queryParams, 'q');
$page = Arr::pull($queryParams, 'page', 1);
$sortMap = $this->getSortMap();

View File

@ -16,6 +16,7 @@ use Flarum\Http\SessionAuthenticator;
use Flarum\User\Command\ConfirmEmail;
use Flarum\User\Exception\InvalidConfirmationTokenException;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
@ -58,7 +59,7 @@ class ConfirmEmailController implements RequestHandlerInterface
public function handle(Request $request): ResponseInterface
{
try {
$token = array_get($request->getQueryParams(), 'token');
$token = Arr::get($request->getQueryParams(), 'token');
$user = $this->bus->dispatch(
new ConfirmEmail($token)

View File

@ -18,6 +18,7 @@ use Flarum\Http\Rememberer;
use Flarum\Http\SessionAuthenticator;
use Flarum\User\Event\LoggedIn;
use Flarum\User\UserRepository;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
@ -65,7 +66,7 @@ class LogInController implements RequestHandlerInterface
{
$actor = $request->getAttribute('actor');
$body = $request->getParsedBody();
$params = array_only($body, ['identification', 'password']);
$params = Arr::only($body, ['identification', 'password']);
$response = $this->apiClient->send(CreateTokenController::class, $actor, [], $params);
@ -79,7 +80,7 @@ class LogInController implements RequestHandlerInterface
event(new LoggedIn($this->users->findOrFail($data->userId), $token));
if (array_get($body, 'remember')) {
if (Arr::get($body, 'remember')) {
$response = $this->rememberer->remember($response, $token);
}
}

View File

@ -20,6 +20,7 @@ use Flarum\User\AssertPermissionTrait;
use Flarum\User\Event\LoggedOut;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
@ -94,7 +95,7 @@ class LogOutController implements RequestHandlerInterface
$session = $request->getAttribute('session');
$actor = $request->getAttribute('actor');
$url = array_get($request->getQueryParams(), 'return', $this->app->url());
$url = Arr::get($request->getQueryParams(), 'return', $this->app->url());
// If there is no user logged in, return to the index.
if ($actor->isGuest()) {
@ -105,8 +106,8 @@ class LogOutController implements RequestHandlerInterface
// allow the user to press a button to complete the log out process.
$csrfToken = $session->token();
if (array_get($request->getQueryParams(), 'token') !== $csrfToken) {
$return = array_get($request->getQueryParams(), 'return');
if (Arr::get($request->getQueryParams(), 'token') !== $csrfToken) {
$return = Arr::get($request->getQueryParams(), 'return');
$view = $this->view->make('flarum.forum::log-out')
->with('url', $this->url->to('forum')->route('logout').'?token='.$csrfToken.($return ? '&return='.urlencode($return) : ''));

View File

@ -16,6 +16,7 @@ use Flarum\Http\Controller\AbstractHtmlController;
use Flarum\User\Exception\InvalidConfirmationTokenException;
use Flarum\User\PasswordToken;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface as Request;
class ResetPasswordController extends AbstractHtmlController
@ -40,7 +41,7 @@ class ResetPasswordController extends AbstractHtmlController
*/
public function render(Request $request)
{
$token = array_get($request->getQueryParams(), 'token');
$token = Arr::get($request->getQueryParams(), 'token');
$token = PasswordToken::findOrFail($token);

View File

@ -18,6 +18,7 @@ use Flarum\User\PasswordToken;
use Flarum\User\UserValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\Arr;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface;
@ -72,9 +73,9 @@ class SavePasswordController implements RequestHandlerInterface
{
$input = $request->getParsedBody();
$token = PasswordToken::findOrFail(array_get($input, 'passwordToken'));
$token = PasswordToken::findOrFail(Arr::get($input, 'passwordToken'));
$password = array_get($input, 'password');
$password = Arr::get($input, 'password');
try {
// todo: probably shouldn't use the user validator for this,

View File

@ -68,6 +68,7 @@ class ForumServiceProvider extends AbstractServiceProvider
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
$pipe->pipe($app->make(HttpMiddleware\ShareErrorsFromSession::class));
@ -94,7 +95,7 @@ class ForumServiceProvider extends AbstractServiceProvider
$assets->css(function (SourceCollector $sources) {
$sources->addFile(__DIR__.'/../../less/forum.less');
$sources->addString(function () {
return $this->app->make(SettingsRepositoryInterface::class)->get('custom_less');
return $this->app->make(SettingsRepositoryInterface::class)->get('custom_less', '');
});
});

View File

@ -13,6 +13,7 @@ namespace Flarum\Foundation;
use Flarum\Foundation\Event\Validating;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
use Illuminate\Validation\Factory;
use Illuminate\Validation\ValidationException;
use Symfony\Component\Translation\TranslatorInterface;
@ -89,7 +90,7 @@ abstract class AbstractValidator
*/
protected function makeValidator(array $attributes)
{
$rules = array_only($this->getRules(), array_keys($attributes));
$rules = Arr::only($this->getRules(), array_keys($attributes));
$validator = $this->validator->make($attributes, $rules, $this->getMessages());

View File

@ -25,7 +25,7 @@ class Application extends Container implements ApplicationContract
*
* @var string
*/
const VERSION = '0.1.0-beta.8.1';
const VERSION = '0.1.0-beta.9';
/**
* The base path for the Flarum installation.
@ -41,6 +41,20 @@ class Application extends Container implements ApplicationContract
*/
protected $publicPath;
/**
* The custom storage path defined by the developer.
*
* @var string
*/
protected $storagePath;
/**
* A custom vendor path to find dependencies in non-standard environments.
*
* @var string
*/
protected $vendorPath;
/**
* Indicates if the application has "booted".
*
@ -83,13 +97,6 @@ class Application extends Container implements ApplicationContract
*/
protected $deferredServices = [];
/**
* The custom storage path defined by the developer.
*
* @var string
*/
protected $storagePath;
/**
* Create a new Flarum application instance.
*
@ -120,7 +127,7 @@ class Application extends Container implements ApplicationContract
*/
public function config($key, $default = null)
{
return array_get($this->make('flarum.config'), $key, $default);
return Arr::get($this->make('flarum.config'), $key, $default);
}
/**
@ -142,7 +149,7 @@ class Application extends Container implements ApplicationContract
public function url($path = null)
{
$config = $this->make('flarum.config');
$url = array_get($config, 'url', array_get($_SERVER, 'REQUEST_URI'));
$url = Arr::get($config, 'url', Arr::get($_SERVER, 'REQUEST_URI'));
if (is_array($url)) {
if (isset($url[$path])) {
@ -153,7 +160,7 @@ class Application extends Container implements ApplicationContract
}
if ($path) {
$url .= '/'.array_get($config, "paths.$path", $path);
$url .= '/'.Arr::get($config, "paths.$path", $path);
}
return $url;
@ -178,7 +185,7 @@ class Application extends Container implements ApplicationContract
$this->instance('app', $this);
$this->instance('Illuminate\Container\Container', $this);
$this->instance(Container::class, $this);
}
/**
@ -226,7 +233,7 @@ class Application extends Container implements ApplicationContract
*/
protected function bindPathsInContainer()
{
foreach (['base', 'public', 'storage'] as $path) {
foreach (['base', 'public', 'storage', 'vendor'] as $path) {
$this->instance('path.'.$path, $this->{$path.'Path'}());
}
}
@ -261,6 +268,16 @@ class Application extends Container implements ApplicationContract
return $this->storagePath ?: $this->basePath.DIRECTORY_SEPARATOR.'storage';
}
/**
* Get the path to the vendor directory where dependencies are installed.
*
* @return string
*/
public function vendorPath()
{
return $this->vendorPath ?: $this->basePath.DIRECTORY_SEPARATOR.'vendor';
}
/**
* Set the storage directory.
*
@ -276,6 +293,21 @@ class Application extends Container implements ApplicationContract
return $this;
}
/**
* Set the vendor directory.
*
* @param string $path
* @return $this
*/
public function useVendorPath($path)
{
$this->vendorPath = $path;
$this->instance('path.vendor', $path);
return $this;
}
/**
* Get or check the current application environment.
*
@ -680,7 +712,7 @@ class Application extends Container implements ApplicationContract
public function registerCoreContainerAliases()
{
$aliases = [
'app' => [\Flarum\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'app' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],

View File

@ -22,6 +22,7 @@ use Illuminate\Contracts\Container\Container;
use Middlewares\BasePath;
use Middlewares\BasePathRouter;
use Middlewares\RequestHandler;
use Zend\Stratigility\Middleware\OriginalMessages;
use Zend\Stratigility\MiddlewarePipe;
class InstalledApp implements AppInterface
@ -61,6 +62,7 @@ class InstalledApp implements AppInterface
$pipe = new MiddlewarePipe;
$pipe->pipe(new BasePath($this->basePath()));
$pipe->pipe(new OriginalMessages);
$pipe->pipe(
new BasePathRouter([
$this->subPath('api') => 'flarum.api.middleware',
@ -89,7 +91,7 @@ class InstalledApp implements AppInterface
/**
* @return \Psr\Http\Server\RequestHandlerInterface
*/
public function getUpdaterHandler()
private function getUpdaterHandler()
{
$pipe = new MiddlewarePipe;
$pipe->pipe(

View File

@ -23,6 +23,7 @@ use Flarum\Forum\ForumServiceProvider;
use Flarum\Frontend\FrontendServiceProvider;
use Flarum\Group\GroupServiceProvider;
use Flarum\Locale\LocaleServiceProvider;
use Flarum\Mail\MailServiceProvider;
use Flarum\Notification\NotificationServiceProvider;
use Flarum\Post\PostServiceProvider;
use Flarum\Search\SearchServiceProvider;
@ -99,6 +100,10 @@ class InstalledSite implements SiteInterface
$laravel->useStoragePath($this->paths['storage']);
if (isset($this->paths['vendor'])) {
$laravel->useVendorPath($this->paths['vendor']);
}
$laravel->instance('env', 'production');
$laravel->instance('flarum.config', $this->config);
$laravel->instance('config', $config = $this->getIlluminateConfig($laravel));

View File

@ -1,83 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Foundation;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Mail\Mailer;
use Illuminate\Mail\Transport\LogTransport;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Swift_Mailer;
use Swift_SendmailTransport;
use Swift_SmtpTransport;
use Swift_Transport;
class MailServiceProvider extends AbstractServiceProvider
{
public function register()
{
$this->app->singleton('mail.supported_drivers', function () {
return ['smtp', 'mail', 'log'];
});
$this->app->singleton('swift.mailer', function ($app) {
$settings = $app->make(SettingsRepositoryInterface::class);
return new Swift_Mailer(
$this->buildTransport($settings)
);
});
$this->app->singleton('mailer', function ($app) {
$mailer = new Mailer(
$app['view'], $app['swift.mailer'], $app['events']
);
if ($app->bound('queue')) {
$mailer->setQueue($app->make('queue'));
}
$settings = $app->make(SettingsRepositoryInterface::class);
$mailer->alwaysFrom($settings->get('mail_from'), $settings->get('forum_title'));
return $mailer;
});
}
private function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport
{
switch ($settings->get('mail_driver')) {
case 'smtp':
return $this->buildSmtpTransport($settings);
case 'mail':
return new Swift_SendmailTransport;
case 'log':
return new LogTransport($this->app->make(LoggerInterface::class));
default:
throw new InvalidArgumentException('Invalid mail driver configuration');
}
}
private function buildSmtpTransport(SettingsRepositoryInterface $settings): Swift_Transport
{
$transport = new Swift_SmtpTransport(
$settings->get('mail_host'),
$settings->get('mail_port'),
$settings->get('mail_encryption')
);
$transport->setUsername($settings->get('mail_username'));
$transport->setPassword($settings->get('mail_password'));
return $transport;
}
}

View File

@ -11,6 +11,7 @@
namespace Flarum\Foundation;
use Illuminate\Support\Str;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
@ -38,7 +39,7 @@ class MaintenanceModeHandler implements RequestHandlerInterface
private function isApiRequest(ServerRequestInterface $request): bool
{
return str_contains(
return Str::contains(
$request->getHeaderLine('Accept'),
'application/vnd.api+json'
);

View File

@ -59,6 +59,10 @@ class UninstalledSite implements SiteInterface
$laravel->useStoragePath($this->paths['storage']);
if (isset($this->paths['vendor'])) {
$laravel->useVendorPath($this->paths['vendor']);
}
$laravel->instance('env', 'production');
$laravel->instance('flarum.config', []);
$laravel->instance('config', $config = $this->getIlluminateConfig());

View File

@ -13,6 +13,7 @@ namespace Flarum\Frontend;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Locale\LocaleManager;
use Illuminate\Support\Arr;
class AddTranslations
{
@ -56,7 +57,7 @@ class AddTranslations
{
$translations = $this->locales->getTranslator()->getCatalogue($locale)->all('messages');
return array_only(
return Arr::only(
$translations,
array_filter(array_keys($translations), $this->filter)
);

View File

@ -58,7 +58,7 @@ class JsCompiler extends RevisionCompiler
$this->assetsDir->put($file, implode("\n", $output));
$mapTemp = tempnam(sys_get_temp_dir(), $mapFile);
$mapTemp = @tempnam(storage_path('tmp'), $mapFile);
$map->save($mapTemp);
$this->assetsDir->put($mapFile, file_get_contents($mapTemp));
@unlink($mapTemp);

View File

@ -14,6 +14,7 @@ namespace Flarum\Frontend\Compiler;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Frontend\Compiler\Source\SourceInterface;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Arr;
class RevisionCompiler implements CompilerInterface
{
@ -202,7 +203,7 @@ class RevisionCompiler implements CompilerInterface
if ($this->assetsDir->has(static::REV_MANIFEST)) {
$manifest = json_decode($this->assetsDir->read(static::REV_MANIFEST), true);
return array_get($manifest, $this->filename);
return Arr::get($manifest, $this->filename);
}
return null;

View File

@ -12,6 +12,7 @@
namespace Flarum\Frontend\Content;
use Flarum\Frontend\Document;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface as Request;
class Meta
@ -28,8 +29,8 @@ class Meta
$meta = [
'viewport' => 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1',
'description' => array_get($forumApiDocument, 'data.attributes.description'),
'theme-color' => array_get($forumApiDocument, 'data.attributes.themePrimaryColor')
'description' => Arr::get($forumApiDocument, 'data.attributes.description'),
'theme-color' => Arr::get($forumApiDocument, 'data.attributes.themePrimaryColor')
];
return $meta;
@ -39,7 +40,7 @@ class Meta
{
$head = [];
if ($faviconUrl = array_get($document->getForumApiDocument(), 'data.attributes.faviconUrl')) {
if ($faviconUrl = Arr::get($document->getForumApiDocument(), 'data.attributes.faviconUrl')) {
$head['favicon'] = '<link rel="shortcut icon" href="'.e($faviconUrl).'">';
}

View File

@ -14,6 +14,7 @@ namespace Flarum\Frontend;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Arr;
/**
* A view which renders a HTML skeleton for Flarum's frontend app.
@ -147,7 +148,7 @@ class Document implements Renderable
*/
public function render(): string
{
$this->view->share('forum', array_get($this->forumApiDocument, 'data.attributes'));
$this->view->share('forum', Arr::get($this->forumApiDocument, 'data.attributes'));
return $this->makeView()->render();
}
@ -174,7 +175,7 @@ class Document implements Renderable
*/
protected function makeTitle(): string
{
return ($this->title ? $this->title.' - ' : '').array_get($this->forumApiDocument, 'data.attributes.title');
return ($this->title ? $this->title.' - ' : '').Arr::get($this->forumApiDocument, 'data.attributes.title');
}
/**

View File

@ -30,7 +30,7 @@ class FrontendServiceProvider extends AbstractServiceProvider
);
$assets->setLessImportDirs([
$this->app->basePath().'/vendor/components/font-awesome/less' => ''
$this->app->vendorPath().'/components/font-awesome/less' => ''
]);
$assets->css([$this, 'addBaseCss']);
@ -72,8 +72,8 @@ class FrontendServiceProvider extends AbstractServiceProvider
public function addBaseCss(SourceCollector $sources)
{
$sources->addFile(base_path().'/vendor/flarum/core/less/common/variables.less');
$sources->addFile(base_path().'/vendor/flarum/core/less/common/mixins.less');
$sources->addFile(__DIR__.'/../../less/common/variables.less');
$sources->addFile(__DIR__.'/../../less/common/mixins.less');
$this->addLessVariables($sources);
}

View File

@ -17,6 +17,7 @@ use Flarum\Group\Group;
use Flarum\Group\GroupValidator;
use Flarum\User\AssertPermissionTrait;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class CreateGroupHandler
{
@ -51,10 +52,10 @@ class CreateGroupHandler
$this->assertCan($actor, 'createGroup');
$group = Group::build(
array_get($data, 'attributes.nameSingular'),
array_get($data, 'attributes.namePlural'),
array_get($data, 'attributes.color'),
array_get($data, 'attributes.icon')
Arr::get($data, 'attributes.nameSingular'),
Arr::get($data, 'attributes.namePlural'),
Arr::get($data, 'attributes.color'),
Arr::get($data, 'attributes.icon')
);
$this->events->dispatch(

View File

@ -19,6 +19,7 @@ use Flarum\Group\GroupValidator;
use Flarum\User\AssertPermissionTrait;
use Flarum\User\Exception\PermissionDeniedException;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class EditGroupHandler
{
@ -61,7 +62,7 @@ class EditGroupHandler
$this->assertCan($actor, 'edit', $group);
$attributes = array_get($data, 'attributes', []);
$attributes = Arr::get($data, 'attributes', []);
if (isset($attributes['nameSingular']) && isset($attributes['namePlural'])) {
$group->rename($attributes['nameSingular'], $attributes['namePlural']);

View File

@ -62,7 +62,7 @@ class Group extends AbstractModel
{
parent::boot();
static::deleted(function (Group $group) {
static::deleted(function (self $group) {
$group->raise(new Deleted($group));
});
}

View File

@ -14,6 +14,7 @@ namespace Flarum\Http;
use Carbon\Carbon;
use Flarum\Database\AbstractModel;
use Flarum\User\User;
use Illuminate\Support\Str;
/**
* @property string $token
@ -47,7 +48,7 @@ class AccessToken extends AbstractModel
{
$token = new static;
$token->token = str_random(40);
$token->token = Str::random(40);
$token->user_id = $userId;
$token->created_at = Carbon::now();
$token->last_activity_at = Carbon::now();

View File

@ -13,6 +13,7 @@ namespace Flarum\Http;
use Dflydev\FigCookies\SetCookie;
use Flarum\Foundation\Application;
use Illuminate\Support\Arr;
class CookieFactory
{
@ -54,9 +55,9 @@ class CookieFactory
// Get the cookie settings from the config or use the default values
$this->prefix = $app->config('cookie.name', 'flarum');
$this->path = $app->config('cookie.path', array_get($url, 'path') ?: '/');
$this->path = $app->config('cookie.path', Arr::get($url, 'path') ?: '/');
$this->domain = $app->config('cookie.domain');
$this->secure = $app->config('cookie.secure', array_get($url, 'scheme') === 'https');
$this->secure = $app->config('cookie.secure', Arr::get($url, 'scheme') === 'https');
}
/**

View File

@ -15,4 +15,8 @@ use Exception;
class TokenMismatchException extends Exception
{
public function __construct($message = null, $code = 419, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View File

@ -14,6 +14,7 @@ namespace Flarum\Http\Middleware;
use Flarum\Api\ApiKey;
use Flarum\Http\AccessToken;
use Flarum\User\User;
use Illuminate\Support\Str;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
@ -29,7 +30,7 @@ class AuthenticateWithHeader implements Middleware
$parts = explode(';', $headerLine);
if (isset($parts[0]) && starts_with($parts[0], self::TOKEN_PREFIX)) {
if (isset($parts[0]) && Str::startsWith($parts[0], self::TOKEN_PREFIX)) {
$id = substr($parts[0], strlen(self::TOKEN_PREFIX));
if ($key = ApiKey::where('key', $id)->first()) {
@ -40,6 +41,7 @@ class AuthenticateWithHeader implements Middleware
$request = $request->withAttribute('apiKey', $key);
$request = $request->withAttribute('bypassFloodgate', true);
$request = $request->withAttribute('bypassCsrfToken', true);
} elseif ($token = AccessToken::find($id)) {
$token->touch();

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Http\Middleware;
use Flarum\Http\Exception\TokenMismatchException;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Server\RequestHandlerInterface as Handler;
class CheckCsrfToken implements Middleware
{
public function process(Request $request, Handler $handler): Response
{
if (in_array($request->getMethod(), ['GET', 'HEAD', 'OPTIONS'])) {
return $handler->handle($request);
}
if ($request->getAttribute('bypassCsrfToken', false)) {
return $handler->handle($request);
}
if ($this->tokensMatch($request)) {
return $handler->handle($request);
}
throw new TokenMismatchException('CSRF token did not match');
}
private function tokensMatch(Request $request): bool
{
$expected = (string) $request->getAttribute('session')->token();
$provided = $request->getParsedBody()['csrfToken'] ??
$request->getHeaderLine('X-CSRF-Token');
return hash_equals($expected, $provided);
}
}

View File

@ -42,11 +42,19 @@ class HandleErrorsWithWhoops implements Middleware
try {
return $handler->handle($request);
} catch (Throwable $e) {
if ($e->getCode() !== 404) {
$status = 500;
$errorCode = $e->getCode();
if ($errorCode !== 404) {
$this->logger->error($e);
}
return WhoopsRunner::handle($e, $request);
if (is_int($errorCode) && $errorCode >= 400 && $errorCode < 600) {
$status = $errorCode;
}
return WhoopsRunner::handle($e, $request)
->withStatus($status);
}
}
}

View File

@ -11,6 +11,7 @@
namespace Flarum\Http\Middleware;
use Illuminate\Support\Str;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
@ -20,7 +21,7 @@ class ParseJsonBody implements Middleware
{
public function process(Request $request, Handler $handler): Response
{
if (str_contains($request->getHeaderLine('content-type'), 'json')) {
if (Str::contains($request->getHeaderLine('content-type'), 'json')) {
$input = json_decode($request->getBody(), true);
$request = $request->withParsedBody($input ?: []);

View File

@ -13,6 +13,7 @@ namespace Flarum\Http\Middleware;
use Flarum\Http\AccessToken;
use Flarum\Http\CookieFactory;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
@ -35,7 +36,7 @@ class RememberFromCookie implements Middleware
public function process(Request $request, Handler $handler): Response
{
$id = array_get($request->getCookieParams(), $this->cookie->getName('remember'));
$id = Arr::get($request->getCookieParams(), $this->cookie->getName('remember'));
if ($id) {
$token = AccessToken::find($id);

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