chore: Upgrade dependencies (#3830)

* wip: laraval and symfony upgrades

* Apply fixes from StyleCI

* Apply fixes from StyleCI

* bump var dumper to 6.3

* require guzzle 7.7

* remove docbloc

* lock symfony/translation-contracts to 2.5

* fix: require mailgun package

* remove docblock

* fix: flysystem tests

* fix: instance flarum assets for testing

* Apply fixes from StyleCI

* downgrade intervention/image back to 2.x

* Apply fixes from StyleCI

* provide ImageManager to AvatarUploader

* fix larastan

* revert back some other intervention/image changes

* fix image resize

* Update framework/core/src/Http/Middleware/AuthenticateWithHeader.php

Co-authored-by: Daniël Klabbers <luceos@users.noreply.github.com>

* Apply fixes from StyleCI

* Update framework/core/src/Mail/SmtpDriver.php

Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>

* Update framework/core/src/User/LoginProvider.php

Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>

* use named attrs

* revert imagemanager in constructor

* revert to using Contract mailer

* reinstate and update FlarumLogTransport

* correct var typo, use one less temp var

* names attrs

* uncomment test

* mailer contract

* Apply fixes from StyleCI

---------

Co-authored-by: StyleCI Bot <bot@styleci.io>
Co-authored-by: Daniël Klabbers <luceos@users.noreply.github.com>
Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>
This commit is contained in:
IanM 2023-06-14 14:46:15 +01:00 committed by GitHub
parent 3757bde4fc
commit 6bc19e2e52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 277 additions and 240 deletions

View File

@ -87,64 +87,68 @@
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"ext-json": "*", "ext-json": "*",
"components/font-awesome": "^5.14.0", "components/font-awesome": "^5.15.0",
"composer/composer": "^2.0", "composer/composer": "^2.0",
"dflydev/fig-cookies": "^3.0.0", "dflydev/fig-cookies": "^v3.0",
"doctrine/dbal": "^2.7", "doctrine/dbal": "^3.6.2",
"dragonmantank/cron-expression": "^3.1.0", "dragonmantank/cron-expression": "^v3.3",
"franzl/whoops-middleware": "^2.0.0", "franzl/whoops-middleware": "^2.0",
"guzzlehttp/guzzle": "^6.0|^7.4", "guzzlehttp/guzzle": "*",
"illuminate/bus": "^8.0", "illuminate/bus": "^10.0",
"illuminate/cache": "^8.0", "illuminate/cache": "^10.0",
"illuminate/config": "^8.0", "illuminate/config": "^10.0",
"illuminate/console": "^8.0", "illuminate/console": "^10.0",
"illuminate/container": "^8.0", "illuminate/container": "^10.0",
"illuminate/contracts": "^8.0", "illuminate/contracts": "^10.0",
"illuminate/database": "^8.0", "illuminate/database": "^10.0",
"illuminate/events": "^8.0", "illuminate/events": "^10.0",
"illuminate/filesystem": "^8.0", "illuminate/filesystem": "^10.0",
"illuminate/hashing": "^8.0", "illuminate/hashing": "^10.0",
"illuminate/mail": "^8.0", "illuminate/mail": "^10.0",
"illuminate/queue": "^8.0", "illuminate/queue": "^10.0",
"illuminate/session": "^8.0", "illuminate/session": "^10.0",
"illuminate/support": "^8.0", "illuminate/support": "^10.0",
"illuminate/validation": "^8.0", "illuminate/validation": "^10.0",
"illuminate/view": "^8.0", "illuminate/view": "^10.0",
"intervention/image": "2.5.* || ^2.6.1", "intervention/image": "^2.7.2",
"jenssegers/agent": "^2.6", "jenssegers/agent": "^v2.6",
"laminas/laminas-diactoros": "^2.4.1", "laminas/laminas-diactoros": "^3.0",
"laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0", "laminas/laminas-httphandlerrunner": "^2.6",
"laminas/laminas-stratigility": "^3.2.2", "laminas/laminas-stratigility": "^3.10",
"league/flysystem": "^1.0.11", "league/flysystem": "^3.15",
"league/flysystem-memory": "^3.15",
"matthiasmullie/minify": "^1.3", "matthiasmullie/minify": "^1.3",
"middlewares/base-path": "^2.0.1", "middlewares/base-path": "^v2.1",
"middlewares/base-path-router": "^2.0.1", "middlewares/base-path-router": "^v2.0.1",
"middlewares/request-handler": "^2.0.1", "middlewares/request-handler": "^v2.0.2",
"monolog/monolog": "^1.16.0", "monolog/monolog": "^3.3",
"nesbot/carbon": "^2.0", "nesbot/carbon": "^2.66",
"nikic/fast-route": "^0.6", "nikic/fast-route": "^1.3",
"psr/http-message": "^1.0", "psr/http-message": "^1.1",
"psr/http-server-handler": "^1.0", "psr/http-server-handler": "^1.0.2",
"psr/http-server-middleware": "^1.0", "psr/http-server-middleware": "^1.0.2",
"pusher/pusher-php-server": "^2.2", "pusher/pusher-php-server": "^7.2",
"s9e/text-formatter": "^2.3.6", "s9e/text-formatter": "^2.13",
"staudenmeir/eloquent-eager-limit": "^1.0", "staudenmeir/eloquent-eager-limit": "^1.8.2",
"sycho/json-api": "^0.5.0", "sycho/json-api": "^0.5.0",
"sycho/sourcemap": "^2.0.0", "sycho/sourcemap": "^2.0.0",
"symfony/config": "^5.2.2", "symfony/config": "^6.3",
"symfony/console": "^5.2.2", "symfony/console": "^6.3",
"symfony/event-dispatcher": "^5.2.2", "symfony/event-dispatcher": "^6.3",
"symfony/mime": "^5.2.0", "symfony/http-client": "^6.3",
"symfony/polyfill-intl-messageformatter": "^1.22.0", "symfony/mime": "^6.3",
"symfony/translation": "^5.1.5", "symfony/polyfill-intl-messageformatter": "^1.27",
"symfony/yaml": "^5.2.2", "symfony/postmark-mailer": "^6.3",
"symfony/translation": "^6.3",
"symfony/yaml": "^6.3",
"wikimedia/less.php": "^3.0" "wikimedia/less.php": "^3.0"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^1.4", "mockery/mockery": "^1.4",
"phpunit/phpunit": "^9.0", "phpunit/phpunit": "^9.0",
"phpstan/phpstan": ">=1.8.11 < 1.9.0", "phpstan/phpstan": "^1.10.0",
"nunomaduro/larastan": "^1.0" "nunomaduro/larastan": "^2.6",
"symfony/var-dumper": "^6.3"
}, },
"config": { "config": {
"sort-packages": true "sort-packages": true

View File

@ -31,7 +31,7 @@ class Flag extends AbstractModel
{ {
use ScopeVisibilityTrait; use ScopeVisibilityTrait;
protected $dates = ['created_at']; protected $casts = ['created_at' => 'datetime'];
public function post(): BelongsTo public function post(): BelongsTo
{ {

View File

@ -54,16 +54,12 @@ class Tag extends AbstractModel
protected $table = 'tags'; protected $table = 'tags';
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['last_posted_at', 'created_at', 'updated_at'];
protected $casts = [ protected $casts = [
'is_hidden' => 'bool', 'is_hidden' => 'bool',
'is_restricted' => 'bool' 'is_restricted' => 'bool',
'last_posted_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
]; ];
public static function boot() public static function boot()

View File

@ -29,7 +29,7 @@ class TagState extends AbstractModel
protected $table = 'tag_user'; protected $table = 'tag_user';
protected $dates = ['marked_as_read_at']; protected $casts = ['marked_as_read_at' => 'datetime'];
public function tag(): BelongsTo public function tag(): BelongsTo
{ {

View File

@ -37,59 +37,66 @@
}, },
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"components/font-awesome": "^5.14.0", "components/font-awesome": "^5.15.0",
"dflydev/fig-cookies": "^3.0.0", "dflydev/fig-cookies": "^v3.0",
"doctrine/dbal": "^2.7", "doctrine/dbal": "^3.6",
"dragonmantank/cron-expression": "^3.1.0", "dragonmantank/cron-expression": "*",
"franzl/whoops-middleware": "^2.0.0", "franzl/whoops-middleware": "V2.0",
"guzzlehttp/guzzle": "^6.0|^7.4", "guzzlehttp/guzzle": "^7.7",
"illuminate/bus": "^8.0", "illuminate/bus": "^10.0",
"illuminate/cache": "^8.0", "illuminate/cache": "^10.0",
"illuminate/config": "^8.0", "illuminate/config": "^10.0",
"illuminate/console": "^8.0", "illuminate/console": "^10.0",
"illuminate/container": "^8.0", "illuminate/container": "^10.0",
"illuminate/contracts": "^8.0", "illuminate/contracts": "^10.0",
"illuminate/database": "^8.0", "illuminate/database": "^10.0",
"illuminate/events": "^8.0", "illuminate/events": "^10.0",
"illuminate/filesystem": "^8.0", "illuminate/filesystem": "^10.0",
"illuminate/hashing": "^8.0", "illuminate/hashing": "^10.0",
"illuminate/mail": "^8.0", "illuminate/mail": "^10.0",
"illuminate/queue": "^8.0", "illuminate/queue": "^10.0",
"illuminate/session": "^8.0", "illuminate/session": "^10.0",
"illuminate/support": "^8.0", "illuminate/support": "^10.0",
"illuminate/validation": "^8.0", "illuminate/validation": "^10.0",
"illuminate/view": "^8.0", "illuminate/view": "^10.0",
"intervention/image": "2.5.* || ^2.6.1", "intervention/image": "^2.7.2",
"jenssegers/agent": "^2.6", "jenssegers/agent": "^v2.6.4",
"laminas/laminas-diactoros": "^2.4.1", "laminas/laminas-diactoros": "^3.0",
"laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0", "laminas/laminas-httphandlerrunner": "^2.6.1",
"laminas/laminas-stratigility": "^3.2.2", "laminas/laminas-stratigility": "^3.10",
"league/flysystem": "^1.0.11", "league/flysystem": "^3.15",
"matthiasmullie/minify": "^1.3", "league/flysystem-memory": "^3.15",
"middlewares/base-path": "^2.0.1", "matthiasmullie/minify": "^1.3.70",
"middlewares/base-path-router": "^2.0.1", "middlewares/base-path": "^v2.1.0",
"middlewares/request-handler": "^2.0.1", "middlewares/base-path-router": "^v2.0.1",
"monolog/monolog": "^1.16.0", "middlewares/request-handler": "^v2.0.2",
"monolog/monolog": "^3.0",
"nesbot/carbon": "^2.0", "nesbot/carbon": "^2.0",
"nikic/fast-route": "^0.6", "nikic/fast-route": "^v1.3",
"psr/http-message": "^1.0", "psr/http-message": "^1.1",
"psr/http-server-handler": "^1.0", "psr/http-server-handler": "^1.0.2",
"psr/http-server-middleware": "^1.0", "psr/http-server-middleware": "^1.0.2",
"s9e/text-formatter": "^2.3.6", "s9e/text-formatter": "^2.13",
"staudenmeir/eloquent-eager-limit": "^1.0", "staudenmeir/eloquent-eager-limit": "^1.8.2",
"sycho/json-api": "^0.5.0", "sycho/json-api": "^0.5.0",
"sycho/sourcemap": "^2.0.0", "sycho/sourcemap": "^2.0.0",
"symfony/config": "^5.2.2", "symfony/config": "^6.3",
"symfony/console": "^5.2.2", "symfony/console": "^6.3",
"symfony/event-dispatcher": "^5.2.2", "symfony/event-dispatcher": "^6.3",
"symfony/mime": "^5.2.0", "symfony/http-client": "^6.3",
"symfony/polyfill-intl-messageformatter": "^1.22.0", "symfony/mailer": "^6.3",
"symfony/translation": "^5.1.5", "symfony/mailgun-mailer": "^6.3",
"symfony/yaml": "^5.2.2", "symfony/mime": "^6.3",
"wikimedia/less.php": "^3.2" "symfony/polyfill-intl-messageformatter": "^1.27",
"symfony/postmark-mailer": "^6.3",
"symfony/translation": "^6.3",
"symfony/translation-contracts": "^2.5",
"symfony/yaml": "^6.3",
"wikimedia/less.php": "^3.0"
}, },
"require-dev": { "require-dev": {
"flarum/testing": "^2.0" "flarum/testing": "^2.0",
"symfony/var-dumper": "^6.3"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

View File

@ -27,7 +27,7 @@ use Illuminate\Support\Str;
*/ */
class ApiKey extends AbstractModel class ApiKey extends AbstractModel
{ {
protected $dates = ['last_activity_at']; protected $casts = ['last_activity_at' => 'datetime'];
public static function generate(): static public static function generate(): static
{ {
@ -38,7 +38,7 @@ class ApiKey extends AbstractModel
return $key; return $key;
} }
public function touch(): bool public function touch($attribute = null): bool
{ {
$this->last_activity_at = Carbon::now(); $this->last_activity_at = Carbon::now();

View File

@ -57,7 +57,7 @@ class CreateTokenController implements RequestHandlerInterface
} }
// We do a first update here to log the IP/agent of the token creator, even if the token is never used afterwards // We do a first update here to log the IP/agent of the token creator, even if the token is never used afterwards
$token->touch($request); $token->touch(request: $request);
return new JsonResponse([ return new JsonResponse([
'token' => $token->token, 'token' => $token->token,

View File

@ -18,7 +18,7 @@ trait ScopeVisibilityTrait
/** /**
* @todo: define clear scoper interfaces. * @todo: define clear scoper interfaces.
* *
* @var array<string, array<string, callable(User, Builder, ?string $ability): void>> * @var array<string, array<string, callable(User, Builder, ?string): void>>
*/ */
protected static array $visibilityScopers = []; protected static array $visibilityScopers = [];

View File

@ -69,20 +69,16 @@ class Discussion extends AbstractModel
*/ */
protected array $modifiedPosts = []; protected array $modifiedPosts = [];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at', 'last_posted_at', 'hidden_at'];
/** /**
* The attributes that should be cast to native types. * The attributes that should be cast to native types.
* *
* @var array * @var array
*/ */
protected $casts = [ protected $casts = [
'is_private' => 'boolean' 'is_private' => 'boolean',
'created_at' => 'datetime',
'last_posted_at' => 'datetime',
'hidden_at' => 'datetime',
]; ];
/** /**

View File

@ -42,7 +42,7 @@ class UserState extends AbstractModel
* *
* @var array * @var array
*/ */
protected $dates = ['last_read_at']; protected $casts = ['last_read_at' => 'datetime'];
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@ -26,7 +26,7 @@ class FilesystemServiceProvider extends AbstractServiceProvider
public function register(): void public function register(): void
{ {
$this->container->singleton('files', function () { $this->container->singleton('files', function () {
return new Filesystem; return new Filesystem();
}); });
$this->container->singleton('flarum.filesystem.disks', function () { $this->container->singleton('flarum.filesystem.disks', function () {

View File

@ -18,8 +18,8 @@ use Flarum\Settings\OverrideSettingsRepository;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Container\Container;
use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Filesystem\FilesystemAdapter;
use League\Flysystem\Adapter\NullAdapter;
use League\Flysystem\Filesystem; use League\Flysystem\Filesystem;
use League\Flysystem\InMemory\InMemoryFilesystemAdapter;
use Less_Exception_Parser; use Less_Exception_Parser;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
@ -68,7 +68,9 @@ class ValidateCustomLess
); );
$assetsDir = $this->assets->getAssetsDir(); $assetsDir = $this->assets->getAssetsDir();
$this->assets->setAssetsDir(new FilesystemAdapter(new Filesystem(new NullAdapter)));
$adapter = new InMemoryFilesystemAdapter();
$this->assets->setAssetsDir(new FilesystemAdapter(new Filesystem($adapter), $adapter));
try { try {
$this->assets->makeCss()->commit(); $this->assets->makeCss()->commit();

View File

@ -0,0 +1,21 @@
<?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\Foundation;
class Container extends \Illuminate\Container\Container
{
public function terminating(): void
{
}
public function terminate(): void
{
}
}

View File

@ -39,13 +39,13 @@ use Illuminate\Cache\Repository as CacheRepository;
use Illuminate\Config\Repository as ConfigRepository; use Illuminate\Config\Repository as ConfigRepository;
use Illuminate\Contracts\Cache\Repository; use Illuminate\Contracts\Cache\Repository;
use Illuminate\Contracts\Cache\Store; use Illuminate\Contracts\Cache\Store;
use Illuminate\Contracts\Container\Container;
use Illuminate\Filesystem\Filesystem; use Illuminate\Filesystem\Filesystem;
use Illuminate\Hashing\HashServiceProvider; use Illuminate\Hashing\HashServiceProvider;
use Illuminate\Validation\ValidationServiceProvider; use Illuminate\Validation\ValidationServiceProvider;
use Illuminate\View\ViewServiceProvider; use Illuminate\View\ViewServiceProvider;
use Monolog\Formatter\LineFormatter; use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler; use Monolog\Handler\RotatingFileHandler;
use Monolog\Level;
use Monolog\Logger; use Monolog\Logger;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -88,7 +88,7 @@ class InstalledSite implements SiteInterface
protected function bootLaravel(): Container protected function bootLaravel(): Container
{ {
$container = new \Illuminate\Container\Container; $container = new Container;
$laravel = new Application($container, $this->paths); $laravel = new Application($container, $this->paths);
$container->instance('env', 'production'); $container->instance('env', 'production');
@ -165,7 +165,7 @@ class InstalledSite implements SiteInterface
protected function registerLogger(Container $container): void protected function registerLogger(Container $container): void
{ {
$logPath = $this->paths->storage.'/logs/flarum.log'; $logPath = $this->paths->storage.'/logs/flarum.log';
$logLevel = $this->config->inDebugMode() ? Logger::DEBUG : Logger::INFO; $logLevel = $this->config->inDebugMode() ? Level::Debug : Level::Info;
$handler = new RotatingFileHandler($logPath, 0, $logLevel); $handler = new RotatingFileHandler($logPath, 0, $logLevel);
$handler->setFormatter(new LineFormatter(null, null, true, true)); $handler->setFormatter(new LineFormatter(null, null, true, true));

View File

@ -44,7 +44,10 @@ class Group extends AbstractModel
* *
* @var array * @var array
*/ */
protected $dates = ['created_at', 'updated_at']; protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
public static function boot() public static function boot()
{ {

View File

@ -26,7 +26,7 @@ class Permission extends AbstractModel
* *
* @var array * @var array
*/ */
protected $dates = ['created_at']; protected $casts = ['created_at' => 'datetime'];
public function group(): BelongsTo public function group(): BelongsTo
{ {

View File

@ -37,9 +37,9 @@ class AccessToken extends AbstractModel
protected $table = 'access_tokens'; protected $table = 'access_tokens';
protected $dates = [ protected $casts = [
'created_at', 'created_at' => 'datetime',
'last_activity_at', 'last_activity_at' => 'datetime',
]; ];
/** /**
@ -94,7 +94,7 @@ class AccessToken extends AbstractModel
* Update the time of last usage of a token. * Update the time of last usage of a token.
* If a request object is provided, the IP address and User Agent will also be logged. * If a request object is provided, the IP address and User Agent will also be logged.
*/ */
public function touch(?ServerRequestInterface $request = null): bool public function touch($attribute = null, ServerRequestInterface $request = null): bool
{ {
$now = Carbon::now(); $now = Carbon::now();

View File

@ -41,7 +41,7 @@ class AuthenticateWithHeader implements Middleware
$request = $request->withAttribute('apiKey', $key); $request = $request->withAttribute('apiKey', $key);
$request = $request->withAttribute('bypassThrottling', true); $request = $request->withAttribute('bypassThrottling', true);
} elseif ($token = AccessToken::findValid($id)) { } elseif ($token = AccessToken::findValid($id)) {
$token->touch($request); $token->touch(request: $request);
$actor = $token->user; $actor = $token->user;
} }

View File

@ -41,7 +41,7 @@ class AuthenticateWithSession implements Middleware
$actor = $token->user; $actor = $token->user;
$actor->updateLastSeen()->save(); $actor->updateLastSeen()->save();
$token->touch($request); $token->touch(request: $request);
return $actor; return $actor;
} }

View File

@ -33,7 +33,7 @@ class RememberFromCookie implements Middleware
$token = AccessToken::findValid($id); $token = AccessToken::findValid($id);
if ($token && $token instanceof RememberAccessToken) { if ($token && $token instanceof RememberAccessToken) {
$token->touch($request); $token->touch(request: $request);
/** @var \Illuminate\Contracts\Session\Session $session */ /** @var \Illuminate\Contracts\Session\Session $session */
$session = $request->getAttribute('session'); $session = $request->getAttribute('session');

View File

@ -14,7 +14,7 @@ use Symfony\Component\Translation\MessageCatalogue;
class PrefixedYamlFileLoader extends YamlFileLoader class PrefixedYamlFileLoader extends YamlFileLoader
{ {
public function load($resource, $locale, $domain = 'messages'): MessageCatalogue public function load(mixed $resource, $locale, $domain = 'messages'): MessageCatalogue
{ {
$catalogue = parent::load($resource['file'], $locale, $domain); $catalogue = parent::load($resource['file'], $locale, $domain);

View File

@ -27,7 +27,7 @@ class Translator extends BaseTranslator implements TranslatorInterface
return $this->trans($key, $replace, null, $locale); return $this->trans($key, $replace, null, $locale);
} }
public function getCatalogue($locale = null): MessageCatalogueInterface public function getCatalogue(?string $locale = null): MessageCatalogueInterface
{ {
if (null === $locale) { if (null === $locale) {
$locale = $this->getLocale(); $locale = $this->getLocale();
@ -73,7 +73,7 @@ class Translator extends BaseTranslator implements TranslatorInterface
return $translation; return $translation;
} }
public function setLocale($locale) public function setLocale($locale): void
{ {
parent::setLocale($locale); parent::setLocale($locale);
} }

View File

@ -12,7 +12,7 @@ namespace Flarum\Mail;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Swift_Transport; use Symfony\Component\Mailer\Transport\TransportInterface;
/** /**
* An interface for a mail service. * An interface for a mail service.
@ -56,5 +56,5 @@ interface DriverInterface
/** /**
* Build a mail transport based on Flarum's current settings. * Build a mail transport based on Flarum's current settings.
*/ */
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport; public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface;
} }

View File

@ -10,24 +10,26 @@
namespace Flarum\Mail; namespace Flarum\Mail;
use Illuminate\Mail\Transport\LogTransport; use Illuminate\Mail\Transport\LogTransport;
use Swift_Mime_SimpleMessage; use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mime\RawMessage;
class FlarumLogTransport extends LogTransport class FlarumLogTransport extends LogTransport
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return int
*/ */
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage
{ {
$this->beforeSendPerformed($message); $string = $message->toString();
if (str_contains($string, 'Content-Transfer-Encoding: quoted-printable')) {
$string = quoted_printable_decode($string);
}
// Overriden to use info, so the log driver works in non-debug mode. // Overriden to use info, so the log driver works in non-debug mode.
$this->logger->info($this->getMimeEntityString($message)); $this->logger->info($string);
$this->sendPerformed($message); return new SentMessage($message, $envelope ?? Envelope::create($message));
return $this->numberOfRecipients($message);
} }
} }

View File

@ -13,7 +13,7 @@ use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Swift_Transport; use Symfony\Component\Mailer\Transport\TransportInterface;
class LogDriver implements DriverInterface class LogDriver implements DriverInterface
{ {
@ -37,7 +37,7 @@ class LogDriver implements DriverInterface
return false; return false;
} }
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface
{ {
return new FlarumLogTransport($this->logger); return new FlarumLogTransport($this->logger);
} }

View File

@ -12,10 +12,11 @@ namespace Flarum\Mail;
use Flarum\Foundation\AbstractServiceProvider; use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Mail\Mailer as MailerContract;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Mail\Mailer; use Illuminate\Mail\Mailer;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Swift_Mailer; use Symfony\Component\Mailer\Transport\TransportInterface;
class MailServiceProvider extends AbstractServiceProvider class MailServiceProvider extends AbstractServiceProvider
{ {
@ -54,19 +55,17 @@ class MailServiceProvider extends AbstractServiceProvider
: $container->make(NullDriver::class); : $container->make(NullDriver::class);
}); });
$this->container->singleton('swift.mailer', function (Container $container) { $this->container->singleton('symfony.mailer.transport', function (Container $container): TransportInterface {
return new Swift_Mailer( return $container->make('mail.driver')->buildTransport(
$container->make('mail.driver')->buildTransport( $container->make(SettingsRepositoryInterface::class)
$container->make(SettingsRepositoryInterface::class)
)
); );
}); });
$this->container->singleton('mailer', function (Container $container) { $this->container->singleton('mailer', function (Container $container): MailerContract {
$mailer = new Mailer( $mailer = new Mailer(
'flarum', 'flarum',
$container['view'], $container['view'],
$container['swift.mailer'], $container['symfony.mailer.transport'],
$container['events'] $container['events']
); );
@ -79,5 +78,7 @@ class MailServiceProvider extends AbstractServiceProvider
return $mailer; return $mailer;
}); });
$this->container->alias('mailer', MailerContract::class);
} }
} }

View File

@ -10,11 +10,11 @@
namespace Flarum\Mail; namespace Flarum\Mail;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use GuzzleHttp\Client;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Mail\Transport\MailgunTransport;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Swift_Transport; use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
class MailgunDriver implements DriverInterface class MailgunDriver implements DriverInterface
{ {
@ -44,13 +44,15 @@ class MailgunDriver implements DriverInterface
return true; return true;
} }
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface
{ {
return new MailgunTransport( $factory = new MailgunTransportFactory();
new Client(['connect_timeout' => 60]),
return $factory->create(new Dsn(
'mailgun+api',
$settings->get('mail_mailgun_region'),
$settings->get('mail_mailgun_secret'), $settings->get('mail_mailgun_secret'),
$settings->get('mail_mailgun_domain'), $settings->get('mail_mailgun_domain')
$settings->get('mail_mailgun_region') ));
);
} }
} }

View File

@ -12,8 +12,8 @@ namespace Flarum\Mail;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Swift_NullTransport; use Symfony\Component\Mailer\Transport\NullTransport;
use Swift_Transport; use Symfony\Component\Mailer\Transport\TransportInterface;
class NullDriver implements DriverInterface class NullDriver implements DriverInterface
{ {
@ -32,8 +32,8 @@ class NullDriver implements DriverInterface
return false; return false;
} }
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface
{ {
return new Swift_NullTransport(); return new NullTransport();
} }
} }

View File

@ -12,8 +12,9 @@ namespace Flarum\Mail;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Swift_SendmailTransport; use Symfony\Component\Mailer\Transport\Dsn;
use Swift_Transport; use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
use Symfony\Component\Mailer\Transport\TransportInterface;
class SendmailDriver implements DriverInterface class SendmailDriver implements DriverInterface
{ {
@ -32,8 +33,8 @@ class SendmailDriver implements DriverInterface
return true; return true;
} }
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface
{ {
return new Swift_SendmailTransport; return (new SendmailTransportFactory())->create(new Dsn('', 'sendmail'));
} }
} }

View File

@ -12,11 +12,17 @@ namespace Flarum\Mail;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Swift_SmtpTransport; use Symfony\Component\Mailer\Transport\Dsn;
use Swift_Transport; use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
use Symfony\Component\Mailer\Transport\TransportInterface;
class SmtpDriver implements DriverInterface class SmtpDriver implements DriverInterface
{ {
public function __construct(
protected EsmtpTransportFactory $factory
) {
}
public function availableSettings(): array public function availableSettings(): array
{ {
return [ return [
@ -44,17 +50,14 @@ class SmtpDriver implements DriverInterface
return true; return true;
} }
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface
{ {
$transport = new Swift_SmtpTransport( return $this->factory->create(new Dsn(
$settings->get('mail_encryption') === 'tls' ? 'smtps' : '',
$settings->get('mail_host'), $settings->get('mail_host'),
$settings->get('mail_port'), $settings->get('mail_username'),
$settings->get('mail_encryption') $settings->get('mail_password'),
); $settings->get('mail_port')
));
$transport->setUsername($settings->get('mail_username'));
$transport->setPassword($settings->get('mail_password'));
return $transport;
} }
} }

View File

@ -52,7 +52,7 @@ class Notification extends AbstractModel
* *
* @var array * @var array
*/ */
protected $dates = ['created_at', 'read_at']; protected $casts = ['created_at' => 'datetime', 'read_at' => 'datetime'];
/** /**
* A map of notification types and the model classes to use for their * A map of notification types and the model classes to use for their

View File

@ -48,20 +48,16 @@ class Post extends AbstractModel
protected $table = 'posts'; protected $table = 'posts';
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at', 'edited_at', 'hidden_at'];
/** /**
* The attributes that should be cast to native types. * The attributes that should be cast to native types.
* *
* @var array * @var array
*/ */
protected $casts = [ protected $casts = [
'is_private' => 'boolean' 'is_private' => 'boolean',
'created_at' => 'datetime',
'edited_at' => 'datetime',
'hidden_at' => 'datetime'
]; ];
/** /**

View File

@ -9,7 +9,6 @@
namespace Flarum\Queue; namespace Flarum\Queue;
use Exception;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandling; use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandling;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Throwable; use Throwable;

View File

@ -29,7 +29,7 @@ class EmailToken extends AbstractModel
* *
* @var array * @var array
*/ */
protected $dates = ['created_at']; protected $casts = ['created_at' => 'datetime'];
/** /**
* Use a custom primary key for this model. * Use a custom primary key for this model.

View File

@ -23,7 +23,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
*/ */
class LoginProvider extends AbstractModel class LoginProvider extends AbstractModel
{ {
protected $dates = ['created_at', 'last_login_at']; protected $casts = [
'created_at' => 'datetime',
'last_login_at' => 'datetime',
];
public $timestamps = true; public $timestamps = true;

View File

@ -26,7 +26,7 @@ class PasswordToken extends AbstractModel
* *
* @var array * @var array
*/ */
protected $dates = ['created_at']; protected $casts = ['created_at' => 'datetime'];
/** /**
* Use a custom primary key for this model. * Use a custom primary key for this model.

View File

@ -27,16 +27,10 @@ use Illuminate\Support\Str;
*/ */
class RegistrationToken extends AbstractModel class RegistrationToken extends AbstractModel
{ {
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at'];
protected $casts = [ protected $casts = [
'user_attributes' => 'array', 'user_attributes' => 'array',
'payload' => 'array' 'payload' => 'array',
'created_at' => 'datetime'
]; ];
/** /**

View File

@ -62,16 +62,11 @@ class User extends AbstractModel
use ScopeVisibilityTrait; use ScopeVisibilityTrait;
use HasEagerLimit; use HasEagerLimit;
/** protected $casts = [
* The attributes that should be mutated to dates. 'joined_at' => 'datetime',
* 'last_seen_at' => 'datetime',
* @var array 'marked_all_as_read_at' => 'datetime',
*/ 'read_notifications_at' => 'datetime',
protected $dates = [
'joined_at',
'last_seen_at',
'marked_all_as_read_at',
'read_notifications_at'
]; ];
/** /**

View File

@ -7,8 +7,8 @@
* LICENSE file that was distributed with this source code. * LICENSE file that was distributed with this source code.
*/ */
use Flarum\Foundation\Container;
use Flarum\Foundation\Paths; use Flarum\Foundation\Paths;
use Illuminate\Container\Container;
use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Config\Repository;
if (! function_exists('resolve')) { if (! function_exists('resolve')) {

View File

@ -113,7 +113,7 @@ class AccessTokenLifecycleTest extends TestCase
/** @var AccessToken $token */ /** @var AccessToken $token */
$token = AccessToken::whereToken('a')->firstOrFail(); $token = AccessToken::whereToken('a')->firstOrFail();
$token->touch((new ServerRequest([ $token->touch(request: (new ServerRequest([
'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36', 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36',
]))->withAttribute('ipAddress', '8.8.8.8')); ]))->withAttribute('ipAddress', '8.8.8.8'));
@ -132,7 +132,7 @@ class AccessTokenLifecycleTest extends TestCase
/** @var AccessToken $token */ /** @var AccessToken $token */
$token = AccessToken::whereToken('a')->firstOrFail(); $token = AccessToken::whereToken('a')->firstOrFail();
$token->touch(new ServerRequest([ $token->touch(request: new ServerRequest([
'HTTP_USER_AGENT' => str_repeat('a', 500), 'HTTP_USER_AGENT' => str_repeat('a', 500),
])); ]));

View File

@ -258,7 +258,7 @@ class CreateTest extends TestCase
'username' => 'test', 'username' => 'test',
'email' => 'test@machine.local', 'email' => 'test@machine.local',
'is_email_confirmed' => 1, 'is_email_confirmed' => 1,
'avatar_url' => 'https://192.168.0.1/image.png' 'avatar_url' => 'https://i_do_not_exist.flarum.org/image.png'
], []); ], []);
$regTokens[] = RegistrationToken::generate('flarum', '1', [ $regTokens[] = RegistrationToken::generate('flarum', '1', [

View File

@ -20,9 +20,8 @@ use Flarum\Testing\integration\TestCase;
use Illuminate\Contracts\Filesystem\Cloud; use Illuminate\Contracts\Filesystem\Cloud;
use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Filesystem\FilesystemAdapter;
use InvalidArgumentException; use InvalidArgumentException;
use League\Flysystem\Adapter\Local; use League\Flysystem\InMemory\InMemoryFilesystemAdapter;
use League\Flysystem\Adapter\NullAdapter; use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\Filesystem as LeagueFilesystem;
class FilesystemTest extends TestCase class FilesystemTest extends TestCase
{ {
@ -49,9 +48,10 @@ class FilesystemTest extends TestCase
]; ];
})); }));
/** @var FilesystemAdapter $uploadsDisk */
$uploadsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-uploads'); $uploadsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-uploads');
$this->assertEquals(get_class($uploadsDisk->getDriver()->getAdapter()), Local::class); $this->assertEquals(get_class($uploadsDisk->getAdapter()), LocalFilesystemAdapter::class);
} }
/** /**
@ -61,9 +61,10 @@ class FilesystemTest extends TestCase
{ {
$this->extend((new Extend\Filesystem)->disk('flarum-uploads', UploadsDisk::class)); $this->extend((new Extend\Filesystem)->disk('flarum-uploads', UploadsDisk::class));
/** @var FilesystemAdapter $uploadsDisk */
$uploadsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-uploads'); $uploadsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-uploads');
$this->assertEquals(get_class($uploadsDisk->getDriver()->getAdapter()), Local::class); $this->assertEquals(get_class($uploadsDisk->getAdapter()), LocalFilesystemAdapter::class);
} }
/** /**
@ -73,9 +74,10 @@ class FilesystemTest extends TestCase
{ {
$this->app()->getContainer()->make(SettingsRepositoryInterface::class)->set('disk_driver.flarum-assets', 'nonexistent_driver'); $this->app()->getContainer()->make(SettingsRepositoryInterface::class)->set('disk_driver.flarum-assets', 'nonexistent_driver');
/** @var FilesystemAdapter $assetsDisk */
$assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets');
$this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), Local::class); $this->assertEquals(get_class($assetsDisk->getAdapter()), LocalFilesystemAdapter::class);
} }
/** /**
@ -85,9 +87,10 @@ class FilesystemTest extends TestCase
{ {
$this->config('disk_driver.flarum-assets', 'null'); $this->config('disk_driver.flarum-assets', 'null');
/** @var FilesystemAdapter $assetsDisk */
$assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets');
$this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), Local::class); $this->assertEquals(get_class($assetsDisk->getAdapter()), LocalFilesystemAdapter::class);
} }
/** /**
@ -101,9 +104,10 @@ class FilesystemTest extends TestCase
$this->app()->getContainer()->make(SettingsRepositoryInterface::class)->set('disk_driver.flarum-assets', 'null'); $this->app()->getContainer()->make(SettingsRepositoryInterface::class)->set('disk_driver.flarum-assets', 'null');
/** @var FilesystemAdapter $assetsDisk */
$assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets');
$this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), NullAdapter::class); $this->assertEquals(get_class($assetsDisk->getAdapter()), InMemoryFilesystemAdapter::class);
} }
/** /**
@ -117,9 +121,10 @@ class FilesystemTest extends TestCase
$this->config('disk_driver.flarum-assets', 'null'); $this->config('disk_driver.flarum-assets', 'null');
/** @var FilesystemAdapter $assetsDisk */
$assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets');
$this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), NullAdapter::class); $this->assertEquals(get_class($assetsDisk->getAdapter()), InMemoryFilesystemAdapter::class);
} }
} }
@ -127,7 +132,13 @@ class NullFilesystemDriver implements DriverInterface
{ {
public function build(string $diskName, SettingsRepositoryInterface $settings, Config $config, array $localConfig): Cloud public function build(string $diskName, SettingsRepositoryInterface $settings, Config $config, array $localConfig): Cloud
{ {
return new FilesystemAdapter(new LeagueFilesystem(new NullAdapter())); // The internal adapter
$adapter = new InMemoryFilesystemAdapter();
// The FilesystemOperator
$filesystem = new \League\Flysystem\Filesystem($adapter);
return new FilesystemAdapter($filesystem, $adapter);
} }
} }

