diff --git a/config/easy_panel_config.php b/config/easy_panel_config.php index e862577..06cddeb 100644 --- a/config/easy_panel_config.php +++ b/config/easy_panel_config.php @@ -1,5 +1,9 @@ \EasyPanel\Support\Auth\AdminIdentifier::class, + 'auth_class' => AdminIdentifier::class, // With this class you can manage how to create a admin or remove it. - 'admin_provider_class' => \EasyPanel\Support\User\UserProvider::class, + 'admin_provider_class' => UserProvider::class, //The namespace of lang manager class - 'lang_manager_class' => \EasyPanel\Services\LangService::class, + 'lang_manager_class' => LangService::class, // it's a place where a user if not authenticated will be redirected 'redirect_unauthorized' => '/', @@ -43,9 +47,9 @@ 'lazy_mode' => true, // database configure - 'database'=>[ - 'connection'=> env('EZ_PANEL_DB_CONNECTION'), - 'panel_admin_table'=>'panel_admins', - 'crud_table'=> 'cruds' + 'database' => [ + 'connection' => env('EASY_PANEL_DB_CONNECTION', env('DB_CONNECTION', 'mysql')), + 'panel_admin_table' => 'panel_admins', + 'crud_table' => 'cruds' ] ]; diff --git a/database/migrations/cruds_table.php b/database/migrations/cruds_table.php index 0cb04ad..8a750b7 100644 --- a/database/migrations/cruds_table.php +++ b/database/migrations/cruds_table.php @@ -11,7 +11,7 @@ class CreateCrudsTableEasypanel extends Migration */ public function getConnection() { - return config('easy_panel_config.database.connection') ?: config('database.default'); + return config('easy_panel.database.connection'); } /** @@ -21,7 +21,7 @@ public function getConnection() */ public function up() { - Schema::create(config('easy_panel_config.database.crud_table'), function (Blueprint $table) { + Schema::create(config('easy_panel.database.crud_table'), function (Blueprint $table) { $table->id(); $table->string('name')->unique(); $table->string('model')->unique(); @@ -42,6 +42,6 @@ public function up() */ public function down() { - Schema::dropIfExists(config('easy_panel_config.database.crud_table')); + Schema::dropIfExists(config('easy_panel.database.crud_table')); } } diff --git a/database/migrations/panel_admins_table.php b/database/migrations/panel_admins_table.php index 139aab1..6d043c3 100644 --- a/database/migrations/panel_admins_table.php +++ b/database/migrations/panel_admins_table.php @@ -11,8 +11,9 @@ class CreatePanelAdminsTableEasypanel extends Migration */ public function getConnection() { - return config('easy_panel_config.database.connection') ?: config('database.default'); + return config('easy_panel.database.connection'); } + /** * Run the migrations. * @@ -20,7 +21,7 @@ public function getConnection() */ public function up() { - Schema::create(config('easy_panel_config.database.panel_admin_table'), function (Blueprint $table) { + Schema::create(config('easy_panel.database.panel_admin_table'), function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); $table->boolean('is_superuser'); @@ -37,6 +38,6 @@ public function up() */ public function down() { - Schema::dropIfExists(config('easy_panel_config.database.panel_admin_table')); + Schema::dropIfExists(config('easy_panel.database.panel_admin_table')); } } diff --git a/src/EasyPanelServiceProvider.php b/src/EasyPanelServiceProvider.php index 0139871..b00775d 100644 --- a/src/EasyPanelServiceProvider.php +++ b/src/EasyPanelServiceProvider.php @@ -3,28 +3,34 @@ namespace EasyPanel; -use EasyPanel\Commands\{Actions\PublishStubs, +use EasyPanel\Commands\{Actions\DeleteCRUD, + Actions\Install, + Actions\MakeCRUD, + Actions\MakeCRUDConfig, + Actions\Migration, + Actions\PublishStubs, Actions\Reinstall, + Actions\Uninstall, CRUDActions\MakeCreate, - UserActions\GetAdmins, - Actions\MakeCRUDConfig, CRUDActions\MakeRead, CRUDActions\MakeSingle, CRUDActions\MakeUpdate, - Actions\DeleteCRUD, - Actions\MakeCRUD, UserActions\DeleteAdmin, - Actions\Install, - UserActions\MakeAdmin, - Actions\Migration, - Actions\Uninstall}; + UserActions\GetAdmins, + UserActions\MakeAdmin}; use EasyPanel\Http\Middleware\isAdmin; use EasyPanel\Http\Middleware\LangChanger; -use EasyPanel\Support\Contract\{LangManager, UserProviderFacade, AuthFacade}; -use Illuminate\{Routing\Router, Support\Facades\Blade, Support\Facades\Route, Support\ServiceProvider}; -use Livewire\Livewire; use EasyPanel\Models\PanelAdmin; +use EasyPanel\Support\Contract\{AuthFacade, LangManager, UserProviderFacade}; use EasyPanelTest\Dependencies\User; +use Exception; +use Illuminate\{Routing\Router, + Support\Facades\Blade, + Support\Facades\DB, + Support\Facades\Log, + Support\Facades\Route, + Support\ServiceProvider}; +use Livewire\Livewire; class EasyPanelServiceProvider extends ServiceProvider { @@ -34,7 +40,7 @@ public function register() $this->mergeConfigFrom(__DIR__ . '/../config/easy_panel_config.php', 'easy_panel'); // Check the status of module - if(!config('easy_panel.enable')) { + if (!config('easy_panel.enable')) { return; } @@ -42,14 +48,22 @@ public function register() $this->defineFacades(); } + private function defineFacades() + { + AuthFacade::shouldProxyTo(config('easy_panel.auth_class')); + UserProviderFacade::shouldProxyTo(config('easy_panel.admin_provider_class')); + LangManager::shouldProxyTo(config('easy_panel.lang_manager_class')); + } + public function boot() { - if(!config('easy_panel.enable')) { + if (!config('easy_panel.enable')) { return; } // Here we register publishes and Commands - if ($this->app->runningInConsole()) { + $isRunningInConsole = $this->app->runningInConsole(); + if ($isRunningInConsole) { $this->mergePublishes(); } @@ -62,35 +76,111 @@ public function boot() // Register Middleware $this->registerMiddlewareAlias(); - // Define routes if doesn't cached - $this->defineRoutes(); - // Load Livewire components $this->loadLivewireComponent(); - // Load relationship for administrators - $this->loadRelations(); + // check if database is connected to work with DB + $isDBConnected = $this->isDBConnected(); + if ($isDBConnected) { + // Define routes if doesn't cache + $this->defineRoutes(); + // Load relationship for administrators + $this->loadRelations(); + } else if ($isRunningInConsole) { + echo "\033[31m ** Please check your DB connection \033[0m\n"; + echo "\033[31m ** Can not load routes of EasyPanel \033[0m\n"; + } Blade::componentNamespace("\\EasyPanel\\ViewComponents", 'easypanel'); } - private function defineRoutes() + private function mergePublishes() { - if(!$this->app->routesAreCached()) { - $middlewares = array_merge(['web', 'isAdmin', 'LangChanger'], config('easy_panel.additional_middlewares')); + $this->publishes([__DIR__ . '/../config/easy_panel_config.php' => config_path('easy_panel.php')], 'easy-panel-config'); - Route::prefix(config('easy_panel.route_prefix')) - ->middleware($middlewares) - ->name(getRouteName() . '.') - ->group(__DIR__ . '/routes.php'); + $this->publishes([__DIR__ . '/../resources/views' => resource_path('/views/vendor/admin')], 'easy-panel-views'); + + $this->publishes([__DIR__ . '/../resources/assets' => public_path('/assets/admin')], 'easy-panel-styles'); + + $migrationForCopy = $this->publishMigration(); + if ($migrationForCopy) { + $this->publishes($migrationForCopy, 'easy-panel-migration'); } + + $this->publishes([__DIR__ . '/../resources/lang' => app()->langPath()], 'easy-panel-lang'); + + $this->publishes([__DIR__ . '/Commands/stub' => base_path('/stubs/panel')], 'easy-panel-stubs'); } - private function defineFacades() + /** + * Scans the target migration directory and copies migrations from the package that do not exist in the target project. + * + * This method performs several key operations: + * 1. It fetches the current migration files from the target project's migration directory. + * 2. It identifies migrations related to this package within the target project by looking for files with a specific naming convention (i.e., containing '_999999_' in the filename). + * 3. It then scans the package's migration directory for all available migrations. + * 4. For each migration in the package, it checks if a corresponding migration (with a modified naming convention indicating it belongs to the EasyPanel package) does not already exist in the target project. + * 5. If such a migration does not exist, it prepares to copy the migration file from the package to the target project, renaming it according to the target project's naming convention and appending '_easypanel' to indicate its origin. + * + * The method ultimately returns an associative array where the keys are the full paths to the source migration files in the package, and the values are the intended full paths for these migrations once copied to the target project. This array can then be used to perform the actual file copy operations. + * + * @return array An associative array mapping source migration file paths to target file paths for migrations that need to be copied. The structure is ['sourceFilePath' => 'targetFilePath']. + */ + private function publishMigration(): array { - AuthFacade::shouldProxyTo(config('easy_panel.auth_class')); - UserProviderFacade::shouldProxyTo(config('easy_panel.admin_provider_class')); - LangManager::shouldProxyTo(config('easy_panel.lang_manager_class')); + // 1- fetch current migration files + // 1-1- scan project + $projectMigrations = array_slice(scandir(base_path('/database/migrations/')), 2); + $packageMigrationInProject = []; + foreach ($projectMigrations as $migrationName) { + if (str_contains($migrationName, '_999999_')) { + // 2024_03_28_999999_migration_name.php + // convert to migration_name + $candidateMigrationName = substr(explode('_999999_', $migrationName)[1], 0, -4); + $packageMigrationInProject[] = $candidateMigrationName; + + } + } + + // 1-2- current migration + $packageMigration = []; + foreach (array_slice(scandir(__DIR__ . '/../database/migrations'), 2) as $migrationName) { + // migration_name.php + // convert to migration_name + $packageMigration[] = substr($migrationName, 0, -4); + } + // copy not existence files: + $migrationForCopy = []; + foreach ($packageMigration as $migrationName) { + $targetMigrationName = 'create_' . $migrationName . '_easypanel'; + if (!in_array($targetMigrationName, $packageMigrationInProject)) { + $migrationForCopy[dirname(__DIR__) . '/database/migrations/' . $migrationName . '.php'] = base_path('/database/migrations/' . date('Y_m_d') . '_999999_create_' . $migrationName . '_easypanel.php'); + } + } + return $migrationForCopy; + + + } + + private function bindCommands() + { + $this->commands([ + MakeAdmin::class, + DeleteAdmin::class, + Install::class, + MakeCreate::class, + MakeUpdate::class, + MakeRead::class, + MakeSingle::class, + MakeCRUD::class, + DeleteCRUD::class, + MakeCRUDConfig::class, + GetAdmins::class, + Migration::class, + Uninstall::class, + Reinstall::class, + PublishStubs::class + ]); } private function registerMiddlewareAlias() @@ -117,50 +207,36 @@ private function loadLivewireComponent() Livewire::component('admin::livewire.admins.update', Http\Livewire\Admins\Update::class); } - private function mergePublishes() + private function isDBConnected() { - $this->publishes([__DIR__ . '/../config/easy_panel_config.php' => config_path('easy_panel.php')], 'easy-panel-config'); - - $this->publishes([__DIR__ . '/../resources/views' => resource_path('/views/vendor/admin')], 'easy-panel-views'); - - $this->publishes([__DIR__ . '/../resources/assets' => public_path('/assets/admin')], 'easy-panel-styles'); - - $this->publishes([ - __DIR__ . '/../database/migrations/cruds_table.php' => base_path('/database/migrations/' . date('Y_m_d') . '_999999_create_cruds_table_easypanel.php'), - __DIR__ . '/../database/migrations/panel_admins_table.php' => base_path('/database/migrations/' . date('Y_m_d') . '_999999_create_panel_admins_table_easypanel.php'), - ], 'easy-panel-migration'); - - $this->publishes([__DIR__.'/../resources/lang' => app()->langPath()], 'easy-panel-lang'); + try { + DB::connection(config('easy_panel.database.connection'))->getPDO(); + } catch (Exception $e) { + Log::error('Please check your DB connection \n Can not load routes of EasyPanel'); + Log::error($e->getMessage()); + return false; + } + return true; - $this->publishes([__DIR__.'/Commands/stub' => base_path('/stubs/panel')], 'easy-panel-stubs'); } - private function bindCommands() + private function defineRoutes() { - $this->commands([ - MakeAdmin::class, - DeleteAdmin::class, - Install::class, - MakeCreate::class, - MakeUpdate::class, - MakeRead::class, - MakeSingle::class, - MakeCRUD::class, - DeleteCRUD::class, - MakeCRUDConfig::class, - GetAdmins::class, - Migration::class, - Uninstall::class, - Reinstall::class, - PublishStubs::class - ]); + if (!$this->app->routesAreCached()) { + $middlewares = array_merge(['web', 'isAdmin', 'LangChanger'], config('easy_panel.additional_middlewares')); + + Route::prefix(config('easy_panel.route_prefix')) + ->middleware($middlewares) + ->name(getRouteName() . '.') + ->group(__DIR__ . '/routes.php'); + } } private function loadRelations() { $model = !$this->app->runningUnitTests() ? config('easy_panel.user_model') : User::class; - $model::resolveRelationUsing('panelAdmin', function ($userModel){ + $model::resolveRelationUsing('panelAdmin', function ($userModel) { return $userModel->hasOne(PanelAdmin::class)->latest(); }); } diff --git a/src/Models/CRUD.php b/src/Models/CRUD.php index 9f0fb50..ccb2c94 100644 --- a/src/Models/CRUD.php +++ b/src/Models/CRUD.php @@ -8,6 +8,8 @@ class CRUD extends Model { + protected $guarded = []; + /** * Create a new Eloquent model instance. * @@ -15,17 +17,13 @@ class CRUD extends Model */ public function __construct(array $attributes = []) { - $connection = config('easy_panel_config.database.connection') ?: config('database.default'); - - $this->setConnection($connection); - - $this->setTable(config('easy_panel_config.database.crud_table')); + + $this->setConnection(config('easy_panel.database.connection')); + $this->setTable(config('easy_panel.database.crud_table')); parent::__construct($attributes); } - protected $guarded = []; - public function scopeActive($query) { return $query->where('built', true)->where('active', true)->get(); diff --git a/src/Models/PanelAdmin.php b/src/Models/PanelAdmin.php index 855fb1f..afa37bb 100644 --- a/src/Models/PanelAdmin.php +++ b/src/Models/PanelAdmin.php @@ -9,24 +9,22 @@ class PanelAdmin extends Model { + protected $guarded = []; + /** - * Create a new Eloquent model instance. - * - * @param array $attributes - */ + * Create a new Eloquent model instance. + * + * @param array $attributes + */ public function __construct(array $attributes = []) { - $connection = config('easy_panel_config.database.connection') ?: config('database.default'); - - $this->setConnection($connection); - $this->setTable(config('easy_panel_config.database.panel_admin_table')); + $this->setConnection(config('easy_panel.database.connection')); + $this->setTable(config('easy_panel.database.panel_admin_table')); parent::__construct($attributes); } - protected $guarded = []; - public function user() { return $this->belongsTo(config('easy_panel.user_model')); diff --git a/src/routes.php b/src/routes.php index 1eed0ab..5ab7aae 100644 --- a/src/routes.php +++ b/src/routes.php @@ -1,16 +1,22 @@ name('home'); -Route::post('/logout', function (){ +Route::post('/logout', function () { auth()->logout(); return redirect(config('easy_panel.redirect_unauthorized')); })->name('logout'); -if (\Illuminate\Support\Facades\Schema::hasTable('cruds')) { - foreach (\EasyPanel\Models\CRUD::active() as $crud) { +if (Schema::connection(config('easy_panel.database.connection'))->hasTable(config('easy_panel.database.crud_table'))) { + foreach (CRUD::active() as $crud) { $crudConfig = getCrudConfig($crud->name); $name = ucfirst($crud->name); $component = "App\\Http\\Livewire\\Admin\\$name"; @@ -41,12 +47,12 @@ } } -Route::prefix('crud')->middleware('dynamicAcl')->name('crud.')->group(function (){ +Route::prefix('crud')->middleware('dynamicAcl')->name('crud.')->group(function () { Route::get('/', \EasyPanel\Http\Livewire\CRUD\Lists::class)->name('lists'); Route::get('/create', \EasyPanel\Http\Livewire\CRUD\Create::class)->name('create'); }); -Route::get('setLang', function (){ +Route::get('setLang', function () { $lang = request()->get('lang'); session()->put('easypanel_lang', $lang); @@ -55,18 +61,18 @@ return redirect()->back(); })->name('setLang'); -Route::get('translation', \EasyPanel\Http\Livewire\Translation\Manage::class) +Route::get('translation', Manage::class) ->middleware('dynamicAcl') ->name('translation'); -Route::prefix('role')->middleware('dynamicAcl')->name('role.')->group(function (){ +Route::prefix('role')->middleware('dynamicAcl')->name('role.')->group(function () { Route::get('/', \EasyPanel\Http\Livewire\Role\Lists::class)->name('lists'); - Route::get('/create', \EasyPanel\Http\Livewire\Role\Create::class)->name('create'); + Route::get('/create', Create::class)->name('create'); Route::get('/update/{role}', \EasyPanel\Http\Livewire\Role\Update::class)->name('update'); }); -Route::prefix('admins')->middleware('dynamicAcl')->name('admins.')->group(function (){ - Route::get('/', \EasyPanel\Http\Livewire\Admins\Lists::class)->name('lists'); +Route::prefix('admins')->middleware('dynamicAcl')->name('admins.')->group(function () { + Route::get('/', Lists::class)->name('lists'); // Route::get('/create', \EasyPanel\Http\Livewire\Admins\Create::class)->name('create'); - Route::get('/update/{admin}', \EasyPanel\Http\Livewire\Admins\Update::class)->name('update'); + Route::get('/update/{admin}', Update::class)->name('update'); }); diff --git a/tests/Dependencies/Article.php b/tests/Dependencies/Article.php new file mode 100644 index 0000000..a5b8c62 --- /dev/null +++ b/tests/Dependencies/Article.php @@ -0,0 +1,9 @@ +'boolean']; public $timestamps = false; } diff --git a/tests/Dependencies/database/migrations/2020_09_06_99999_create_articles_table.php b/tests/Dependencies/database/migrations/2020_09_06_99999_create_articles_table.php new file mode 100644 index 0000000..a2bb310 --- /dev/null +++ b/tests/Dependencies/database/migrations/2020_09_06_99999_create_articles_table.php @@ -0,0 +1,21 @@ +id(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('articles'); + } +} diff --git a/tests/Feature/ManageAdminWithCommandTest.php b/tests/Feature/ManageAdminWithCommandTest.php index e2300f0..5609066 100644 --- a/tests/Feature/ManageAdminWithCommandTest.php +++ b/tests/Feature/ManageAdminWithCommandTest.php @@ -2,17 +2,19 @@ namespace EasyPanelTest\Feature; +use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Artisan; use EasyPanelTest\TestCase; use EasyPanel\Support\Contract\UserProviderFacade; - +use Illuminate\Support\Facades\Schema; class ManageAdminWithCommandTest extends TestCase { - use RefreshDatabase; + use DatabaseMigrations; /** @test * */ public function create_admin_with_command(){ + Artisan::call('panel:add', [ 'user' => $this->user->id ]); diff --git a/tests/Feature/MiddlewareTest.php b/tests/Feature/MiddlewareTest.php index 2bc27aa..6dba5ad 100644 --- a/tests/Feature/MiddlewareTest.php +++ b/tests/Feature/MiddlewareTest.php @@ -4,6 +4,7 @@ namespace EasyPanelTest\Feature; use EasyPanel\Http\Middleware\isAdmin; +use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Auth; @@ -12,7 +13,7 @@ class MiddlewareTest extends TestCase { - use RefreshDatabase; + use DatabaseMigrations; protected function setUp(): void { diff --git a/tests/Feature/UserProviderFacadeTest.php b/tests/Feature/UserProviderFacadeTest.php index f3b3625..4f23548 100644 --- a/tests/Feature/UserProviderFacadeTest.php +++ b/tests/Feature/UserProviderFacadeTest.php @@ -3,12 +3,13 @@ namespace EasyPanelTest\Feature; use EasyPanel\Support\Contract\UserProviderFacade; +use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\RefreshDatabase; use EasyPanelTest\TestCase; class UserProviderFacadeTest extends TestCase { - use RefreshDatabase; + use DatabaseMigrations; /** @test * */ public function find_a_real_user_by_id(){ diff --git a/tests/TestCase.php b/tests/TestCase.php index e2a1a76..87bb9ae 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,8 +4,11 @@ use EasyPanel\EasyPanelServiceProvider; use EasyPanel\Parsers\StubParser; +use EasyPanelTest\Dependencies\Article; use EasyPanelTest\Dependencies\User; use Faker\Factory; +use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Hash; use Iya30n\DynamicAcl\Providers\DynamicAclServiceProvider; use Javoscript\MacroableModels\MacroableModelsServiceProvider; @@ -15,7 +18,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase { /** - * @var \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model + * @var Collection|Model */ protected $user; @@ -24,26 +27,28 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase */ protected $parser; + public function getAdmin() + { + $this->user->panelAdmin()->create([ + 'is_superuser' => true + ]); + + return $this->user->refresh(); + } + protected function setUp(): void { parent::setUp(); - $this->loadMigrationsFrom(__DIR__.'/Dependencies/database/migrations'); - $this->loadMigrationsFrom(__DIR__.'/../vendor/iya30n/dynamic-acl/database/migrations'); + $this->loadMigrationsFrom(__DIR__ . '/Dependencies/database/migrations'); + $this->loadMigrationsFrom(__DIR__ . '/../vendor/iya30n/dynamic-acl/database/migrations'); $this->setUser(); $this->setParser(); - + config()->set('easy_panel.user_model', User::class); - } + config()->set('easy_panel.database.panel_admin_table', 'panel_admins'); + config()->set('easy_panel.database.crud_table', 'cruds'); - protected function getPackageProviders($app) - { - return [ - EasyPanelServiceProvider::class, - LivewireServiceProvider::class, - MacroableModelsServiceProvider::class, - DynamicAclServiceProvider::class, - ]; } protected function setUser() @@ -53,17 +58,18 @@ protected function setUser() $this->user = $user; } - public function getAdmin() + private function setParser() { - $this->user->panelAdmin()->create([ - 'is_superuser' => true - ]); - - return $this->user->refresh(); + $this->parser = new StubParser('article', Article::class); } - private function setParser() + protected function getPackageProviders($app) { - $this->parser = new StubParser('article', \App\Models\Article::class); + return [ + EasyPanelServiceProvider::class, + LivewireServiceProvider::class, + MacroableModelsServiceProvider::class, + DynamicAclServiceProvider::class, + ]; } } diff --git a/tests/Unit/StubParserTest.php b/tests/Unit/StubParserTest.php index 712f41d..228fa9e 100644 --- a/tests/Unit/StubParserTest.php +++ b/tests/Unit/StubParserTest.php @@ -2,7 +2,8 @@ namespace EasyPanelTest\Unit; -use App\Models\Article; + +use EasyPanelTest\Dependencies\Article; use EasyPanelTest\Dependencies\User; use Illuminate\Support\Str; use EasyPanel\Parsers\HTMLInputs\Text;