From 1311321a4b6a4ce81c644b52f3ea8450a0341584 Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Fri, 31 Mar 2023 07:15:00 +0200 Subject: [PATCH] wip #5842 @1 --- app/Models/User.php | 6 +- app/Notifications/DownloadReady.php | 22 +- composer.json | 1 + composer.lock | 765 +++++++++++++++++- config/medialibrary.php | 156 ++++ config/webpush.php | 48 ++ ...065045_create_push_subscriptions_table.php | 36 + public/images/icons/icon-notification.png | Bin 0 -> 31914 bytes 8 files changed, 1019 insertions(+), 15 deletions(-) create mode 100644 config/medialibrary.php create mode 100644 config/webpush.php create mode 100644 database/migrations/2023_03_31_065045_create_push_subscriptions_table.php create mode 100644 public/images/icons/icon-notification.png diff --git a/app/Models/User.php b/app/Models/User.php index 81d3b92c2..909a9b8a2 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,9 +2,13 @@ namespace App\Models; +use NotificationChannels\WebPush\HasPushSubscriptions; + class User extends \Cubedesigners\UserDatabase\Models\User { - // protected $_syncDbSchema = false; + use HasPushSubscriptions; + + // protected $_syncDbSchema = false; public function scopeTeam($query) { $query->where('company', 7); diff --git a/app/Notifications/DownloadReady.php b/app/Notifications/DownloadReady.php index 0ca9018c7..3fa23a9b7 100644 --- a/app/Notifications/DownloadReady.php +++ b/app/Notifications/DownloadReady.php @@ -6,6 +6,8 @@ use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; use Illuminate\Support\HtmlString; +use NotificationChannels\WebPush\WebPushChannel; +use NotificationChannels\WebPush\WebPushMessage; class DownloadReady extends Notification { @@ -40,11 +42,11 @@ class DownloadReady extends Notification { if ($notifiable->slack) { if ($notifiable->id == 5) { - return ['database', FluidbookslackChannel::class, 'mail']; + return ['database', FluidbookslackChannel::class, 'mail', WebPushChannel::class]; } return ['database', FluidbookslackChannel::class]; } - return ['database', 'mail']; + return ['database', 'mail', WebPushChannel::class]; } /** @@ -68,6 +70,22 @@ class DownloadReady extends Notification } + public function toWebPush($notifiable) + { + $res = (new WebPushMessage) + ->title($this->subject) + ->icon('/images/icons/icon-notification.png') + ->lang($notifiable->locale) + ->options(['TTL' => 150]); + + foreach ($this->actions as $label => $url) { + $res->action($label, $url); + } + if ($this->showTextIfNotEmail) { + $res->body($this->text); + } + } + /** * Get the array representation of the notification. * diff --git a/composer.json b/composer.json index 7b3c9bf6e..559868b42 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "jolicode/slack-php-api": "^v4.5", "jsvrcek/ics": "^0.8.4", "larabug/larabug": "^2.5", + "laravel-notification-channels/webpush": "^7.1", "league/csv": "^9.8", "mxl/laravel-job": "^1.3", "nyholm/psr7": "^1.5", diff --git a/composer.lock b/composer.lock index 5c5a9ec91..56983e439 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9e1d830868759266a700df2a00576cf8", + "content-hash": "f0d82b7f6818c5bed0223a6fe93d460c", "packages": [ { "name": "ahmadshah/lucy", @@ -1660,13 +1660,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/cubist_cms-back.git", - "reference": "a97f1f76c7b4a1b3215547bec2afce5b3ce0747f" + "reference": "d3c2c4e5e13dfb63d851324d4e87a367219692dc" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-d88158.tar", - "reference": "a97f1f76c7b4a1b3215547bec2afce5b3ce0747f", - "shasum": "e98db0aaa9fbf6092e389a6810e32cf75425f2c3" + "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-ca37b0.tar", + "reference": "d3c2c4e5e13dfb63d851324d4e87a367219692dc", + "shasum": "1f3141c258a8d6d1a5eaf5c249597ab0053ccae3" }, "require": { "backpack/backupmanager": "^3.0", @@ -1747,7 +1747,7 @@ } ], "description": "Cubist Backpack extension", - "time": "2023-03-15T13:23:08+00:00" + "time": "2023-03-30T14:44:48+00:00" }, { "name": "cubist/cms-front", @@ -3505,13 +3505,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/fluidbook_tools.git", - "reference": "1321bea19745ffaf0d0944085dd7900ab8426e46" + "reference": "33472af7df33e6095bf65bdcefbd1162207ab3a6" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/fluidbook/tools/fluidbook-tools-dev-master-825435.tar", - "reference": "1321bea19745ffaf0d0944085dd7900ab8426e46", - "shasum": "e3dff8ef16fd5ac940104a5545e1417db423d4bc" + "url": "https://composer.cubedesigners.com/dist/fluidbook/tools/fluidbook-tools-dev-master-0eb654.tar", + "reference": "33472af7df33e6095bf65bdcefbd1162207ab3a6", + "shasum": "bad96b39e6fa52960158a1ef50a9da61dd909b5f" }, "require": { "barryvdh/laravel-debugbar": "^3.6", @@ -3545,7 +3545,7 @@ } ], "description": "Fluidbook Tools", - "time": "2023-03-22T17:17:02+00:00" + "time": "2023-03-30T09:40:52+00:00" }, { "name": "genealabs/laravel-model-caching", @@ -4954,6 +4954,64 @@ ], "time": "2021-11-10T08:45:45+00:00" }, + { + "name": "laravel-notification-channels/webpush", + "version": "7.1.0", + "source": { + "type": "git", + "url": "https://github.com/laravel-notification-channels/webpush.git", + "reference": "b31f7d807d30c80e7391063291ebfe9683bb7de5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel-notification-channels/webpush/zipball/b31f7d807d30c80e7391063291ebfe9683bb7de5", + "reference": "b31f7d807d30c80e7391063291ebfe9683bb7de5", + "shasum": "" + }, + "require": { + "illuminate/notifications": "^8.0|^9.0|^10.0", + "illuminate/support": "^8.0|^9.0|^10.0", + "minishlink/web-push": "^8.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "~1.0", + "orchestra/testbench": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NotificationChannels\\WebPush\\WebPushServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "NotificationChannels\\WebPush\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cretu Eusebiu", + "email": "me@cretueusebiu.com", + "homepage": "http://cretueusebiu.com", + "role": "Developer" + } + ], + "description": "Web Push Notifications driver for Laravel.", + "homepage": "https://github.com/laravel-notification-channels/webpush", + "support": { + "issues": "https://github.com/laravel-notification-channels/webpush/issues", + "source": "https://github.com/laravel-notification-channels/webpush/tree/7.1.0" + }, + "time": "2023-03-14T11:20:02+00:00" + }, { "name": "laravel/framework", "version": "v8.83.27", @@ -6181,6 +6239,73 @@ }, "time": "2022-03-28T17:43:20+00:00" }, + { + "name": "minishlink/web-push", + "version": "v8.0.0", + "source": { + "type": "git", + "url": "https://github.com/web-push-libs/web-push-php.git", + "reference": "ec034f1e287cd1e74235e349bd017d71a61e9d8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-push-libs/web-push-php/zipball/ec034f1e287cd1e74235e349bd017d71a61e9d8d", + "reference": "ec034f1e287cd1e74235e349bd017d71a61e9d8d", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^7.0.1|^6.2", + "php": ">=8.0", + "spomky-labs/base64url": "^2.0", + "web-token/jwt-key-mgmt": "^2.0|^3.0.2", + "web-token/jwt-signature": "^2.0|^3.0.2", + "web-token/jwt-signature-algorithm-ecdsa": "^2.0|^3.0.2", + "web-token/jwt-util-ecc": "^2.0|^3.0.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.13.2", + "phpstan/phpstan": "^1.9.8", + "phpunit/phpunit": "^9.5.27" + }, + "suggest": { + "ext-gmp": "Optional for performance." + }, + "type": "library", + "autoload": { + "psr-4": { + "Minishlink\\WebPush\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Louis Lagrange", + "email": "lagrange.louis@gmail.com", + "homepage": "https://github.com/Minishlink" + } + ], + "description": "Web Push library for PHP", + "homepage": "https://github.com/web-push-libs/web-push-php", + "keywords": [ + "Push API", + "WebPush", + "notifications", + "push", + "web" + ], + "support": { + "issues": "https://github.com/web-push-libs/web-push-php/issues", + "source": "https://github.com/web-push-libs/web-push-php/tree/v8.0.0" + }, + "time": "2023-01-10T17:14:44+00:00" + }, { "name": "mobiledetect/mobiledetectlib", "version": "2.8.41", @@ -6824,6 +6949,73 @@ }, "time": "2022-01-27T09:35:39+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.6.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "58c3f47f650c94ec05a151692652a868995d2938" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938", + "reference": "58c3f47f650c94ec05a151692652a868995d2938", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2022-06-14T06:56:20+00:00" + }, { "name": "php-ffmpeg/php-ffmpeg", "version": "v0.18.0", @@ -9457,6 +9649,181 @@ ], "time": "2022-08-23T07:15:15+00:00" }, + { + "name": "spomky-labs/base64url", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/base64url.git", + "reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/7752ce931ec285da4ed1f4c5aa27e45e097be61d", + "reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.11|^0.12", + "phpstan/phpstan-beberlei-assert": "^0.11|^0.12", + "phpstan/phpstan-deprecation-rules": "^0.11|^0.12", + "phpstan/phpstan-phpunit": "^0.11|^0.12", + "phpstan/phpstan-strict-rules": "^0.11|^0.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "description": "Base 64 URL Safe Encoding/Decoding PHP Library", + "homepage": "https://github.com/Spomky-Labs/base64url", + "keywords": [ + "base64", + "rfc4648", + "safe", + "url" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/base64url/issues", + "source": "https://github.com/Spomky-Labs/base64url/tree/v2.0.4" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2020-11-03T09:10:25+00:00" + }, + { + "name": "spomky-labs/pki-framework", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/pki-framework.git", + "reference": "d3ba688bf40e7c6e0dabf065ee18fc210734e760" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/d3ba688bf40e7c6e0dabf065ee18fc210734e760", + "reference": "d3ba688bf40e7c6e0dabf065ee18fc210734e760", + "shasum": "" + }, + "require": { + "brick/math": "^0.10 || ^0.11", + "ext-mbstring": "*", + "php": ">=8.1" + }, + "require-dev": { + "ekino/phpstan-banned-code": "^1.0", + "ext-gmp": "*", + "ext-openssl": "*", + "infection/infection": "^0.26", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-beberlei-assert": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^10.0", + "rector/rector": "^0.15", + "roave/security-advisories": "dev-latest", + "symfony/phpunit-bridge": "^6.1", + "symfony/var-dumper": "^6.1", + "symplify/easy-coding-standard": "^11.1", + "thecodingmachine/phpstan-safe-rule": "^1.2" + }, + "suggest": { + "ext-bcmath": "For better performance (or GMP)", + "ext-gmp": "For better performance (or BCMath)", + "ext-openssl": "For OpenSSL based cyphering" + }, + "type": "library", + "autoload": { + "psr-4": { + "SpomkyLabs\\Pki\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joni Eskelinen", + "email": "jonieske@gmail.com", + "role": "Original developer" + }, + { + "name": "Florent Morselli", + "email": "florent.morselli@spomky-labs.com", + "role": "Spomky-Labs PKI Framework developer" + } + ], + "description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.", + "homepage": "https://github.com/spomky-labs/pki-framework", + "keywords": [ + "DER", + "Private Key", + "ac", + "algorithm identifier", + "asn.1", + "asn1", + "attribute certificate", + "certificate", + "certification request", + "cryptography", + "csr", + "decrypt", + "ec", + "encrypt", + "pem", + "pkcs", + "public key", + "rsa", + "sign", + "signature", + "verify", + "x.509", + "x.690", + "x509", + "x690" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/pki-framework/issues", + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2023-02-13T17:21:24+00:00" + }, { "name": "swayok/alternative-laravel-cache", "version": "6.1.10", @@ -12560,6 +12927,380 @@ ], "time": "2022-01-24T18:55:24+00:00" }, + { + "name": "web-token/jwt-core", + "version": "3.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-core.git", + "reference": "ec2580e8cdd17410016216fbf1b645052c35f644" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-core/zipball/ec2580e8cdd17410016216fbf1b645052c35f644", + "reference": "ec2580e8cdd17410016216fbf1b645052c35f644", + "shasum": "" + }, + "require": { + "brick/math": "^0.9|^0.10|^0.11", + "ext-json": "*", + "ext-mbstring": "*", + "paragonie/constant_time_encoding": "^2.4", + "php": ">=8.1", + "spomky-labs/pki-framework": "^1.0" + }, + "conflict": { + "spomky-labs/jose": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jose\\Component\\Core\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "Core component of the JWT Framework.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-core/tree/3.1.7" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2023-02-02T17:25:26+00:00" + }, + { + "name": "web-token/jwt-key-mgmt", + "version": "3.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-key-mgmt.git", + "reference": "bf6dec304f2a718d70f7316e498c612317c59e08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-key-mgmt/zipball/bf6dec304f2a718d70f7316e498c612317c59e08", + "reference": "bf6dec304f2a718d70f7316e498c612317c59e08", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=8.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "web-token/jwt-core": "^3.0" + }, + "suggest": { + "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "php-http/httplug": "To enable JKU/X5U support.", + "php-http/message-factory": "To enable JKU/X5U support.", + "web-token/jwt-util-ecc": "To use EC key analyzers." + }, + "type": "library", + "autoload": { + "psr-4": { + "Jose\\Component\\KeyManagement\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-key-mgmt/contributors" + } + ], + "description": "Key Management component of the JWT Framework.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-key-mgmt/tree/3.1.7" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2023-02-02T17:25:26+00:00" + }, + { + "name": "web-token/jwt-signature", + "version": "3.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-signature.git", + "reference": "14b71230d9632564e356b785366ad36880964190" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/14b71230d9632564e356b785366ad36880964190", + "reference": "14b71230d9632564e356b785366ad36880964190", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "web-token/jwt-core": "^3.0" + }, + "suggest": { + "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms", + "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms", + "web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms", + "web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms", + "web-token/jwt-signature-algorithm-none": "None Signature Algorithm", + "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jose\\Component\\Signature\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-signature/contributors" + } + ], + "description": "Signature component of the JWT Framework.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-signature/tree/3.1.7" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2023-02-02T17:25:26+00:00" + }, + { + "name": "web-token/jwt-signature-algorithm-ecdsa", + "version": "3.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-signature-algorithm-ecdsa.git", + "reference": "e09159600f19832cf4a68921e7299e564bc0eaf9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-signature-algorithm-ecdsa/zipball/e09159600f19832cf4a68921e7299e564bc0eaf9", + "reference": "e09159600f19832cf4a68921e7299e564bc0eaf9", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=8.1", + "web-token/jwt-signature": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jose\\Component\\Signature\\Algorithm\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "ECDSA Based Signature Algorithms the JWT Framework.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-signature-algorithm-ecdsa/tree/3.1.7" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2022-08-04T21:04:09+00:00" + }, + { + "name": "web-token/jwt-util-ecc", + "version": "3.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-util-ecc.git", + "reference": "b2337052dbee724d710c1fdb0d3609835a5f8609" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-util-ecc/zipball/b2337052dbee724d710c1fdb0d3609835a5f8609", + "reference": "b2337052dbee724d710c1fdb0d3609835a5f8609", + "shasum": "" + }, + "require": { + "brick/math": "^0.9|^0.10|^0.11", + "php": ">=8.1" + }, + "suggest": { + "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance", + "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jose\\Component\\Core\\Util\\Ecc\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "ECC Tools for the JWT Framework.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-util-ecc/tree/3.1.7" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2023-02-02T13:35:41+00:00" + }, { "name": "webmozart/assert", "version": "1.11.0", @@ -15139,5 +15880,5 @@ "ext-zlib": "*" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.3.0" } diff --git a/config/medialibrary.php b/config/medialibrary.php new file mode 100644 index 000000000..a8957028d --- /dev/null +++ b/config/medialibrary.php @@ -0,0 +1,156 @@ + env('MEDIA_DISK', 'public'), + + /* + * The maximum file size of an item in bytes. + * Adding a larger file will result in an exception. + */ + 'max_file_size' => 1024 * 1024 * 10, + + /* + * This queue will be used to generate derived and responsive images. + * Leave empty to use the default queue. + */ + 'queue_name' => '', + + /* + * The fully qualified class name of the media model. + */ + 'media_model' => Spatie\MediaLibrary\Models\Media::class, + + 's3' => [ + /* + * The domain that should be prepended when generating urls. + */ + 'domain' => 'https://'.env('AWS_BUCKET').'.s3.amazonaws.com', + ], + + 'remote' => [ + /* + * Any extra headers that should be included when uploading media to + * a remote disk. Even though supported headers may vary between + * different drivers, a sensible default has been provided. + * + * Supported by S3: CacheControl, Expires, StorageClass, + * ServerSideEncryption, Metadata, ACL, ContentEncoding + */ + 'extra_headers' => [ + 'CacheControl' => 'max-age=604800', + ], + ], + + 'responsive_images' => [ + + /* + * This class is responsible for calculating the target widths of the responsive + * images. By default we optimize for filesize and create variations that each are 20% + * smaller than the previous one. More info in the documentation. + * + * https://docs.spatie.be/laravel-medialibrary/v7/advanced-usage/generating-responsive-images + */ + 'width_calculator' => Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\FileSizeOptimizedWidthCalculator::class, + + /* + * By default rendering media to a responsive image will add some javascript and a tiny placeholder. + * This ensures that the browser can already determine the correct layout. + */ + 'use_tiny_placeholders' => true, + + /* + * This class will generate the tiny placeholder used for progressive image loading. By default + * the medialibrary will use a tiny blurred jpg image. + */ + 'tiny_placeholder_generator' => Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\Blurred::class, + ], + + /* + * When urls to files get generated, this class will be called. Leave empty + * if your files are stored locally above the site root or on s3. + */ + 'url_generator' => null, + + /* + * Whether to activate versioning when urls to files get generated. + * When activated, this attaches a ?v=xx query string to the URL. + */ + 'version_urls' => false, + + /* + * The class that contains the strategy for determining a media file's path. + */ + 'path_generator' => null, + + /* + * Medialibrary will try to optimize all converted images by removing + * metadata and applying a little bit of compression. These are + * the optimizers that will be used by default. + */ + 'image_optimizers' => [ + Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [ + '--strip-all', // this strips out all text information such as comments and EXIF data + '--all-progressive', // this will make sure the resulting image is a progressive one + ], + Spatie\ImageOptimizer\Optimizers\Pngquant::class => [ + '--force', // required parameter for this package + ], + Spatie\ImageOptimizer\Optimizers\Optipng::class => [ + '-i0', // this will result in a non-interlaced, progressive scanned image + '-o2', // this set the optimization level to two (multiple IDAT compression trials) + '-quiet', // required parameter for this package + ], + Spatie\ImageOptimizer\Optimizers\Svgo::class => [ + '--disable=cleanupIDs', // disabling because it is known to cause troubles + ], + Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [ + '-b', // required parameter for this package + '-O3', // this produces the slowest but best results + ], + ], + + /* + * These generators will be used to create an image of media files. + */ + 'image_generators' => [ + Spatie\MediaLibrary\ImageGenerators\FileTypes\Image::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Webp::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Pdf::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Svg::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Video::class, + ], + + /* + * The engine that should perform the image conversions. + * Should be either `gd` or `imagick`. + */ + 'image_driver' => env('IMAGE_DRIVER', 'gd'), + + /* + * FFMPEG & FFProbe binaries paths, only used if you try to generate video + * thumbnails and have installed the php-ffmpeg/php-ffmpeg composer + * dependency. + */ + 'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'), + 'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'), + + /* + * The path where to store temporary files while performing image conversions. + * If set to null, storage_path('medialibrary/temp') will be used. + */ + 'temporary_directory_path' => null, + + /* + * Here you can override the class names of the jobs used by this package. Make sure + * your custom jobs extend the ones provided by the package. + */ + 'jobs' => [ + 'perform_conversions' => Spatie\MediaLibrary\Jobs\PerformConversions::class, + 'generate_responsive_images' => Spatie\MediaLibrary\Jobs\GenerateResponsiveImages::class, + ], +]; diff --git a/config/webpush.php b/config/webpush.php new file mode 100644 index 000000000..bef3e6653 --- /dev/null +++ b/config/webpush.php @@ -0,0 +1,48 @@ + [ + 'subject' => env('VAPID_SUBJECT'), + 'public_key' => env('VAPID_PUBLIC_KEY'), + 'private_key' => env('VAPID_PRIVATE_KEY'), + 'pem_file' => env('VAPID_PEM_FILE'), + ], + + /** + * This is model that will be used to for push subscriptions. + */ + 'model' => \NotificationChannels\WebPush\PushSubscription::class, + + /** + * This is the name of the table that will be created by the migration and + * used by the PushSubscription model shipped with this package. + */ + 'table_name' => env('WEBPUSH_DB_TABLE', 'push_subscriptions'), + + /** + * This is the database connection that will be used by the migration and + * the PushSubscription model shipped with this package. + */ + 'database_connection' => env('WEBPUSH_DB_CONNECTION', env('DB_CONNECTION', 'mysql')), + + /** + * The Guzzle client options used by Minishlink\WebPush. + */ + 'client_options' => [], + + /** + * Google Cloud Messaging. + * + * @deprecated + */ + 'gcm' => [ + 'key' => env('GCM_KEY'), + 'sender_id' => env('GCM_SENDER_ID'), + ], + +]; diff --git a/database/migrations/2023_03_31_065045_create_push_subscriptions_table.php b/database/migrations/2023_03_31_065045_create_push_subscriptions_table.php new file mode 100644 index 000000000..550a98f6a --- /dev/null +++ b/database/migrations/2023_03_31_065045_create_push_subscriptions_table.php @@ -0,0 +1,36 @@ +create(config('webpush.table_name'), function (Blueprint $table) { + $table->bigIncrements('id'); + $table->morphs('subscribable'); + $table->string('endpoint', 500)->unique(); + $table->string('public_key')->nullable(); + $table->string('auth_token')->nullable(); + $table->string('content_encoding')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::connection(config('webpush.database_connection'))->dropIfExists(config('webpush.table_name')); + } +} diff --git a/public/images/icons/icon-notification.png b/public/images/icons/icon-notification.png new file mode 100644 index 0000000000000000000000000000000000000000..bd6f3996202519b56f51683b1a295b1d07028833 GIT binary patch literal 31914 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 UdCclx196bDf|`7_tZB&q0WCspY5)KL literal 0 HcmV?d00001 -- 2.39.5