View File

@ -16,8 +16,8 @@ use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase; use Flarum\Testing\integration\TestCase;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Swift_NullTransport; use Symfony\Component\Mailer\Transport\NullTransport;
use Swift_Transport; use Symfony\Component\Mailer\Transport\TransportInterface;
class MailTest extends TestCase class MailTest extends TestCase
{ {
@ -110,8 +110,8 @@ class CustomDriver implements DriverInterface
return false; return false;
} }
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface
{ {
return new Swift_NullTransport; return new NullTransport();
} }
} }

View File

@ -21,8 +21,7 @@ use Illuminate\Filesystem\Filesystem;
use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use League\Flysystem\Adapter\Local; use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\Filesystem as FlysystemFilesystem;
class ExtensionManagerIncludeCurrent extends ExtensionManager class ExtensionManagerIncludeCurrent extends ExtensionManager
{ {
@ -108,6 +107,8 @@ class ExtensionManagerIncludeCurrent extends ExtensionManager
*/ */
protected function getAssetsFilesystem(): Cloud protected function getAssetsFilesystem(): Cloud
{ {
return new FilesystemAdapter(new FlysystemFilesystem(new Local($this->paths->public.'/assets'), ['url' => resolve('flarum.config')->url().'/assets'])); $adapter = new LocalFilesystemAdapter($this->paths->public.'/assets');
return new FilesystemAdapter(new \League\Flysystem\Filesystem($adapter), $adapter);
} }
} }