Fix errors with Webhooks and error templates.

This commit is contained in:
Buster Neece 2022-11-17 09:13:41 -06:00
parent 33a1c84b5a
commit 3068f7c4e7
No known key found for this signature in database
GPG Key ID: F1D2E64A0005E80E
22 changed files with 108 additions and 128 deletions

View File

@ -9,6 +9,7 @@ use App\Environment;
use App\Exception;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\ServiceControl;
use Psr\Http\Message\ResponseInterface;
final class LogsAction
@ -16,7 +17,8 @@ final class LogsAction
use HasLogViewer;
public function __construct(
private readonly Environment $environment
private readonly Environment $environment,
private readonly ServiceControl $serviceControl,
) {
}
@ -78,37 +80,19 @@ final class LogsAction
];
if ($this->environment->isDocker()) {
$langServiceLog = __('%s Service Log');
$logPaths['service_mariadb'] = [
'name' => sprintf($langServiceLog, __('MariaDB')),
'path' => $tempDir . '/service_mariadb.log',
'tail' => true,
];
$logPaths['service_redis'] = [
'name' => sprintf($langServiceLog, __('Redis')),
'path' => $tempDir . '/service_redis.log',
'tail' => true,
];
$logPaths['service_beanstalkd'] = [
'name' => sprintf($langServiceLog, __('Beanstalkd')),
'path' => $tempDir . '/service_beanstalkd.log',
'tail' => true,
];
$logPaths['service_cron'] = [
'name' => sprintf($langServiceLog, __('Cron')),
'path' => $tempDir . '/service_crond.log',
'tail' => true,
];
$logPaths['service_nginx'] = [
'name' => sprintf($langServiceLog, __('Nginx')),
'path' => $tempDir . '/service_nginx.log',
'tail' => true,
];
$logPaths['service_sftpgo'] = [
'name' => sprintf($langServiceLog, __('SFTPGo')),
'path' => $tempDir . '/service_sftpgo.log',
'tail' => true,
];
$langServiceLog = __('Service Log: %s (%s)');
foreach ($this->serviceControl->getServiceNames() as $serviceKey => $serviceName) {
$logPath = $tempDir . '/service_' . $serviceKey . '.log';
if (is_file($logPath)) {
$logPaths['service_' . $serviceKey] = [
'name' => sprintf($langServiceLog, $serviceKey, $serviceName),
'path' => $logPath,
'tail' => true,
];
}
}
} else {
$logPaths['nginx_access'] = [
'name' => __('Nginx Access Log'),

View File

@ -10,10 +10,13 @@ use App\Entity;
use App\Enums\SupportedLocales;
use App\Enums\SupportedThemes;
use App\Http\ServerRequest;
use App\Traits\RequestAwareTrait;
use Psr\Http\Message\ServerRequestInterface;
final class Customization
{
use RequestAwareTrait;
private ?Entity\User $user = null;
private Entity\Settings $settings;
@ -28,22 +31,34 @@ final class Customization
public function __construct(
private readonly Environment $environment,
Entity\Repository\SettingsRepository $settingsRepo,
ServerRequestInterface $request
Entity\Repository\SettingsRepository $settingsRepo
) {
$this->settings = $settingsRepo->readSettings();
$this->instanceName = $this->settings->getInstanceName() ?? '';
// Register current user
$this->user = $request->getAttribute(ServerRequest::ATTR_USER);
$this->user = null;
$this->theme = SupportedThemes::default();
$this->publicTheme = $this->settings->getPublicThemeEnum();
// Register current theme
$this->theme = $this->determineTheme($request);
$this->publicTheme = $this->determineTheme($request, true);
$this->locale = SupportedLocales::default();
}
// Register locale
$this->locale = SupportedLocales::createFromRequest($this->environment, $request);
public function setRequest(?ServerRequestInterface $request): void
{
$this->request = $request;
if (null !== $request) {
// Register current user
$this->user = $request->getAttribute(ServerRequest::ATTR_USER);
// Register current theme
$this->theme = $this->determineTheme($request);
$this->publicTheme = $this->determineTheme($request, true);
// Register locale
$this->locale = SupportedLocales::createFromRequest($this->environment, $request);
}
}
private function determineTheme(

View File

@ -13,7 +13,6 @@ use App\Exception\PermissionDeniedException;
use App\Middleware\InjectSession;
use App\Session\Flash;
use App\View;
use DI\FactoryInterface;
use Mezzio\Session\Session;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface;
@ -34,7 +33,7 @@ final class ErrorHandler extends \Slim\Handlers\ErrorHandler
private string $loggerLevel = LogLevel::ERROR;
public function __construct(
private readonly FactoryInterface $factory,
private readonly View $view,
private readonly Router $router,
private readonly InjectSession $injectSession,
private readonly Environment $environment,
@ -142,14 +141,9 @@ final class ErrorHandler extends \Slim\Handlers\ErrorHandler
return $response->withJson($apiResponse);
}
try {
$view = $this->factory->make(
View::class,
[
'request' => $this->request,
]
);
$view = $this->view->withRequest($this->request);
try {
return $view->renderToResponse(
$response,
'system/error_http',
@ -247,14 +241,9 @@ final class ErrorHandler extends \Slim\Handlers\ErrorHandler
return $response->write($run->handleException($this->exception));
}
try {
$view = $this->factory->make(
View::class,
[
'request' => $this->request,
]
);
$view = $this->view->withRequest($this->request);
try {
return $view->renderToResponse(
$response,
'system/error_general',

View File

@ -17,20 +17,16 @@ use Psr\Http\Server\RequestHandlerInterface;
abstract class AbstractAuth implements MiddlewareInterface
{
public function __construct(
protected Entity\Repository\SettingsRepository $settingsRepo,
protected Environment $environment,
protected Acl $acl
protected readonly Entity\Repository\UserRepository $userRepo,
protected readonly Environment $environment,
protected readonly Acl $acl,
protected readonly Customization $customization
) {
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// Initialize Customization (timezones, locales, etc) based on the current logged in user.
$customization = new Customization(
environment: $this->environment,
settingsRepo: $this->settingsRepo,
request: $request
);
$customization = $this->customization->withRequest($request);
// Initialize ACL (can only be initialized after Customization as it contains localizations).
$acl = $this->acl->withRequest($request);

View File

@ -6,6 +6,7 @@ namespace App\Middleware\Auth;
use App\Acl;
use App\Auth;
use App\Customization;
use App\Entity;
use App\Environment;
use App\Exception\CsrfValidationException;
@ -21,13 +22,13 @@ final class ApiAuth extends AbstractAuth
public const API_CSRF_NAMESPACE = 'api';
public function __construct(
protected Entity\Repository\UserRepository $userRepo,
protected Entity\Repository\ApiKeyRepository $apiKeyRepo,
Entity\Repository\SettingsRepository $settingsRepo,
Entity\Repository\UserRepository $userRepo,
Environment $environment,
Acl $acl
Acl $acl,
Customization $customization
) {
parent::__construct($settingsRepo, $environment, $acl);
parent::__construct($userRepo, $environment, $acl, $customization);
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface

View File

@ -4,10 +4,7 @@ declare(strict_types=1);
namespace App\Middleware\Auth;
use App\Acl;
use App\Auth;
use App\Entity;
use App\Environment;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
@ -15,15 +12,6 @@ use Psr\Http\Server\RequestHandlerInterface;
final class StandardAuth extends AbstractAuth
{
public function __construct(
private readonly Entity\Repository\UserRepository $userRepo,
Entity\Repository\SettingsRepository $settingsRepo,
Environment $environment,
Acl $acl
) {
parent::__construct($settingsRepo, $environment, $acl);
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// Initialize the Auth for this request.

View File

@ -22,9 +22,9 @@ final class GetCurrentUser implements MiddlewareInterface
{
public function __construct(
private readonly Entity\Repository\UserRepository $userRepo,
private readonly Entity\Repository\SettingsRepository $settingsRepo,
private readonly Environment $environment,
private readonly Acl $acl
private readonly Acl $acl,
private readonly Customization $customization
) {
}
@ -44,11 +44,7 @@ final class GetCurrentUser implements MiddlewareInterface
->withAttribute('is_logged_in', (null !== $user));
// Initialize Customization (timezones, locales, etc) based on the current logged in user.
$customization = new Customization(
environment: $this->environment,
settingsRepo: $this->settingsRepo,
request: $request
);
$customization = $this->customization->withRequest($request);
// Initialize ACL (can only be initialized after Customization as it contains localizations).
$acl = $this->acl->withRequest($request);

View File

@ -24,6 +24,7 @@ final class View extends Engine
private readonly GlobalSections $sections;
public function __construct(
Customization $customization,
Environment $environment,
EventDispatcherInterface $dispatcher,
Version $version,
@ -37,6 +38,7 @@ final class View extends Engine
$this->addData(
[
'sections' => $this->sections,
'customization' => $customization,
'environment' => $environment,
'version' => $version,
'router' => $router,
@ -99,17 +101,25 @@ final class View extends Engine
$this->request = $request;
if (null !== $request) {
$this->addData(
[
'request' => $request,
'router' => $request->getAttribute(ServerRequest::ATTR_ROUTER),
'auth' => $request->getAttribute(ServerRequest::ATTR_AUTH),
'acl' => $request->getAttribute(ServerRequest::ATTR_ACL),
'customization' => $request->getAttribute(ServerRequest::ATTR_CUSTOMIZATION),
'flash' => $request->getAttribute(ServerRequest::ATTR_SESSION_FLASH),
'user' => $request->getAttribute(ServerRequest::ATTR_USER),
]
);
$requestData = [
'request' => $request,
'auth' => $request->getAttribute(ServerRequest::ATTR_AUTH),
'acl' => $request->getAttribute(ServerRequest::ATTR_ACL),
'flash' => $request->getAttribute(ServerRequest::ATTR_SESSION_FLASH),
'user' => $request->getAttribute(ServerRequest::ATTR_USER),
];
$router = $request->getAttribute(ServerRequest::ATTR_ROUTER);
if (null !== $router) {
$requestData['router'] = $router;
}
$customization = $request->getAttribute(ServerRequest::ATTR_CUSTOMIZATION);
if (null !== $customization) {
$requestData['customization'] = $customization;
}
$this->addData($requestData);
}
}

View File

@ -115,12 +115,12 @@ abstract class AbstractConnector implements ConnectorInterface
return (preg_match($pattern, $url)) ? $url : null;
}
protected function incompleteConfigException(): \InvalidArgumentException
protected function incompleteConfigException(string $name): \InvalidArgumentException
{
return new \InvalidArgumentException(
sprintf(
'Webhook %s is missing necessary configuration. Skipping...',
static::NAME
$name
),
);
}

View File

@ -77,7 +77,7 @@ final class Discord extends AbstractConnector
$webhook_url = $this->getValidUrl($config['webhook_url'] ?? '');
if (empty($webhook_url)) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
$raw_vars = [

View File

@ -40,7 +40,7 @@ final class Email extends AbstractConnector
$emailBody = $config['message'];
if (empty($emailTo) || empty($emailSubject) || empty($emailBody)) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
$email = $this->mail->createMessage();

View File

@ -24,7 +24,7 @@ final class Generic extends AbstractConnector
$webhook_url = $this->getValidUrl($config['webhook_url'] ?? '');
if (empty($webhook_url)) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
$request_options = [

View File

@ -34,7 +34,7 @@ final class GoogleAnalytics extends AbstractConnector
): void {
$config = $webhook->getConfig();
if (empty($config['tracking_id'])) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
// Get listen URLs for each mount point.

View File

@ -34,7 +34,7 @@ final class Mastodon extends AbstractConnector
$accessToken = trim($config['access_token'] ?? '');
if (empty($instanceUrl) || empty($accessToken)) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
$messages = $this->replaceVariables(

View File

@ -36,7 +36,7 @@ final class MatomoAnalytics extends AbstractConnector
$config = $webhook->getConfig();
if (empty($config['matomo_url']) || empty($config['site_id'])) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
// Get listen URLs for each mount point.

View File

@ -30,7 +30,7 @@ final class Telegram extends AbstractConnector
$chat_id = trim($config['chat_id'] ?? '');
if (empty($bot_token) || empty($chat_id)) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
$messages = $this->replaceVariables(

View File

@ -27,7 +27,7 @@ final class TuneIn extends AbstractConnector
$config = $webhook->getConfig();
if (empty($config['partner_id']) || empty($config['partner_key']) || empty($config['station_id'])) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
$this->logger->debug('Dispatching TuneIn AIR API call...');

View File

@ -47,7 +47,7 @@ final class Twitter extends AbstractConnector
|| empty($config['token'])
|| empty($config['token_secret'])
) {
throw $this->incompleteConfigException();
throw $this->incompleteConfigException(self::NAME);
}
// Set up Twitter OAuth

View File

@ -51,7 +51,16 @@ final class Dispatcher
$triggers = $message->triggers;
// Always dispatch the special "local" updater task.
$this->localHandler->dispatch($station, $np);
try {
$this->localHandler->dispatch($station, $np);
} catch (\Throwable $e) {
$this->logger->error(
sprintf('%s L%d: %s', $e->getFile(), $e->getLine(), $e->getMessage()),
[
'exception' => $e,
]
);
}
if ($this->environment->isTesting()) {
$this->logger->notice('In testing mode; no webhooks dispatched.');
@ -74,18 +83,12 @@ final class Dispatcher
$this->logger->debug(sprintf('Dispatching connector "%s".', $webhook->getType()));
try {
if ($connectorObj->dispatch($station, $webhook, $np, $triggers)) {
$webhook->updateLastSentTimestamp();
$this->em->persist($webhook);
}
$connectorObj->dispatch($station, $webhook, $np, $triggers);
$webhook->updateLastSentTimestamp();
$this->em->persist($webhook);
} catch (\Throwable $e) {
$this->logger->error(
sprintf(
'%s L%d: %s',
$e->getFile(),
$e->getLine(),
$e->getMessage()
),
sprintf('%s L%d: %s', $e->getFile(), $e->getLine(), $e->getMessage()),
[
'exception' => $e,
]

View File

@ -6,7 +6,6 @@ namespace App\Webhook;
use App\Entity;
use App\Environment;
use GuzzleHttp\Client;
use Monolog\Logger;
use Symfony\Component\Filesystem\Filesystem;
@ -18,7 +17,6 @@ final class LocalWebhookHandler
public function __construct(
private readonly Logger $logger,
private readonly Client $httpClient,
private readonly Environment $environment,
) {
}

View File

@ -10,11 +10,11 @@ $this->layout('minimal', [
<div class="card-body">
<h2 class="display-1 mt-2">500</h2>
<p>
<?=$exception->getMessage() ?><br>
<?=basename($exception->getFile()) ?> : <?=$exception->getLine() ?>
<?= $exception->getMessage() ?><br>
<?= basename($exception->getFile()) ?> : <?= $exception->getLine() ?>
</p>
<a role="button" title="<?=__('Dashboard') ?>" class="btn btn-login btn-primary btn-float" href="<?=$router->named('home') ?>">
<a role="button" title="<?= __('Dashboard') ?>" class="btn btn-login btn-primary btn-float" href="/">
<i class="material-icons" aria-hidden="true">home</i>
</a>
</div>

View File

@ -15,7 +15,7 @@ $this->layout('minimal', [
<p><?=$exception->getDescription()?></p>
<a role="button" title="<?=__('Dashboard')?>" class="btn btn-login btn-primary btn-float"
href="<?=$router->named('home')?>">
href="/">
<i class="material-icons" aria-hidden="true">home</i>
</a>
</div>