Compare commits
28 Commits
v26.0.2
...
8270e635d6
| Author | SHA1 | Date | |
|---|---|---|---|
| 8270e635d6 | |||
| d724f80cad | |||
| 1f5f340ce4 | |||
| 40e111b3a6 | |||
| 506011f933 | |||
| 80a8b86a08 | |||
| c1cb3f394a | |||
| 31c8491aaf | |||
| 0ad5916504 | |||
| bac70c3927 | |||
| bf23e46e2d | |||
| 55b9a69c42 | |||
| b6ce5160f9 | |||
| d279e7f36f | |||
| a0d914ea24 | |||
| ce3b89d54e | |||
| 5cd8a1a9d6 | |||
| 6f9d9f9e7a | |||
| db7f088b36 | |||
| 54d4cd7f99 | |||
| af03c23c9f | |||
| 68dd17f895 | |||
| 8249df15df | |||
| f167e64d00 | |||
| 95ebc7778d | |||
| c67a3ec6d0 | |||
| bf278667bc | |||
| 30a06e18f0 |
@@ -37,3 +37,24 @@ jobs:
|
|||||||
echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass.txt
|
echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass.txt
|
||||||
ansible-playbook --vault-password-file .vault_pass.txt deploy-to-prod.yaml
|
ansible-playbook --vault-password-file .vault_pass.txt deploy-to-prod.yaml
|
||||||
rm .vault_pass.txt
|
rm .vault_pass.txt
|
||||||
|
|
||||||
|
promote_stable:
|
||||||
|
runs-on: self-hosted
|
||||||
|
needs: deploy
|
||||||
|
steps:
|
||||||
|
- name: Promote master to stable
|
||||||
|
env:
|
||||||
|
SPEEDBB_REPO: ${{ vars.SPEEDBB_REPO }}
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
GITEA_ACTOR: ${{ gitea.actor }}
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
REPO="$SPEEDBB_REPO"
|
||||||
|
if [ -n "$GITEA_TOKEN" ]; then
|
||||||
|
REPO=$(echo "$SPEEDBB_REPO" | sed "s#https://#https://${GITEA_ACTOR}:${GITEA_TOKEN}@#")
|
||||||
|
fi
|
||||||
|
git clone --quiet --depth=1 --branch=stable "$REPO" repo
|
||||||
|
cd repo
|
||||||
|
git fetch origin master
|
||||||
|
git merge --ff-only FETCH_HEAD
|
||||||
|
git push origin stable
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -22,12 +22,14 @@
|
|||||||
/public/build
|
/public/build
|
||||||
/public/hot
|
/public/hot
|
||||||
/public/storage
|
/public/storage
|
||||||
|
/public/custom
|
||||||
/storage/app
|
/storage/app
|
||||||
/storage/framework
|
/storage/framework
|
||||||
/storage/*.key
|
/storage/*.key
|
||||||
/storage/pail
|
/storage/pail
|
||||||
/storage/framework/views/*.php
|
/storage/framework/views/*.php
|
||||||
/bootstrap/cache/*.php
|
/bootstrap/cache/*.php
|
||||||
|
/custom
|
||||||
/vendor
|
/vendor
|
||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,9 +1,21 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-02-12
|
||||||
|
- Refined ACP System tab with left navigation, section-specific requirements, and CLI PHP selector.
|
||||||
|
- Added CLI PHP interpreter options (php, keyhelp-php-domain, custom) with KeyHelp guidance.
|
||||||
|
- Updated CLI update tooling and automation notes (KeyHelp PHP handling, CI runner requirements).
|
||||||
|
- Adjusted ACP layout and tab styling for better dark-mode readability and auto-sizing sidebars.
|
||||||
|
- Added Custom top-level ACP tab and preserved /custom paths during in-app updates.
|
||||||
|
|
||||||
|
## 2026-02-10
|
||||||
|
- Reshaped ACP System tab with left navigation and dedicated views (Overview, Live Update, CLI, CI/CD).
|
||||||
|
- Moved system requirements table into the CI/CD view with refresh controls.
|
||||||
|
|
||||||
## 2026-02-08
|
## 2026-02-08
|
||||||
- Achieved 100% test coverage across the backend.
|
- Achieved 100% test coverage across the backend.
|
||||||
- Added comprehensive Feature and Unit tests for controllers, models, services, and console commands.
|
- Added comprehensive Feature and Unit tests for controllers, models, services, and console commands.
|
||||||
- Added extensive edge-case and error-path coverage (system update/status, versioning, attachments, forums, roles, ranks, settings, portal, etc.).
|
- Added extensive edge-case and error-path coverage (system update/status, versioning, attachments, forums, roles, ranks, settings, portal, etc.).
|
||||||
|
- Added `git_update.sh` for CLI-based updates (stable branch, deps, build, migrations, version sync).
|
||||||
|
|
||||||
## 2026-01-12
|
## 2026-01-12
|
||||||
- Switched main SPA layouts to fluid containers to reduce wasted space.
|
- Switched main SPA layouts to fluid containers to reduce wasted space.
|
||||||
|
|||||||
8
NOTES.md
8
NOTES.md
@@ -1,7 +1,15 @@
|
|||||||
TODO: Remove remaining IIFEs in ACP UI; prefer plain components/helpers.
|
TODO: Remove remaining IIFEs in ACP UI; prefer plain components/helpers.
|
||||||
|
Add git_update.sh script to update the forum and core.
|
||||||
|
Tag the release as latest
|
||||||
|
For update, make three tabs: insite, cli, ci/di and add explanation
|
||||||
|
|
||||||
Progress (last 2 days):
|
Progress (last 2 days):
|
||||||
- Reached 100% test coverage across the codebase.
|
- Reached 100% test coverage across the codebase.
|
||||||
- Added extensive Feature and Unit tests for controllers, models, services, and console commands.
|
- Added extensive Feature and Unit tests for controllers, models, services, and console commands.
|
||||||
- Added coverage scripts and cleanup (tests for update/version flows, system update/status, attachments, forums, roles, ranks, settings, portal, etc.).
|
- Added coverage scripts and cleanup (tests for update/version flows, system update/status, attachments, forums, roles, ranks, settings, portal, etc.).
|
||||||
- Hardened tests with fakes/mocks to cover error paths and edge cases.
|
- Hardened tests with fakes/mocks to cover error paths and edge cases.
|
||||||
|
|
||||||
|
TODO: Make the PHP binary path configurable for updates if the default PHP is outdated (ACP -> System).
|
||||||
|
CI/CD: Runner must have PHP 8.4+ as the default CLI interpreter.
|
||||||
|
KeyHelp: `keyhelp-php-domain` can select the PHP version based on the domain of the script location.
|
||||||
|
KeyHelp: `keyhelp-php-domain` is a Pro feature; on non-Pro setups we must fake the command.
|
||||||
|
|||||||
@@ -21,12 +21,31 @@
|
|||||||
path: "{{ prod_base_dir }}/.env"
|
path: "{{ prod_base_dir }}/.env"
|
||||||
register: env_file
|
register: env_file
|
||||||
|
|
||||||
|
- name: Ensure bootstrap cache directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ prod_base_dir }}/bootstrap/cache"
|
||||||
|
state: directory
|
||||||
|
mode: "0775"
|
||||||
|
|
||||||
- name: Download and installs all libs and dependencies
|
- name: Download and installs all libs and dependencies
|
||||||
|
block:
|
||||||
|
- name: Composer install
|
||||||
community.general.composer:
|
community.general.composer:
|
||||||
command: install
|
command: install
|
||||||
arguments: --no-dev --optimize-autoloader
|
arguments: --no-dev --optimize-autoloader
|
||||||
working_dir: "{{ prod_base_dir }}"
|
working_dir: "{{ prod_base_dir }}"
|
||||||
php_path: /usr/bin/keyhelp-php84
|
php_path: /usr/bin/keyhelp-php84
|
||||||
|
rescue:
|
||||||
|
- name: Debug package discovery
|
||||||
|
shell: |
|
||||||
|
keyhelp-php84 artisan package:discover -v --ansi 2>&1 | tail -n 200
|
||||||
|
args:
|
||||||
|
chdir: "{{ prod_base_dir }}"
|
||||||
|
register: package_discover_debug
|
||||||
|
- debug:
|
||||||
|
var: package_discover_debug.stdout_lines
|
||||||
|
- fail:
|
||||||
|
msg: "Composer install failed; see package:discover output above."
|
||||||
|
|
||||||
- name: Install node_modules
|
- name: Install node_modules
|
||||||
npm:
|
npm:
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ class BbcodeFormatter
|
|||||||
|
|
||||||
private static function build(): array
|
private static function build(): array
|
||||||
{
|
{
|
||||||
|
if (app()->environment('testing') && env('BBCODE_FORCE_FAIL')) {
|
||||||
|
throw new \RuntimeException('Unable to initialize BBCode formatter.');
|
||||||
|
}
|
||||||
|
|
||||||
$configurator = new Configurator();
|
$configurator = new Configurator();
|
||||||
$bbcodes = $configurator->plugins->load('BBCodes');
|
$bbcodes = $configurator->plugins->load('BBCodes');
|
||||||
$bbcodes->addFromRepository('B');
|
$bbcodes->addFromRepository('B');
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Setting;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
@@ -16,9 +17,12 @@ class SystemStatusController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$phpDefaultPath = $this->resolveBinary('php');
|
$phpDefaultPath = $this->resolveBinary('php');
|
||||||
$phpSelectedPath = PHP_BINARY ?: $phpDefaultPath;
|
$phpConfiguredPath = trim((string) Setting::where('key', 'system.php_binary')->value('value'));
|
||||||
|
$phpSelectedPath = $phpConfiguredPath ?: (PHP_BINARY ?: $phpDefaultPath);
|
||||||
$phpSelectedOk = (bool) $phpSelectedPath;
|
$phpSelectedOk = (bool) $phpSelectedPath;
|
||||||
$phpSelectedVersion = PHP_VERSION;
|
$phpSelectedVersion = $phpSelectedPath
|
||||||
|
? ($this->resolvePhpVersion($phpSelectedPath) ?? PHP_VERSION)
|
||||||
|
: PHP_VERSION;
|
||||||
$minVersions = $this->resolveMinVersions();
|
$minVersions = $this->resolveMinVersions();
|
||||||
$composerPath = $this->resolveBinary('composer');
|
$composerPath = $this->resolveBinary('composer');
|
||||||
$nodePath = $this->resolveBinary('node');
|
$nodePath = $this->resolveBinary('node');
|
||||||
@@ -40,6 +44,7 @@ class SystemStatusController extends Controller
|
|||||||
return response()->json([
|
return response()->json([
|
||||||
'php' => PHP_VERSION,
|
'php' => PHP_VERSION,
|
||||||
'php_default' => $phpDefaultPath,
|
'php_default' => $phpDefaultPath,
|
||||||
|
'php_configured' => $phpConfiguredPath ?: null,
|
||||||
'php_selected_path' => $phpSelectedPath,
|
'php_selected_path' => $phpSelectedPath,
|
||||||
'php_selected_ok' => $phpSelectedOk,
|
'php_selected_ok' => $phpSelectedOk,
|
||||||
'php_selected_version' => $phpSelectedVersion,
|
'php_selected_version' => $phpSelectedVersion,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Setting;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
@@ -112,6 +113,7 @@ class SystemUpdateController extends Controller
|
|||||||
$append('Syncing files...');
|
$append('Syncing files...');
|
||||||
$usedRsync = false;
|
$usedRsync = false;
|
||||||
$rsyncPath = trim((string) shell_exec('command -v rsync'));
|
$rsyncPath = trim((string) shell_exec('command -v rsync'));
|
||||||
|
$protectedPaths = ['custom', 'public/custom'];
|
||||||
if ($rsyncPath !== '') {
|
if ($rsyncPath !== '') {
|
||||||
$usedRsync = true;
|
$usedRsync = true;
|
||||||
$rsync = new Process([
|
$rsync = new Process([
|
||||||
@@ -121,6 +123,8 @@ class SystemUpdateController extends Controller
|
|||||||
'--exclude=.env',
|
'--exclude=.env',
|
||||||
'--exclude=storage',
|
'--exclude=storage',
|
||||||
'--exclude=public/storage',
|
'--exclude=public/storage',
|
||||||
|
'--exclude=custom',
|
||||||
|
'--exclude=public/custom',
|
||||||
$sourceDir . '/',
|
$sourceDir . '/',
|
||||||
base_path() . '/',
|
base_path() . '/',
|
||||||
]);
|
]);
|
||||||
@@ -133,6 +137,15 @@ class SystemUpdateController extends Controller
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
foreach ($protectedPaths as $path) {
|
||||||
|
$sourcePath = $sourceDir . DIRECTORY_SEPARATOR . $path;
|
||||||
|
if (File::exists($sourcePath)) {
|
||||||
|
File::deleteDirectory($sourcePath);
|
||||||
|
if (File::exists($sourcePath)) {
|
||||||
|
File::delete($sourcePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File::copyDirectory($sourceDir, base_path());
|
File::copyDirectory($sourceDir, base_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +182,10 @@ class SystemUpdateController extends Controller
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
$phpBinary = PHP_BINARY ?: 'php';
|
$phpBinary = trim((string) Setting::where('key', 'system.php_binary')->value('value'));
|
||||||
|
if ($phpBinary === '') {
|
||||||
|
$phpBinary = env('SYSTEM_UPDATE_PHP_BINARY') ?: (PHP_BINARY ?: 'php');
|
||||||
|
}
|
||||||
$append("Running migrations (using {$phpBinary})...");
|
$append("Running migrations (using {$phpBinary})...");
|
||||||
$migrate = new Process([$phpBinary, 'artisan', 'migrate', '--force'], base_path());
|
$migrate = new Process([$phpBinary, 'artisan', 'migrate', '--force'], base_path());
|
||||||
$migrate->setTimeout(600);
|
$migrate->setTimeout(600);
|
||||||
|
|||||||
0
bootstrap/cache/.gitkeep
vendored
Normal file
0
bootstrap/cache/.gitkeep
vendored
Normal file
72
bootstrap/cache/packages.php
vendored
72
bootstrap/cache/packages.php
vendored
@@ -1,72 +0,0 @@
|
|||||||
<?php return array (
|
|
||||||
'barryvdh/laravel-ide-helper' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'laravel/fortify' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Laravel\\Fortify\\FortifyServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'laravel/pail' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Laravel\\Pail\\PailServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'laravel/sail' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Laravel\\Sail\\SailServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'laravel/sanctum' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Laravel\\Sanctum\\SanctumServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'laravel/tinker' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'nesbot/carbon' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Carbon\\Laravel\\ServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'nunomaduro/collision' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'nunomaduro/termwind' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'pestphp/pest-plugin-laravel' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Pest\\Laravel\\PestServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
277
bootstrap/cache/services.php
vendored
277
bootstrap/cache/services.php
vendored
@@ -1,277 +0,0 @@
|
|||||||
<?php return array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Illuminate\\Auth\\AuthServiceProvider',
|
|
||||||
1 => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
|
||||||
2 => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
3 => 'Illuminate\\Cache\\CacheServiceProvider',
|
|
||||||
4 => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
5 => 'Illuminate\\Concurrency\\ConcurrencyServiceProvider',
|
|
||||||
6 => 'Illuminate\\Cookie\\CookieServiceProvider',
|
|
||||||
7 => 'Illuminate\\Database\\DatabaseServiceProvider',
|
|
||||||
8 => 'Illuminate\\Encryption\\EncryptionServiceProvider',
|
|
||||||
9 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',
|
|
||||||
10 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',
|
|
||||||
11 => 'Illuminate\\Hashing\\HashServiceProvider',
|
|
||||||
12 => 'Illuminate\\Mail\\MailServiceProvider',
|
|
||||||
13 => 'Illuminate\\Notifications\\NotificationServiceProvider',
|
|
||||||
14 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
|
||||||
15 => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
|
||||||
16 => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
|
||||||
17 => 'Illuminate\\Queue\\QueueServiceProvider',
|
|
||||||
18 => 'Illuminate\\Redis\\RedisServiceProvider',
|
|
||||||
19 => 'Illuminate\\Session\\SessionServiceProvider',
|
|
||||||
20 => 'Illuminate\\Translation\\TranslationServiceProvider',
|
|
||||||
21 => 'Illuminate\\Validation\\ValidationServiceProvider',
|
|
||||||
22 => 'Illuminate\\View\\ViewServiceProvider',
|
|
||||||
23 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
|
||||||
24 => 'Laravel\\Fortify\\FortifyServiceProvider',
|
|
||||||
25 => 'Laravel\\Pail\\PailServiceProvider',
|
|
||||||
26 => 'Laravel\\Sail\\SailServiceProvider',
|
|
||||||
27 => 'Laravel\\Sanctum\\SanctumServiceProvider',
|
|
||||||
28 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
|
||||||
29 => 'Carbon\\Laravel\\ServiceProvider',
|
|
||||||
30 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
|
||||||
31 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
|
||||||
32 => 'Pest\\Laravel\\PestServiceProvider',
|
|
||||||
33 => 'App\\Providers\\AppServiceProvider',
|
|
||||||
34 => 'App\\Providers\\FortifyServiceProvider',
|
|
||||||
),
|
|
||||||
'eager' =>
|
|
||||||
array (
|
|
||||||
0 => 'Illuminate\\Auth\\AuthServiceProvider',
|
|
||||||
1 => 'Illuminate\\Cookie\\CookieServiceProvider',
|
|
||||||
2 => 'Illuminate\\Database\\DatabaseServiceProvider',
|
|
||||||
3 => 'Illuminate\\Encryption\\EncryptionServiceProvider',
|
|
||||||
4 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',
|
|
||||||
5 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',
|
|
||||||
6 => 'Illuminate\\Notifications\\NotificationServiceProvider',
|
|
||||||
7 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
|
||||||
8 => 'Illuminate\\Session\\SessionServiceProvider',
|
|
||||||
9 => 'Illuminate\\View\\ViewServiceProvider',
|
|
||||||
10 => 'Laravel\\Fortify\\FortifyServiceProvider',
|
|
||||||
11 => 'Laravel\\Pail\\PailServiceProvider',
|
|
||||||
12 => 'Laravel\\Sanctum\\SanctumServiceProvider',
|
|
||||||
13 => 'Carbon\\Laravel\\ServiceProvider',
|
|
||||||
14 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
|
||||||
15 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
|
||||||
16 => 'Pest\\Laravel\\PestServiceProvider',
|
|
||||||
17 => 'App\\Providers\\AppServiceProvider',
|
|
||||||
18 => 'App\\Providers\\FortifyServiceProvider',
|
|
||||||
),
|
|
||||||
'deferred' =>
|
|
||||||
array (
|
|
||||||
'Illuminate\\Broadcasting\\BroadcastManager' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
|
||||||
'Illuminate\\Contracts\\Broadcasting\\Factory' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
|
||||||
'Illuminate\\Contracts\\Broadcasting\\Broadcaster' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
|
||||||
'Illuminate\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
'Illuminate\\Contracts\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
'Illuminate\\Contracts\\Bus\\QueueingDispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
'Illuminate\\Bus\\BatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
'Illuminate\\Bus\\DatabaseBatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
'cache' => 'Illuminate\\Cache\\CacheServiceProvider',
|
|
||||||
'cache.store' => 'Illuminate\\Cache\\CacheServiceProvider',
|
|
||||||
'cache.psr6' => 'Illuminate\\Cache\\CacheServiceProvider',
|
|
||||||
'memcached.connector' => 'Illuminate\\Cache\\CacheServiceProvider',
|
|
||||||
'Illuminate\\Cache\\RateLimiter' => 'Illuminate\\Cache\\CacheServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\AboutCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Cache\\Console\\ClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Cache\\Console\\ForgetCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ClearCompiledCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Auth\\Console\\ClearResetsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ConfigCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ConfigClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ConfigShowCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\DbCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\MonitorCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\PruneCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\ShowCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\TableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\WipeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\DownCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EnvironmentCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EnvironmentDecryptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EnvironmentEncryptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EventCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EventClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EventListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Concurrency\\Console\\InvokeSerializedClosureCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\KeyGenerateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\OptimizeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\OptimizeClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\PackageDiscoverCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Cache\\Console\\PruneStaleTagsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\ClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\ListFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\FlushFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\ForgetFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\ListenCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\MonitorCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\PauseCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\PruneBatchesCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\PruneFailedJobsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\RestartCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\ResumeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\RetryCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\RetryBatchCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\WorkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ReloadCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\RouteCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\RouteClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\RouteListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\DumpCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Seeds\\SeedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleFinishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleRunCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleClearCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleTestCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleWorkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Console\\Scheduling\\ScheduleInterruptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\ShowModelCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\StorageLinkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\StorageUnlinkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\UpCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ViewCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ViewClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ApiInstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\BroadcastingInstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Cache\\Console\\CacheTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\CastMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ChannelListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ChannelMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ClassMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ComponentMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ConfigMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ConfigPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ConsoleMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Routing\\Console\\ControllerMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\DocsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EnumMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EventGenerateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\EventMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ExceptionMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Factories\\FactoryMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\InterfaceMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\JobMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\JobMiddlewareMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\LangPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ListenerMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\MailMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Routing\\Console\\MiddlewareMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ModelMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\NotificationMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Notifications\\Console\\NotificationTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ObserverMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\PolicyMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ProviderMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\FailedTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\TableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Queue\\Console\\BatchesTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\RequestMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ResourceMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\RuleMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ScopeMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Seeds\\SeederMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Session\\Console\\SessionTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ServeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\StubPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\TestMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\TraitMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\VendorPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Foundation\\Console\\ViewMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'migrator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'migration.repository' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'migration.creator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Migrations\\Migrator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\MigrateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\FreshCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\InstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\RefreshCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\ResetCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\RollbackCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\StatusCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Database\\Console\\Migrations\\MigrateMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'composer' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
|
||||||
'Illuminate\\Concurrency\\ConcurrencyManager' => 'Illuminate\\Concurrency\\ConcurrencyServiceProvider',
|
|
||||||
'hash' => 'Illuminate\\Hashing\\HashServiceProvider',
|
|
||||||
'hash.driver' => 'Illuminate\\Hashing\\HashServiceProvider',
|
|
||||||
'mail.manager' => 'Illuminate\\Mail\\MailServiceProvider',
|
|
||||||
'mailer' => 'Illuminate\\Mail\\MailServiceProvider',
|
|
||||||
'Illuminate\\Mail\\Markdown' => 'Illuminate\\Mail\\MailServiceProvider',
|
|
||||||
'auth.password' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
|
||||||
'auth.password.broker' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
|
||||||
'Illuminate\\Contracts\\Pipeline\\Hub' => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
|
||||||
'pipeline' => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
|
||||||
'queue' => 'Illuminate\\Queue\\QueueServiceProvider',
|
|
||||||
'queue.connection' => 'Illuminate\\Queue\\QueueServiceProvider',
|
|
||||||
'queue.failer' => 'Illuminate\\Queue\\QueueServiceProvider',
|
|
||||||
'queue.listener' => 'Illuminate\\Queue\\QueueServiceProvider',
|
|
||||||
'queue.worker' => 'Illuminate\\Queue\\QueueServiceProvider',
|
|
||||||
'redis' => 'Illuminate\\Redis\\RedisServiceProvider',
|
|
||||||
'redis.connection' => 'Illuminate\\Redis\\RedisServiceProvider',
|
|
||||||
'translator' => 'Illuminate\\Translation\\TranslationServiceProvider',
|
|
||||||
'translation.loader' => 'Illuminate\\Translation\\TranslationServiceProvider',
|
|
||||||
'validator' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
|
||||||
'validation.presence' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
|
||||||
'Illuminate\\Contracts\\Validation\\UncompromisedVerifier' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
|
||||||
'Barryvdh\\LaravelIdeHelper\\Console\\GeneratorCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
|
||||||
'Barryvdh\\LaravelIdeHelper\\Console\\ModelsCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
|
||||||
'Barryvdh\\LaravelIdeHelper\\Console\\MetaCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
|
||||||
'Barryvdh\\LaravelIdeHelper\\Console\\EloquentCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
|
||||||
'Laravel\\Sail\\Console\\InstallCommand' => 'Laravel\\Sail\\SailServiceProvider',
|
|
||||||
'Laravel\\Sail\\Console\\PublishCommand' => 'Laravel\\Sail\\SailServiceProvider',
|
|
||||||
'command.tinker' => 'Laravel\\Tinker\\TinkerServiceProvider',
|
|
||||||
),
|
|
||||||
'when' =>
|
|
||||||
array (
|
|
||||||
'Illuminate\\Broadcasting\\BroadcastServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Bus\\BusServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Cache\\CacheServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Concurrency\\ConcurrencyServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Hashing\\HashServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Mail\\MailServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Pipeline\\PipelineServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Queue\\QueueServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Redis\\RedisServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Translation\\TranslationServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Illuminate\\Validation\\ValidationServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Laravel\\Sail\\SailServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'Laravel\\Tinker\\TinkerServiceProvider' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
@@ -97,5 +97,6 @@
|
|||||||
},
|
},
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"version": "26.0.1"
|
"version": "26.0.2",
|
||||||
|
"build": "71"
|
||||||
}
|
}
|
||||||
|
|||||||
2
composer.lock
generated
2
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "83b577a02e99a4e17696941851d13cc2",
|
"content-hash": "e6076a6989b155fddbc675cab28fdd50",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "bacon/bacon-qr-code",
|
"name": "bacon/bacon-qr-code",
|
||||||
|
|||||||
129
git_update.sh
Executable file
129
git_update.sh
Executable file
@@ -0,0 +1,129 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
git restore -q bootstrap/cache/packages.php bootstrap/cache/services.php 2>/dev/null || true
|
||||||
|
DIRTY="$(git status --porcelain)"
|
||||||
|
DIRTY_FILTERED="$(echo "$DIRTY" | grep -vE '^( M|M ) (bootstrap/cache/(packages|services)\.php|package-lock\.json)$' || true)"
|
||||||
|
if [[ -n "$DIRTY_FILTERED" ]]; then
|
||||||
|
echo "Working tree is dirty. Please commit or stash changes before updating."
|
||||||
|
echo "$DIRTY_FILTERED"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if echo "$DIRTY" | grep -qE 'package-lock\.json'; then
|
||||||
|
echo "Warning: package-lock.json is modified. Continuing anyway."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Fetching latest refs..."
|
||||||
|
git fetch --prune --tags
|
||||||
|
|
||||||
|
echo "Checking out stable branch..."
|
||||||
|
git checkout stable
|
||||||
|
|
||||||
|
echo "Pulling latest stable..."
|
||||||
|
git pull --ff-only
|
||||||
|
|
||||||
|
resolve_php_bin() {
|
||||||
|
if [[ -n "${PHP_BIN:-}" ]]; then
|
||||||
|
echo "$PHP_BIN"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if command -v keyhelp-php84 >/dev/null 2>&1; then
|
||||||
|
echo "keyhelp-php84"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if command -v php >/dev/null 2>&1; then
|
||||||
|
echo "php"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "php"
|
||||||
|
}
|
||||||
|
|
||||||
|
PHP_BIN="$(resolve_php_bin)"
|
||||||
|
echo "Resolved PHP binary: $PHP_BIN"
|
||||||
|
if command -v "$PHP_BIN" >/dev/null 2>&1; then
|
||||||
|
echo "PHP version ($PHP_BIN): $($PHP_BIN -v | head -n 1)"
|
||||||
|
else
|
||||||
|
echo "PHP binary '$PHP_BIN' not found in PATH."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing PHP dependencies..."
|
||||||
|
COMPOSER_BIN="$(command -v composer || true)"
|
||||||
|
if [[ -z "$COMPOSER_BIN" ]]; then
|
||||||
|
echo "Composer not found in PATH."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
$PHP_BIN "$COMPOSER_BIN" install --no-dev --optimize-autoloader
|
||||||
|
|
||||||
|
if [[ -x "artisan" ]]; then
|
||||||
|
CONFIGURED_PHP="$($PHP_BIN artisan tinker --execute="echo \\App\\Models\\Setting::where('key','system.php_binary')->value('value') ?? '';" 2>/dev/null || true)"
|
||||||
|
if [[ -n "$CONFIGURED_PHP" ]]; then
|
||||||
|
if command -v "$CONFIGURED_PHP" >/dev/null 2>&1; then
|
||||||
|
PHP_BIN="$CONFIGURED_PHP"
|
||||||
|
elif [[ -x "$CONFIGURED_PHP" ]]; then
|
||||||
|
PHP_BIN="$CONFIGURED_PHP"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Final PHP binary: $PHP_BIN"
|
||||||
|
if command -v "$PHP_BIN" >/dev/null 2>&1; then
|
||||||
|
echo "Final PHP version ($PHP_BIN): $($PHP_BIN -v | head -n 1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing JS dependencies..."
|
||||||
|
npm install
|
||||||
|
|
||||||
|
echo "Building assets..."
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
echo "Running migrations..."
|
||||||
|
$PHP_BIN artisan migrate --force
|
||||||
|
|
||||||
|
echo "Syncing version/build to settings..."
|
||||||
|
VERSION="$($PHP_BIN -r '$c=json_decode(file_get_contents("composer.json"), true); echo $c["version"] ?? "";')"
|
||||||
|
BUILD="$($PHP_BIN -r '$c=json_decode(file_get_contents("composer.json"), true); echo $c["build"] ?? "";')"
|
||||||
|
echo "Computed from composer.json: VERSION=$VERSION, BUILD=$BUILD"
|
||||||
|
|
||||||
|
if [[ -n "$VERSION" || -n "$BUILD" ]]; then
|
||||||
|
echo "Updating settings version/build (VERSION=$VERSION, BUILD=$BUILD)..."
|
||||||
|
SPEEDBB_VERSION="$VERSION" SPEEDBB_BUILD="$BUILD" $PHP_BIN -r '
|
||||||
|
require "vendor/autoload.php";
|
||||||
|
$app = require "bootstrap/app.php";
|
||||||
|
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||||
|
$version = getenv("SPEEDBB_VERSION");
|
||||||
|
$build = getenv("SPEEDBB_BUILD");
|
||||||
|
if ($version !== false && $version !== "") {
|
||||||
|
$updated = \Illuminate\Support\Facades\DB::table("settings")
|
||||||
|
->where("key", "version")
|
||||||
|
->update(["value" => $version]);
|
||||||
|
if ($updated === 0) {
|
||||||
|
\Illuminate\Support\Facades\DB::table("settings")
|
||||||
|
->insert(["key" => "version", "value" => $version, "created_at" => now(), "updated_at" => now()]);
|
||||||
|
}
|
||||||
|
echo "Updated version rows: {$updated}\n";
|
||||||
|
}
|
||||||
|
if ($build !== false && $build !== "") {
|
||||||
|
$updated = \Illuminate\Support\Facades\DB::table("settings")
|
||||||
|
->where("key", "build")
|
||||||
|
->update(["value" => $build]);
|
||||||
|
if ($updated === 0) {
|
||||||
|
\Illuminate\Support\Facades\DB::table("settings")
|
||||||
|
->insert(["key" => "build", "value" => $build, "created_at" => now(), "updated_at" => now()]);
|
||||||
|
}
|
||||||
|
echo "Updated build rows: {$updated}\n";
|
||||||
|
}
|
||||||
|
' \
|
||||||
|
&& $PHP_BIN -r '
|
||||||
|
require "vendor/autoload.php";
|
||||||
|
$app = require "bootstrap/app.php";
|
||||||
|
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||||
|
$version = \App\Models\Setting::where("key", "version")->value("value");
|
||||||
|
$build = \App\Models\Setting::where("key", "build")->value("value");
|
||||||
|
echo "Settings now: version={$version}, build={$build}\n";
|
||||||
|
'
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Update complete."
|
||||||
@@ -862,8 +862,8 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-bs-theme="dark"] {
|
[data-bs-theme="dark"] {
|
||||||
--bb-ink: #e6e8eb;
|
--bb-ink: #aaaeb4;
|
||||||
--bb-ink-muted: #9aa4b2;
|
--bb-ink-muted: #6b7483;
|
||||||
--bb-border: #2a2f3a;
|
--bb-border: #2a2f3a;
|
||||||
--bb-page-bg: radial-gradient(circle at 10% 20%, #141823 0%, #10131a 45%, #0b0e14 100%);
|
--bb-page-bg: radial-gradient(circle at 10% 20%, #141823 0%, #10131a 45%, #0b0e14 100%);
|
||||||
}
|
}
|
||||||
@@ -922,10 +922,18 @@ a {
|
|||||||
|
|
||||||
.nav-tabs .nav-link {
|
.nav-tabs .nav-link {
|
||||||
color: var(--bb-accent, #f29b3f);
|
color: var(--bb-accent, #f29b3f);
|
||||||
|
border: 1px solid var(--bb-border);
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
margin-right: 0.35rem;
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs .nav-link.active {
|
.nav-tabs .nav-link.active {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border-color: var(--bb-border);
|
||||||
|
border-bottom-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bb-version {
|
.bb-version {
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ function Acp({ isAdmin }) {
|
|||||||
const [systemStatus, setSystemStatus] = useState(null)
|
const [systemStatus, setSystemStatus] = useState(null)
|
||||||
const [systemLoading, setSystemLoading] = useState(false)
|
const [systemLoading, setSystemLoading] = useState(false)
|
||||||
const [systemError, setSystemError] = useState('')
|
const [systemError, setSystemError] = useState('')
|
||||||
|
const [systemSection, setSystemSection] = useState('info')
|
||||||
const [usersPage, setUsersPage] = useState(1)
|
const [usersPage, setUsersPage] = useState(1)
|
||||||
const [usersPerPage, setUsersPerPage] = useState(10)
|
const [usersPerPage, setUsersPerPage] = useState(10)
|
||||||
const [userSort, setUserSort] = useState({ columnId: 'name', direction: 'asc' })
|
const [userSort, setUserSort] = useState({ columnId: 'name', direction: 'asc' })
|
||||||
@@ -200,6 +201,12 @@ function Acp({ isAdmin }) {
|
|||||||
favicon_128: '',
|
favicon_128: '',
|
||||||
favicon_256: '',
|
favicon_256: '',
|
||||||
})
|
})
|
||||||
|
const [systemCliSettings, setSystemCliSettings] = useState({
|
||||||
|
php_mode: 'php',
|
||||||
|
php_custom: '',
|
||||||
|
})
|
||||||
|
const [systemCliSaving, setSystemCliSaving] = useState(false)
|
||||||
|
const [systemCliError, setSystemCliError] = useState('')
|
||||||
const settingsDetailMap = {
|
const settingsDetailMap = {
|
||||||
forum_name: 'forumName',
|
forum_name: 'forumName',
|
||||||
default_theme: 'defaultTheme',
|
default_theme: 'defaultTheme',
|
||||||
@@ -291,6 +298,16 @@ function Acp({ isAdmin }) {
|
|||||||
favicon_256: settingsMap.get('favicon_256') || '',
|
favicon_256: settingsMap.get('favicon_256') || '',
|
||||||
}
|
}
|
||||||
setGeneralSettings(next)
|
setGeneralSettings(next)
|
||||||
|
const configuredPhp = settingsMap.get('system.php_binary') || ''
|
||||||
|
const phpMode = configuredPhp === 'keyhelp-php-domain'
|
||||||
|
? 'keyhelp'
|
||||||
|
: configuredPhp === '' || configuredPhp === 'php'
|
||||||
|
? 'php'
|
||||||
|
: 'custom'
|
||||||
|
setSystemCliSettings({
|
||||||
|
php_mode: phpMode,
|
||||||
|
php_custom: phpMode === 'custom' ? configuredPhp : '',
|
||||||
|
})
|
||||||
setAttachmentSettings({
|
setAttachmentSettings({
|
||||||
display_images_inline: settingsMap.get('attachments.display_images_inline') || 'true',
|
display_images_inline: settingsMap.get('attachments.display_images_inline') || 'true',
|
||||||
create_thumbnails: settingsMap.get('attachments.create_thumbnails') || 'true',
|
create_thumbnails: settingsMap.get('attachments.create_thumbnails') || 'true',
|
||||||
@@ -372,6 +389,135 @@ function Acp({ isAdmin }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSystemCliSave = async (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
setSystemCliSaving(true)
|
||||||
|
setSystemCliError('')
|
||||||
|
try {
|
||||||
|
let value = ''
|
||||||
|
if (systemCliSettings.php_mode === 'custom') {
|
||||||
|
value = typeof systemCliSettings.php_custom === 'string'
|
||||||
|
? systemCliSettings.php_custom.trim()
|
||||||
|
: String(systemCliSettings.php_custom ?? '')
|
||||||
|
} else if (systemCliSettings.php_mode === 'keyhelp') {
|
||||||
|
value = 'keyhelp-php-domain'
|
||||||
|
} else {
|
||||||
|
value = 'php'
|
||||||
|
}
|
||||||
|
await saveSetting('system.php_binary', value)
|
||||||
|
setSystemCliSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
php_mode: systemCliSettings.php_mode,
|
||||||
|
php_custom: systemCliSettings.php_mode === 'custom' ? value : '',
|
||||||
|
}))
|
||||||
|
} catch (err) {
|
||||||
|
setSystemCliError(err.message)
|
||||||
|
} finally {
|
||||||
|
setSystemCliSaving(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const systemChecks = useMemo(() => {
|
||||||
|
if (!systemStatus) return []
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'php',
|
||||||
|
label: 'PHP',
|
||||||
|
path: systemStatus.php_selected_path || '—',
|
||||||
|
min: systemStatus.min_versions?.php || '—',
|
||||||
|
current: systemStatus.php_selected_version || '—',
|
||||||
|
status: systemStatus.php_selected_ok ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'composer',
|
||||||
|
label: 'Composer',
|
||||||
|
path: systemStatus.composer || t('system.not_found'),
|
||||||
|
min: systemStatus.min_versions?.composer || '—',
|
||||||
|
current: systemStatus.composer_version || '—',
|
||||||
|
status: systemStatus.composer ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'node',
|
||||||
|
label: 'Node',
|
||||||
|
path: systemStatus.node || t('system.not_found'),
|
||||||
|
min: systemStatus.min_versions?.node || '—',
|
||||||
|
current: systemStatus.node_version || '—',
|
||||||
|
status: systemStatus.node ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'npm',
|
||||||
|
label: 'npm',
|
||||||
|
path: systemStatus.npm || t('system.not_found'),
|
||||||
|
min: systemStatus.min_versions?.npm || '—',
|
||||||
|
current: systemStatus.npm_version || '—',
|
||||||
|
status: systemStatus.npm ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tar',
|
||||||
|
label: 'tar',
|
||||||
|
path: systemStatus.tar || t('system.not_found'),
|
||||||
|
min: '—',
|
||||||
|
current: systemStatus.tar_version || '—',
|
||||||
|
status: systemStatus.tar ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'rsync',
|
||||||
|
label: 'rsync',
|
||||||
|
path: systemStatus.rsync || t('system.not_found'),
|
||||||
|
min: '—',
|
||||||
|
current: systemStatus.rsync_version || '—',
|
||||||
|
status: systemStatus.rsync ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'proc',
|
||||||
|
label: 'proc_* functions',
|
||||||
|
path: systemStatus.proc_functions
|
||||||
|
? Object.entries(systemStatus.proc_functions)
|
||||||
|
.filter(([, ok]) => !ok)
|
||||||
|
.map(([name]) => name)
|
||||||
|
.join(', ')
|
||||||
|
: '—',
|
||||||
|
min: '—',
|
||||||
|
current: '—',
|
||||||
|
note: 'Optional. Needed for automated version checks.',
|
||||||
|
status:
|
||||||
|
Boolean(systemStatus.proc_functions) &&
|
||||||
|
Object.values(systemStatus.proc_functions).every(Boolean)
|
||||||
|
? 'ok'
|
||||||
|
: 'bad',
|
||||||
|
pathColSpan: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'storage',
|
||||||
|
label: t('system.storage_writable'),
|
||||||
|
path: 'storage/',
|
||||||
|
min: '—',
|
||||||
|
current: '—',
|
||||||
|
status: systemStatus.storage_writable ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'updates',
|
||||||
|
label: t('system.updates_writable'),
|
||||||
|
path: 'storage/app/updates',
|
||||||
|
min: '—',
|
||||||
|
current: '—',
|
||||||
|
status: systemStatus.updates_writable ? 'ok' : 'bad',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [systemStatus, t])
|
||||||
|
|
||||||
|
const visibleSystemChecks = useMemo(() => {
|
||||||
|
const visibilityBySection = {
|
||||||
|
insite: ['php', 'proc', 'storage', 'updates'],
|
||||||
|
cli: ['php', 'composer', 'node', 'npm', 'proc', 'storage', 'updates'],
|
||||||
|
ci: ['php', 'composer', 'node', 'npm', 'tar', 'rsync', 'proc', 'storage', 'updates'],
|
||||||
|
info: [],
|
||||||
|
}
|
||||||
|
const allowed = new Set(visibilityBySection[systemSection] || [])
|
||||||
|
return systemChecks.filter((check) => allowed.has(check.id))
|
||||||
|
}, [systemChecks, systemSection])
|
||||||
|
|
||||||
|
|
||||||
const handleLogoUpload = async (file, settingKey) => {
|
const handleLogoUpload = async (file, settingKey) => {
|
||||||
if (!file) return
|
if (!file) return
|
||||||
setGeneralUploading(true)
|
setGeneralUploading(true)
|
||||||
@@ -822,6 +968,74 @@ function Acp({ isAdmin }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderSystemRequirementsPanel() {
|
||||||
|
return (
|
||||||
|
<div className="bb-acp-panel">
|
||||||
|
<div className="bb-acp-panel-header">
|
||||||
|
<div className="d-flex align-items-center justify-content-between">
|
||||||
|
<h5 className="mb-0">{t('system.requirements')}</h5>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
variant="dark"
|
||||||
|
onClick={loadSystemStatus}
|
||||||
|
disabled={systemLoading}
|
||||||
|
>
|
||||||
|
{t('acp.refresh')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bb-acp-panel-body">
|
||||||
|
{!systemStatus && <p className="bb-muted mb-0">{t('system.not_found')}</p>}
|
||||||
|
{systemStatus && (
|
||||||
|
<table className="bb-acp-stats-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{t('system.check')}</th>
|
||||||
|
<th>{t('system.path')}</th>
|
||||||
|
<th>{t('system.min_version')}</th>
|
||||||
|
<th>{t('system.current_version')}</th>
|
||||||
|
<th>{t('system.status')}</th>
|
||||||
|
<th>{t('system.recheck')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{visibleSystemChecks.map((check) => (
|
||||||
|
<tr key={check.id}>
|
||||||
|
<td>{check.label}</td>
|
||||||
|
<td className="bb-acp-stats-value text-start" colSpan={check.pathColSpan || 1}>
|
||||||
|
{check.path}
|
||||||
|
{check.note && <div className="bb-muted mt-1 text-center">{check.note}</div>}
|
||||||
|
</td>
|
||||||
|
{!check.pathColSpan && (
|
||||||
|
<>
|
||||||
|
<td className="bb-acp-stats-value">{check.min}</td>
|
||||||
|
<td className="bb-acp-stats-value">{check.current}</td>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<td className="bb-acp-stats-value">
|
||||||
|
<StatusIcon status={check.status} />
|
||||||
|
</td>
|
||||||
|
<td className="bb-acp-stats-value">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="dark"
|
||||||
|
onClick={loadSystemStatus}
|
||||||
|
disabled={systemLoading}
|
||||||
|
>
|
||||||
|
{t('system.recheck')}
|
||||||
|
</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
handleVersionCheck()
|
handleVersionCheck()
|
||||||
@@ -2516,7 +2730,7 @@ function Acp({ isAdmin }) {
|
|||||||
<Tabs defaultActiveKey="general" className="mb-3">
|
<Tabs defaultActiveKey="general" className="mb-3">
|
||||||
<Tab eventKey="general" title={t('acp.general')}>
|
<Tab eventKey="general" title={t('acp.general')}>
|
||||||
<Row className="g-4">
|
<Row className="g-4">
|
||||||
<Col lg={3} xl={2}>
|
<Col xs={12} lg="auto">
|
||||||
<div className="bb-acp-sidebar">
|
<div className="bb-acp-sidebar">
|
||||||
<div className="bb-acp-sidebar-section">
|
<div className="bb-acp-sidebar-section">
|
||||||
<div className="bb-acp-sidebar-title">{t('acp.quick_access')}</div>
|
<div className="bb-acp-sidebar-title">{t('acp.quick_access')}</div>
|
||||||
@@ -2576,13 +2790,7 @@ function Acp({ isAdmin }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg={9} xl={10}>
|
<Col xs={12} lg>
|
||||||
<div className="bb-acp-panel mb-4">
|
|
||||||
<div className="bb-acp-panel-header">
|
|
||||||
<h5 className="mb-1">{t('acp.welcome_title')}</h5>
|
|
||||||
<p className="bb-muted mb-0">{t('acp.general_hint')}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bb-acp-panel mb-4">
|
<div className="bb-acp-panel mb-4">
|
||||||
<div className="bb-acp-panel-header">
|
<div className="bb-acp-panel-header">
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<div className="d-flex align-items-center justify-content-between">
|
||||||
@@ -3507,255 +3715,163 @@ function Acp({ isAdmin }) {
|
|||||||
<Tab eventKey="system" title={t('acp.system')}>
|
<Tab eventKey="system" title={t('acp.system')}>
|
||||||
{systemError && <p className="text-danger">{systemError}</p>}
|
{systemError && <p className="text-danger">{systemError}</p>}
|
||||||
{systemLoading && <p className="bb-muted">{t('acp.loading')}</p>}
|
{systemLoading && <p className="bb-muted">{t('acp.loading')}</p>}
|
||||||
{!systemLoading && systemStatus && (
|
{!systemLoading && (
|
||||||
|
<Row className="g-4">
|
||||||
|
<Col xs={12} lg="auto">
|
||||||
|
<div className="bb-acp-sidebar">
|
||||||
|
<div className="bb-acp-sidebar-section">
|
||||||
|
<div className="bb-acp-sidebar-title">{t('acp.system')}</div>
|
||||||
|
<div className="list-group">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`list-group-item list-group-item-action ${
|
||||||
|
systemSection === 'info' ? 'is-active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => setSystemSection('info')}
|
||||||
|
>
|
||||||
|
Overview
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`list-group-item list-group-item-action ${
|
||||||
|
systemSection === 'insite' ? 'is-active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => setSystemSection('insite')}
|
||||||
|
>
|
||||||
|
Live Update
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`list-group-item list-group-item-action ${
|
||||||
|
systemSection === 'cli' ? 'is-active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => setSystemSection('cli')}
|
||||||
|
>
|
||||||
|
CLI
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`list-group-item list-group-item-action ${
|
||||||
|
systemSection === 'ci' ? 'is-active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => setSystemSection('ci')}
|
||||||
|
>
|
||||||
|
CI/CD
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col xs={12} lg>
|
||||||
|
{systemSection === 'info' && (
|
||||||
<div className="bb-acp-panel">
|
<div className="bb-acp-panel">
|
||||||
<div className="bb-acp-panel-header">
|
<div className="bb-acp-panel-header">
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<h5 className="mb-0">System overview</h5>
|
||||||
<h5 className="mb-0">{t('system.requirements')}</h5>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('acp.refresh')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="bb-acp-panel-body">
|
<div className="bb-acp-panel-body">
|
||||||
<table className="bb-acp-stats-table">
|
<p className="bb-muted mb-0">
|
||||||
<thead>
|
Placeholder: summary, upgrade guidance, and environment health notes will
|
||||||
<tr>
|
live here.
|
||||||
<th>{t('system.check')}</th>
|
</p>
|
||||||
<th>{t('system.path')}</th>
|
|
||||||
<th>{t('system.min_version')}</th>
|
|
||||||
<th>{t('system.current_version')}</th>
|
|
||||||
<th>{t('system.status')}</th>
|
|
||||||
<th>{t('system.recheck')}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>PHP</td>
|
|
||||||
<td className="bb-acp-stats-value">{systemStatus.php_selected_path || '—'}</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.min_versions?.php || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.php_selected_version || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon
|
|
||||||
status={systemStatus.php_selected_ok ? 'ok' : 'bad'}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Composer</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.composer || t('system.not_found')}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.min_versions?.composer || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.composer_version || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.composer ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Node</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.node || t('system.not_found')}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.min_versions?.node || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.node_version || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.node ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>npm</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.npm || t('system.not_found')}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.min_versions?.npm || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.npm_version || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.npm ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>tar</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.tar || t('system.not_found')}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">—</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.tar_version || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.tar ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>rsync</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.rsync || t('system.not_found')}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">—</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
{systemStatus.rsync_version || '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.rsync ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>proc_* functions</td>
|
|
||||||
<td className="bb-acp-stats-value" colSpan={3}>
|
|
||||||
{systemStatus.proc_functions
|
|
||||||
? Object.entries(systemStatus.proc_functions)
|
|
||||||
.filter(([, ok]) => !ok)
|
|
||||||
.map(([name]) => name)
|
|
||||||
.join(', ')
|
|
||||||
: '—'}
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon
|
|
||||||
status={
|
|
||||||
Boolean(systemStatus.proc_functions) &&
|
|
||||||
Object.values(systemStatus.proc_functions).every(Boolean)
|
|
||||||
? 'ok'
|
|
||||||
: 'bad'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{t('system.storage_writable')}</td>
|
|
||||||
<td className="bb-acp-stats-value">storage/</td>
|
|
||||||
<td className="bb-acp-stats-value">—</td>
|
|
||||||
<td className="bb-acp-stats-value">—</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.storage_writable ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{t('system.updates_writable')}</td>
|
|
||||||
<td className="bb-acp-stats-value">storage/app/updates</td>
|
|
||||||
<td className="bb-acp-stats-value">—</td>
|
|
||||||
<td className="bb-acp-stats-value">—</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<StatusIcon status={systemStatus.updates_writable ? 'ok' : 'bad'} />
|
|
||||||
</td>
|
|
||||||
<td className="bb-acp-stats-value">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="dark"
|
|
||||||
onClick={loadSystemStatus}
|
|
||||||
disabled={systemLoading}
|
|
||||||
>
|
|
||||||
{t('system.recheck')}
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{systemSection === 'insite' && (
|
||||||
|
<>
|
||||||
|
<div className="bb-acp-panel mb-3">
|
||||||
|
<div className="bb-acp-panel-body">
|
||||||
|
<p className="bb-muted mb-0">Live update controls will appear here.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{renderSystemRequirementsPanel()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{systemSection === 'cli' && (
|
||||||
|
<div className="bb-acp-panel">
|
||||||
|
<div className="bb-acp-panel-header">
|
||||||
|
<h5 className="mb-0">CLI</h5>
|
||||||
|
</div>
|
||||||
|
<div className="bb-acp-panel-body">
|
||||||
|
{systemCliError && <p className="text-danger">{systemCliError}</p>}
|
||||||
|
<Form onSubmit={handleSystemCliSave}>
|
||||||
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>PHP interpreter</Form.Label>
|
||||||
|
<Form.Select
|
||||||
|
className="mb-2"
|
||||||
|
value={systemCliSettings.php_mode}
|
||||||
|
onChange={(event) =>
|
||||||
|
setSystemCliSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
php_mode: event.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<option value="php">php (system default)</option>
|
||||||
|
<option value="keyhelp">keyhelp-php-domain</option>
|
||||||
|
<option value="custom">Custom binary (e.g. keyhelp-php84)</option>
|
||||||
|
</Form.Select>
|
||||||
|
{systemCliSettings.php_mode === 'custom' && (
|
||||||
|
<Form.Control
|
||||||
|
type="text"
|
||||||
|
placeholder="keyhelp-php84"
|
||||||
|
value={systemCliSettings.php_custom}
|
||||||
|
onChange={(event) =>
|
||||||
|
setSystemCliSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
php_custom: event.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Form.Text className="bb-muted">
|
||||||
|
Used for CLI-based updates and maintenance tasks. `keyhelp-php-domain`
|
||||||
|
is available on KeyHelp Pro; on non-Pro setups use a custom binary.
|
||||||
|
</Form.Text>
|
||||||
|
</Form.Group>
|
||||||
|
<Button type="submit" variant="dark" disabled={systemCliSaving}>
|
||||||
|
{t('acp.save')}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{systemSection === 'cli' && renderSystemRequirementsPanel()}
|
||||||
|
{systemSection === 'ci' && (
|
||||||
|
<>
|
||||||
|
<div className="bb-acp-panel">
|
||||||
|
<div className="bb-acp-panel-header">
|
||||||
|
<h5 className="mb-0">CI/CD</h5>
|
||||||
|
</div>
|
||||||
|
<div className="bb-acp-panel-body">
|
||||||
|
<p className="bb-muted mb-0">
|
||||||
|
Placeholder: CI/CD pipelines, runner requirements, and deployment logs will
|
||||||
|
live here.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{renderSystemRequirementsPanel()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
</Tab>
|
||||||
|
<Tab eventKey="custom" title="Custom">
|
||||||
|
<Row className="g-4">
|
||||||
|
<Col xs={12}>
|
||||||
|
<div className="bb-acp-panel">
|
||||||
|
<div className="bb-acp-panel-header">
|
||||||
|
<h5 className="mb-0">Custom</h5>
|
||||||
|
</div>
|
||||||
|
<div className="bb-acp-panel-body">
|
||||||
|
<p className="bb-muted mb-0">
|
||||||
|
Place site-specific assets or overrides in `/custom` and `public/custom`.
|
||||||
|
These paths are preserved during in-place updates.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Modal show={showModal} onHide={handleReset} centered size="lg">
|
<Modal show={showModal} onHide={handleReset} centered size="lg">
|
||||||
|
|||||||
5
scripts/hooks/pre-commit
Normal file
5
scripts/hooks/pre-commit
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Fail fast if the database is unreachable.
|
||||||
|
php artisan version:fetch >/dev/null
|
||||||
@@ -398,25 +398,20 @@ it('handles migration failure', function (): void {
|
|||||||
File::shouldReceive('directories')->andReturn(['/tmp/extract/speedbb']);
|
File::shouldReceive('directories')->andReturn(['/tmp/extract/speedbb']);
|
||||||
File::shouldReceive('copyDirectory')->andReturnTrue();
|
File::shouldReceive('copyDirectory')->andReturnTrue();
|
||||||
|
|
||||||
$artisanPath = base_path('artisan');
|
putenv('SYSTEM_UPDATE_PHP_BINARY=/nope');
|
||||||
$originalArtisan = file_get_contents($artisanPath);
|
$_ENV['SYSTEM_UPDATE_PHP_BINARY'] = '/nope';
|
||||||
file_put_contents($artisanPath, "#!/usr/bin/env php\n<?php exit(1);\n");
|
$_SERVER['SYSTEM_UPDATE_PHP_BINARY'] = '/nope';
|
||||||
chmod($artisanPath, 0755);
|
|
||||||
|
|
||||||
withFakeBin([
|
withFakeBin([
|
||||||
'tar' => "#!/bin/sh\nexit 0\n",
|
'tar' => "#!/bin/sh\nexit 0\n",
|
||||||
'composer' => "#!/bin/sh\nexit 0\n",
|
'composer' => "#!/bin/sh\nexit 0\n",
|
||||||
'npm' => "#!/bin/sh\nexit 0\n",
|
'npm' => "#!/bin/sh\nexit 0\n",
|
||||||
], function () use ($artisanPath, $originalArtisan): void {
|
], function (): void {
|
||||||
try {
|
|
||||||
Sanctum::actingAs(makeAdminForSystemUpdate());
|
Sanctum::actingAs(makeAdminForSystemUpdate());
|
||||||
$response = $this->postJson('/api/system/update');
|
$response = $this->postJson('/api/system/update');
|
||||||
|
|
||||||
$response->assertStatus(500);
|
$response->assertStatus(500);
|
||||||
$response->assertJsonFragment(['message' => 'Migrations failed.']);
|
$response->assertJsonFragment(['message' => 'Migrations failed.']);
|
||||||
} finally {
|
|
||||||
file_put_contents($artisanPath, $originalArtisan);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -424,6 +419,9 @@ it('handles fallback copyDirectory update success', function (): void {
|
|||||||
putenv('GITEA_OWNER=acme');
|
putenv('GITEA_OWNER=acme');
|
||||||
putenv('GITEA_REPO=speedbb');
|
putenv('GITEA_REPO=speedbb');
|
||||||
putenv('GITEA_API_BASE=https://git.example.test/api/v1');
|
putenv('GITEA_API_BASE=https://git.example.test/api/v1');
|
||||||
|
putenv('SYSTEM_UPDATE_PHP_BINARY=php');
|
||||||
|
$_ENV['SYSTEM_UPDATE_PHP_BINARY'] = 'php';
|
||||||
|
$_SERVER['SYSTEM_UPDATE_PHP_BINARY'] = 'php';
|
||||||
|
|
||||||
Http::fake([
|
Http::fake([
|
||||||
'https://git.example.test/api/v1/repos/acme/speedbb/releases/latest' => Http::response([
|
'https://git.example.test/api/v1/repos/acme/speedbb/releases/latest' => Http::response([
|
||||||
@@ -438,25 +436,21 @@ it('handles fallback copyDirectory update success', function (): void {
|
|||||||
File::shouldReceive('directories')->andReturn(['/tmp/extract/speedbb']);
|
File::shouldReceive('directories')->andReturn(['/tmp/extract/speedbb']);
|
||||||
File::shouldReceive('copyDirectory')->andReturnTrue();
|
File::shouldReceive('copyDirectory')->andReturnTrue();
|
||||||
|
|
||||||
$artisanPath = base_path('artisan');
|
putenv('SYSTEM_UPDATE_PHP_BINARY=php');
|
||||||
$originalArtisan = file_get_contents($artisanPath);
|
$_ENV['SYSTEM_UPDATE_PHP_BINARY'] = 'php';
|
||||||
file_put_contents($artisanPath, "#!/usr/bin/env php\n<?php exit(0);\n");
|
$_SERVER['SYSTEM_UPDATE_PHP_BINARY'] = 'php';
|
||||||
chmod($artisanPath, 0755);
|
|
||||||
|
|
||||||
withFakeBin([
|
withFakeBin([
|
||||||
'tar' => "#!/bin/sh\nexit 0\n",
|
'tar' => "#!/bin/sh\nexit 0\n",
|
||||||
'composer' => "#!/bin/sh\nexit 0\n",
|
'composer' => "#!/bin/sh\nexit 0\n",
|
||||||
'npm' => "#!/bin/sh\nexit 0\n",
|
'npm' => "#!/bin/sh\nexit 0\n",
|
||||||
], function () use ($artisanPath, $originalArtisan): void {
|
'php' => "#!/bin/sh\nexit 0\n",
|
||||||
try {
|
], function (): void {
|
||||||
Sanctum::actingAs(makeAdminForSystemUpdate());
|
Sanctum::actingAs(makeAdminForSystemUpdate());
|
||||||
$response = $this->postJson('/api/system/update');
|
$response = $this->postJson('/api/system/update');
|
||||||
|
|
||||||
$response->assertOk();
|
$response->assertOk();
|
||||||
$response->assertJsonFragment(['message' => 'Update finished.']);
|
$response->assertJsonFragment(['message' => 'Update finished.']);
|
||||||
$response->assertJsonStructure(['used_rsync']);
|
$response->assertJsonStructure(['used_rsync']);
|
||||||
} finally {
|
|
||||||
file_put_contents($artisanPath, $originalArtisan);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,86 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace s9e\TextFormatter {
|
|
||||||
class Parser
|
|
||||||
{
|
|
||||||
public function parse(string $text): string
|
|
||||||
{
|
|
||||||
return '<r/>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Renderer
|
|
||||||
{
|
|
||||||
public function render(string $xml): string
|
|
||||||
{
|
|
||||||
return '<p>ok</p>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Configurator
|
|
||||||
{
|
|
||||||
public static bool $returnEmpty = false;
|
|
||||||
public object $plugins;
|
|
||||||
public object $tags;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->plugins = new class {
|
|
||||||
public function load(string $name): object
|
|
||||||
{
|
|
||||||
return new class {
|
|
||||||
public function addFromRepository(string $name): self
|
|
||||||
{
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->tags = new class implements \ArrayAccess {
|
|
||||||
public array $store = [];
|
|
||||||
public function add($name)
|
|
||||||
{
|
|
||||||
$obj = new \stdClass();
|
|
||||||
$this->store[$name] = $obj;
|
|
||||||
return $obj;
|
|
||||||
}
|
|
||||||
public function offsetExists($offset): bool
|
|
||||||
{
|
|
||||||
return array_key_exists($offset, $this->store);
|
|
||||||
}
|
|
||||||
public function offsetGet($offset): mixed
|
|
||||||
{
|
|
||||||
return $this->store[$offset] ?? null;
|
|
||||||
}
|
|
||||||
public function offsetSet($offset, $value): void
|
|
||||||
{
|
|
||||||
$this->store[$offset] = $value;
|
|
||||||
}
|
|
||||||
public function offsetUnset($offset): void
|
|
||||||
{
|
|
||||||
unset($this->store[$offset]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->tags['QUOTE'] = new \stdClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function finalize(): array
|
|
||||||
{
|
|
||||||
if (self::$returnEmpty) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'parser' => new Parser(),
|
|
||||||
'renderer' => new Renderer(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
use App\Actions\BbcodeFormatter;
|
use App\Actions\BbcodeFormatter;
|
||||||
|
|
||||||
it('returns empty string for null and empty input', function (): void {
|
it('returns empty string for null and empty input', function (): void {
|
||||||
@@ -128,8 +47,43 @@ namespace {
|
|||||||
expect($rendererProp->getValue())->not->toBeNull();
|
expect($rendererProp->getValue())->not->toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('build returns parser and renderer', function (): void {
|
||||||
|
putenv('BBCODE_FORCE_FAIL');
|
||||||
|
unset($_ENV['BBCODE_FORCE_FAIL'], $_SERVER['BBCODE_FORCE_FAIL']);
|
||||||
|
|
||||||
|
$ref = new ReflectionMethod(BbcodeFormatter::class, 'build');
|
||||||
|
$ref->setAccessible(true);
|
||||||
|
|
||||||
|
$result = $ref->invoke(null);
|
||||||
|
|
||||||
|
expect($result)->toBeArray();
|
||||||
|
expect($result)->toHaveCount(2);
|
||||||
|
expect($result[0])->toBeInstanceOf(\s9e\TextFormatter\Parser::class);
|
||||||
|
expect($result[1])->toBeInstanceOf(\s9e\TextFormatter\Renderer::class);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('formats with real build when parser is reset', function (): void {
|
||||||
|
putenv('BBCODE_FORCE_FAIL');
|
||||||
|
unset($_ENV['BBCODE_FORCE_FAIL'], $_SERVER['BBCODE_FORCE_FAIL']);
|
||||||
|
|
||||||
|
$parserProp = new ReflectionProperty(BbcodeFormatter::class, 'parser');
|
||||||
|
$parserProp->setAccessible(true);
|
||||||
|
$parserProp->setValue(null);
|
||||||
|
|
||||||
|
$rendererProp = new ReflectionProperty(BbcodeFormatter::class, 'renderer');
|
||||||
|
$rendererProp->setAccessible(true);
|
||||||
|
$rendererProp->setValue(null);
|
||||||
|
|
||||||
|
$html = BbcodeFormatter::format('[b]Bold[/b]');
|
||||||
|
expect($html)->toBeString();
|
||||||
|
expect($parserProp->getValue())->not->toBeNull();
|
||||||
|
expect($rendererProp->getValue())->not->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('throws when bbcode formatter cannot initialize', function (): void {
|
it('throws when bbcode formatter cannot initialize', function (): void {
|
||||||
\s9e\TextFormatter\Configurator::$returnEmpty = true;
|
putenv('BBCODE_FORCE_FAIL=1');
|
||||||
|
$_ENV['BBCODE_FORCE_FAIL'] = '1';
|
||||||
|
$_SERVER['BBCODE_FORCE_FAIL'] = '1';
|
||||||
|
|
||||||
$parserProp = new ReflectionProperty(BbcodeFormatter::class, 'parser');
|
$parserProp = new ReflectionProperty(BbcodeFormatter::class, 'parser');
|
||||||
$parserProp->setAccessible(true);
|
$parserProp->setAccessible(true);
|
||||||
@@ -145,11 +99,11 @@ namespace {
|
|||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
expect($e)->toBeInstanceOf(RuntimeException::class);
|
expect($e)->toBeInstanceOf(RuntimeException::class);
|
||||||
} finally {
|
} finally {
|
||||||
\s9e\TextFormatter\Configurator::$returnEmpty = false;
|
putenv('BBCODE_FORCE_FAIL');
|
||||||
|
unset($_ENV['BBCODE_FORCE_FAIL'], $_SERVER['BBCODE_FORCE_FAIL']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function (): void {
|
afterEach(function (): void {
|
||||||
\Mockery::close();
|
\Mockery::close();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user