diff --git a/.env.example b/.env.example index 59099c0..f60fa60 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,9 @@ APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US APP_MAINTENANCE_DRIVER=file -APP_MAINTENANCE_STORE=database +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 BCRYPT_ROUNDS=12 @@ -19,32 +21,36 @@ LOG_STACK=single LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=mailcoach -DB_USERNAME=root -DB_PASSWORD= +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=mailcoach +# DB_USERNAME=root +# DB_PASSWORD= -BROADCAST_CONNECTION=log -CACHE_STORE=file -FILESYSTEM_DISK=local -QUEUE_CONNECTION=redis -SESSION_DRIVER=file +SESSION_DRIVER=database SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +CACHE_PREFIX= + MEMCACHED_HOST=127.0.0.1 +REDIS_CLIENT=phpredis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 -MAIL_MAILER=smtp -MAIL_HOST=mailhog -MAIL_PORT=1025 +MAIL_MAILER=log +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null @@ -57,17 +63,4 @@ AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false -PUSHER_APP_ID= -PUSHER_APP_KEY= -PUSHER_APP_SECRET= -PUSHER_HOST= -PUSHER_PORT=443 -PUSHER_SCHEME=https -PUSHER_APP_CLUSTER=mt1 - VITE_APP_NAME="${APP_NAME}" -VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" -VITE_PUSHER_HOST="${PUSHER_HOST}" -VITE_PUSHER_PORT="${PUSHER_PORT}" -VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" -VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" diff --git a/.gitignore b/.gitignore index dbe5a5b..c148f82 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,5 @@ composer.lock public/vendor public/js/filament public/css/filament -database/migrations -/.phpunit.cache \ No newline at end of file +/.phpunit.cache diff --git a/app/Providers/HorizonServiceProvider.php b/app/Providers/HorizonServiceProvider.php deleted file mode 100644 index 9b6ec71..0000000 --- a/app/Providers/HorizonServiceProvider.php +++ /dev/null @@ -1,34 +0,0 @@ - auth()->check()); - } -} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 4e3b440..38b258d 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -2,5 +2,4 @@ return [ App\Providers\AppServiceProvider::class, - App\Providers\HorizonServiceProvider::class, ]; diff --git a/composer.json b/composer.json index 4414fd9..4e5c975 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,9 @@ { + "$schema": "https://getcomposer.org/schema.json", "name": "spatie/mailcoach", "type": "project", - "description": "Self-host Mailcoach", - "keywords": [ - "mailcoach", - "spatie" - ], + "description": "Get started with Mailcoach Self-Hosted.", + "keywords": ["laravel", "mailcoach", "spatie"], "repositories": [ { "type": "composer", @@ -14,21 +12,19 @@ ], "require": { "php": "^8.2", - "guzzlehttp/guzzle": "^7.2", - "laravel/framework": "^11.3", - "laravel/horizon": "^5.22", + "laravel/framework": "^11.31", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.9", - "spatie/laravel-mailcoach": "^8.0" + "spatie/laravel-mailcoach": "^8.12" }, "require-dev": { "fakerphp/faker": "^1.23", + "laravel/pail": "^1.1", "laravel/pint": "^1.13", "laravel/sail": "^1.26", "mockery/mockery": "^1.6", - "nunomaduro/collision": "^8.0", - "phpunit/phpunit": "^10.5", - "spatie/laravel-ignition": "^2.4" + "nunomaduro/collision": "^8.1", + "phpunit/phpunit": "^11.0.1" }, "autoload": { "psr-4": { @@ -57,7 +53,10 @@ ], "post-create-project-cmd": [ "@php artisan key:generate --ansi", - "@php artisan mailcoach:publish" + "@php artisan mailcoach:publish", + "@php artisan vendor:publish --tag=mailcoach-migrations", + "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"", + "@php artisan migrate --graceful --ansi" ] }, "extra": { @@ -70,7 +69,8 @@ "preferred-install": "dist", "sort-packages": true, "allow-plugins": { - "pestphp/pest-plugin": true + "pestphp/pest-plugin": true, + "php-http/discovery": true } }, "minimum-stability": "dev", diff --git a/config/database.php b/config/database.php index 125949e..0af5c85 100644 --- a/config/database.php +++ b/config/database.php @@ -37,9 +37,9 @@ 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), - 'busy_timeout' => null, - 'journal_mode' => null, - 'synchronous' => null, + 'busy_timeout' => 5000, + 'journal_mode' => 'WAL', + 'synchronous' => 'NORMAL', ], 'mysql' => [ diff --git a/config/horizon.php b/config/horizon.php deleted file mode 100644 index f7e2d78..0000000 --- a/config/horizon.php +++ /dev/null @@ -1,205 +0,0 @@ - env('HORIZON_DOMAIN'), - - /* - |-------------------------------------------------------------------------- - | Horizon Path - |-------------------------------------------------------------------------- - | - | This is the URI path where Horizon will be accessible from. Feel free - | to change this path to anything you like. Note that the URI will not - | affect the paths of its internal API that aren't exposed to users. - | - */ - - 'path' => env('HORIZON_PATH', 'horizon'), - - /* - |-------------------------------------------------------------------------- - | Horizon Redis Connection - |-------------------------------------------------------------------------- - | - | This is the name of the Redis connection where Horizon will store the - | meta information required for it to function. It includes the list - | of supervisors, failed jobs, job metrics, and other information. - | - */ - - 'use' => 'default', - - /* - |-------------------------------------------------------------------------- - | Horizon Redis Prefix - |-------------------------------------------------------------------------- - | - | This prefix will be used when storing all Horizon data in Redis. You - | may modify the prefix when you are running multiple installations - | of Horizon on the same server so that they don't have problems. - | - */ - - 'prefix' => env( - 'HORIZON_PREFIX', - Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:' - ), - - /* - |-------------------------------------------------------------------------- - | Horizon Route Middleware - |-------------------------------------------------------------------------- - | - | These middleware will get attached onto each Horizon route, giving you - | the chance to add your own middleware to this list or change any of - | the existing middleware. Or, you can simply stick with this list. - | - */ - - 'middleware' => ['web'], - - /* - |-------------------------------------------------------------------------- - | Queue Wait Time Thresholds - |-------------------------------------------------------------------------- - | - | This option allows you to configure when the LongWaitDetected event - | will be fired. Every connection / queue combination may have its - | own, unique threshold (in seconds) before this event is fired. - | - */ - - 'waits' => [ - 'redis:default' => 60, - ], - - /* - |-------------------------------------------------------------------------- - | Job Trimming Times - |-------------------------------------------------------------------------- - | - | Here you can configure for how long (in minutes) you desire Horizon to - | persist the recent and failed jobs. Typically, recent jobs are kept - | for one hour while all failed jobs are stored for an entire week. - | - */ - - 'trim' => [ - 'recent' => 60, - 'pending' => 60, - 'completed' => 60, - 'recent_failed' => 10080, - 'failed' => 10080, - 'monitored' => 10080, - ], - - /* - |-------------------------------------------------------------------------- - | Metrics - |-------------------------------------------------------------------------- - | - | Here you can configure how many snapshots should be kept to display in - | the metrics graph. This will get used in combination with Horizon's - | `horizon:snapshot` schedule to define how long to retain metrics. - | - */ - - 'metrics' => [ - 'trim_snapshots' => [ - 'job' => 24, - 'queue' => 24, - ], - ], - - /* - |-------------------------------------------------------------------------- - | Fast Termination - |-------------------------------------------------------------------------- - | - | When this option is enabled, Horizon's "terminate" command will not - | wait on all of the workers to terminate unless the --wait option - | is provided. Fast termination can shorten deployment delay by - | allowing a new instance of Horizon to start while the last - | instance will continue to terminate each of its workers. - | - */ - - 'fast_termination' => false, - - /* - |-------------------------------------------------------------------------- - | Memory Limit (MB) - |-------------------------------------------------------------------------- - | - | This value describes the maximum amount of memory the Horizon master - | supervisor may consume before it is terminated and restarted. For - | configuring these limits on your workers, see the next section. - | - */ - - 'memory_limit' => 64, - - /* - |-------------------------------------------------------------------------- - | Queue Worker Configuration - |-------------------------------------------------------------------------- - | - | Here you may define the queue worker settings used by your application - | in all environments. These supervisors and settings handle all your - | queued jobs and will be provisioned by Horizon during deployment. - | - */ - - 'defaults' => [ - 'mailcoach-general' => [ - 'connection' => 'mailcoach-redis', - 'queue' => ['default', 'mailcoach-schedule', 'mailcoach', 'mailcoach-feedback', 'send-mail', 'send-automation-mail'], - 'balance' => 'auto', - 'processes' => 10, - 'tries' => 2, - 'timeout' => 60 * 60, - ], - 'mailcoach-heavy' => [ - 'connection' => 'mailcoach-redis', - 'queue' => ['send-campaign'], - 'balance' => 'auto', - 'processes' => 3, - 'tries' => 1, - 'timeout' => 60 * 60, - ], - ], - - 'environments' => [ - 'production' => [ - 'mailcoach-general' => [ - 'processes' => 10, - ], - 'mailcoach-heavy' => [ - 'processes' => 3, - ], - ], - - 'local' => [ - 'mailcoach-general' => [ - 'processes' => 5, - ], - 'mailcoach-heavy' => [ - 'processes' => 1, - ], - ], - ], -]; diff --git a/config/queue.php b/config/queue.php index 4d05236..116bd8d 100644 --- a/config/queue.php +++ b/config/queue.php @@ -72,15 +72,6 @@ 'after_commit' => false, ], - 'mailcoach-redis' => [ - 'driver' => 'redis', - 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), - 'queue' => env('REDIS_QUEUE', 'default'), - 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 60 * 60), - 'block_for' => null, - 'after_commit' => false, - ], - ], /* diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php similarity index 50% rename from database/migrations/2014_10_12_000000_create_users_table.php rename to database/migrations/0001_01_01_000000_create_users_table.php index 444fafb..05fb5d9 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -20,6 +20,21 @@ public function up(): void $table->rememberToken(); $table->timestamps(); }); + + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + + Schema::create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); } /** @@ -28,5 +43,7 @@ public function up(): void public function down(): void { Schema::dropIfExists('users'); + Schema::dropIfExists('password_reset_tokens'); + Schema::dropIfExists('sessions'); } }; diff --git a/database/migrations/0001_01_01_000001_create_cache_table.php b/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..b9c106b --- /dev/null +++ b/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/database/migrations/0001_01_01_000002_create_jobs_table.php b/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php b/database/migrations/0001_01_01_000003_create_personal_access_tokens_table.php similarity index 100% rename from database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php rename to database/migrations/0001_01_01_000003_create_personal_access_tokens_table.php diff --git a/database/migrations/2014_10_12_100000_create_password_resets_table.php b/database/migrations/2014_10_12_100000_create_password_resets_table.php deleted file mode 100644 index 4f42fe6..0000000 --- a/database/migrations/2014_10_12_100000_create_password_resets_table.php +++ /dev/null @@ -1,28 +0,0 @@ -string('email')->index(); - $table->string('token'); - $table->timestamp('created_at')->nullable(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('password_resets'); - } -}; diff --git a/database/migrations/2019_08_19_000000_create_failed_jobs_table.php b/database/migrations/2019_08_19_000000_create_failed_jobs_table.php deleted file mode 100644 index 249da81..0000000 --- a/database/migrations/2019_08_19_000000_create_failed_jobs_table.php +++ /dev/null @@ -1,32 +0,0 @@ -id(); - $table->string('uuid')->unique(); - $table->text('connection'); - $table->text('queue'); - $table->longText('payload'); - $table->longText('exception'); - $table->timestamp('failed_at')->useCurrent(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('failed_jobs'); - } -}; diff --git a/database/migrations/2023_09_18_000000_rename_password_resets_table.php b/database/migrations/2023_09_18_000000_rename_password_resets_table.php deleted file mode 100644 index c3f9489..0000000 --- a/database/migrations/2023_09_18_000000_rename_password_resets_table.php +++ /dev/null @@ -1,23 +0,0 @@ -hourly(); Schedule::command('mailcoach:send-email-list-summary-mail')->mondays()->at('9:00'); Schedule::command('mailcoach:delete-old-unconfirmed-subscribers')->daily(); - -Schedule::command('horizon:snapshot')->everyFiveMinutes();