├── .gitignore ├── README.md ├── artisan ├── composer.json ├── config └── config.php ├── database ├── factories │ ├── ActorFactory.php │ ├── CategoryFactory.php │ ├── DirectorFactory.php │ ├── EpisodeFactory.php │ ├── MovieFactory.php │ ├── RegionFactory.php │ ├── StudioFactory.php │ └── TagFactory.php ├── migrations │ ├── 2015_08_04_131614_create_menus_table.php │ ├── 2015_08_04_131614_create_settings_table.php │ ├── 2020_03_31_114745_remove_backpackuser_model.php │ ├── 2022_07_09_153613_create_themes_table.php │ ├── 2022_07_10_125114_create_permission_tables.php │ ├── 2022_07_10_153442_create_categories_table.php │ ├── 2022_07_10_153517_create_actors_table.php │ ├── 2022_07_10_153517_create_directors_table.php │ ├── 2022_07_10_153517_create_regions_table.php │ ├── 2022_07_10_153517_create_studios_table.php │ ├── 2022_07_10_153517_create_tags_table.php │ ├── 2022_07_10_153613_create_movies_table.php │ ├── 2022_07_10_153614_create_episodes_table.php │ ├── 2022_07_11_062342_create_actor_movie_table.php │ ├── 2022_07_11_062342_create_category_movie_table.php │ ├── 2022_07_11_062342_create_director_movie_table.php │ ├── 2022_07_11_062342_create_movie_region_table.php │ ├── 2022_07_11_062342_create_movie_studio_table.php │ ├── 2022_07_11_062342_create_movie_tag_table.php │ ├── 2022_11_02_071552_create_catalogs_table.php │ └── 2023_06_06_185118_add_fulltext_index_to_movies.php └── seeders │ ├── CatalogsTableSeeder.php │ ├── CategoriesTableSeeder.php │ ├── MenusTableSeeder.php │ ├── PermissionsSeeder.php │ ├── RegionsTableSeeder.php │ └── SettingsTableSeeder.php ├── draft.yml ├── package.json ├── resources ├── assets │ └── js │ │ ├── hls.min.js │ │ ├── jwplayer-8.9.3.js │ │ └── jwplayer.hlsjs.min.js └── views │ ├── core │ ├── base │ │ ├── columns │ │ │ └── relationship.blade.php │ │ ├── dashboard.blade.php │ │ ├── fields │ │ │ ├── checklist.blade.php │ │ │ ├── ckfinder.blade.php │ │ │ ├── fields_option.blade.php │ │ │ ├── page_or_link.blade.php │ │ │ ├── select2_from_array.blade.php │ │ │ ├── select2_relationship_tags.blade.php │ │ │ ├── select2_tags.blade.php │ │ │ ├── select_from_table.blade.php │ │ │ ├── select_theme.blade.php │ │ │ └── update_fields_option.blade.php │ │ └── inc │ │ │ ├── main_header.blade.php │ │ │ ├── sidebar_content.blade.php │ │ │ └── topbar_right_content.blade.php │ ├── crud │ │ ├── buttons │ │ │ └── bulk_delete.blade.php │ │ └── filters │ │ │ ├── select2.blade.php │ │ │ └── simple.blade.php │ ├── movies │ │ ├── columns │ │ │ └── column_movie_info.blade.php │ │ ├── create.blade.php │ │ ├── edit.blade.php │ │ └── inc │ │ │ └── episode.blade.php │ └── sitemap │ │ └── styles.blade.php │ └── themes │ └── layout.blade.php ├── routes └── admin.php ├── src ├── Console │ ├── ChangeDomainEpisodeCommand.php │ ├── CreateUser.php │ ├── GenerateMenuCommand.php │ └── InstallCommand.php ├── Contracts │ ├── HasUrlInterface.php │ ├── SeoInterface.php │ └── TaxonomyInterface.php ├── Controllers │ ├── Admin │ │ ├── ActorCrudController.php │ │ ├── AdminController.php │ │ ├── CatalogCrudController.php │ │ ├── CategoryCrudController.php │ │ ├── DirectorCrudController.php │ │ ├── EpisodeCrudController.php │ │ ├── MenuCrudController.php │ │ ├── MovieCrudController.php │ │ ├── PluginController.php │ │ ├── QuickActionController.php │ │ ├── RegionCrudController.php │ │ ├── SiteMapController.php │ │ ├── StudioCrudController.php │ │ ├── TagCrudController.php │ │ └── ThemeManagementController.php │ └── Controller.php ├── Helpers │ └── helpers.php ├── Middleware │ ├── CKFinderAuth.php │ ├── EncryptCookies.php │ └── VerifyCsrfToken.php ├── Models │ ├── Actor.php │ ├── Catalog.php │ ├── Category.php │ ├── Director.php │ ├── Episode.php │ ├── Menu.php │ ├── Movie.php │ ├── Region.php │ ├── Studio.php │ ├── Tag.php │ ├── Theme.php │ └── User.php ├── OphimServiceProvider.php ├── Policies │ ├── ActorPolicy.php │ ├── CatalogPolicy.php │ ├── CategoryPolicy.php │ ├── CrawlSchedulePolicy.php │ ├── DirectorPolicy.php │ ├── EpisodePolicy.php │ ├── MenuPolicy.php │ ├── MoviePolicy.php │ ├── PermissionPolicy.php │ ├── RegionPolicy.php │ ├── RolePolicy.php │ ├── StudioPolicy.php │ ├── TagPolicy.php │ └── UserPolicy.php ├── Requests │ ├── ActorRequest.php │ ├── CatalogRequest.php │ ├── CategoryRequest.php │ ├── CrawlScheduleRequest.php │ ├── DirectorRequest.php │ ├── MenuRequest.php │ ├── MovieRequest.php │ ├── RegionRequest.php │ ├── StudioRequest.php │ └── TagRequest.php ├── Rules │ └── UniqueName.php ├── Theme.php └── Traits │ ├── ActorLog.php │ ├── HasDescription.php │ ├── HasFactory.php │ ├── HasKeywords.php │ ├── HasTitle.php │ ├── HasUniqueName.php │ ├── Operations │ └── BulkDeleteOperation.php │ └── Sluggable.php ├── tests └── databases │ └── DatabaseTesting.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server Requirements: 2 | - Laravel Framework 8. 3 | - PHP 7.3 or higher. 4 | + Configure `php.ini`: 5 | 6 | ``` 7 | max_input_vars=100000 8 | ``` 9 | - MySQL 5.7 or higher. 10 | # Add-on & Themes: 11 | - Home: [OPhimCMS.CC](https://opcms.cc) 12 | - Admin: [Demo.OPhimCMS.CC/admin](https://demo.ophimcms.cc/admin) 13 | - Free Movies Data: [OPhim.Movie](https://ophim.movie) 14 | 15 | - Add-on: 16 | - [OPhim Crawler](https://github.com/hacoidev/ophim-crawler) 17 | - Theme: [MORE...](https://opcms.cc) 18 | 19 | # Installation: 20 | 1. CD to project root and run: `composer require hacoidev/ophim-core -W` 21 | 2. Configuration your database connection information in file `.env` 22 | 3. Then, run command: `php artisan ophim:install` 23 | 4. Change app\Models\User: 24 | ```php 25 | use Ophim\Core\Models\User as OphimUser; 26 | 27 | class User extends OphimUser { 28 | use HasApiTokens, HasFactory, Notifiable; 29 | // ... 30 | } 31 | ``` 32 | 5. Create new user by command: `php artisan ophim:user` 33 | 34 | 6. Remove this route definition in routes/web.php 35 | ```php 36 | Route::get('/', function () { 37 | return view('welcome'); 38 | }); 39 | ``` 40 | 7. Run `php artisan optimize:clear` 41 | 42 | # Update: 43 | 1. CD to project root and run: `composer update hacoidev/ophim-core -W` 44 | 2. Then, run command: `php artisan ophim:install` 45 | 3. Run `php artisan optimize:clear` 46 | 4. Clear PHP Opcache in server (if enabled) 47 | 48 | # Note 49 | - Configure a production environment file `.env` 50 | + `APP_NAME=your_app_name` 51 | + `APP_ENV=production` 52 | + `APP_DEBUG=false` 53 | + `APP_URL=https://your-domain.com` 54 | - Configure timezone `/config/app.php` 55 | + `'timezone' => 'Asia/Ho_Chi_Minh'` 56 | + `'locale' => 'vi'` 57 | 58 | - Command CMS 59 | + `php artisan ophim:menu:generate` : Generate menu 60 | + `php artisan ophim:episode:change_domain` : Change episode domain play stream 61 | 62 | # Command: 63 | - Generate menu categories & regions: `php artisan ophim:menu:generate` 64 | 65 | # Reset view counter: 66 | - Setup crontab, add this entry: 67 | ``` 68 | * * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1 69 | ``` 70 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hacoidev/ophim-core", 3 | "description": "Ophim's core features", 4 | "type": "library", 5 | "authors": [ 6 | { 7 | "name": "hacoidev", 8 | "email": "hacoi.dev@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "laravel/framework": "^6|^7|^8", 13 | "ckfinder/ckfinder-laravel-package": "v3.5.2.1", 14 | "hacoidev/laravel-caching-model": "^1.0.0", 15 | "hacoidev/crud": "^1.0.0", 16 | "hacoidev/settings": "^1.0.0", 17 | "hacoidev/permissionmanager": "^1.0.0", 18 | "spatie/laravel-sitemap": "^5.8", 19 | "artesaos/seotools": "^v0.22.1" 20 | }, 21 | "license": "MIT", 22 | "autoload": { 23 | "psr-4": { 24 | "Ophim\\Core\\": "src/", 25 | "Ophim\\Core\\Database\\Factories\\": "database/factories/", 26 | "Ophim\\Core\\Database\\Seeders\\": "database/seeders/" 27 | } 28 | }, 29 | "extra": { 30 | "laravel": { 31 | "providers": [ 32 | "Ophim\\Core\\OphimServiceProvider" 33 | ] 34 | } 35 | }, 36 | "minimum-stability": "stable" 37 | } 38 | -------------------------------------------------------------------------------- /config/config.php: -------------------------------------------------------------------------------- 1 | explode('@', \PackageVersions\Versions::getVersion('hacoidev/ophim-core') ?? 0)[0], 5 | 'episodes' => [ 6 | 'types' => [ 7 | 'embed' => 'Nhúng', 8 | 'mp4' => 'MP4', 9 | 'm3u8' => 'M3U8' 10 | ] 11 | ], 12 | 'ckfinder' => [ 13 | 'loadRoutes' => false, 14 | 'backends' => [ 15 | 'name' => 'default', 16 | 'adapter' => 'local', 17 | 'baseUrl' => '/storage/', 18 | 'root' => public_path('/storage/'), 19 | 'chmodFiles' => 0777, 20 | 'chmodFolders' => 0755, 21 | 'filesystemEncoding' => 'UTF-8' 22 | ] 23 | ] 24 | ]; 25 | -------------------------------------------------------------------------------- /database/factories/ActorFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'slug' => Str::slug($name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/CategoryFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'slug' => Str::slug($name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/DirectorFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'slug' => Str::slug($name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/EpisodeFactory.php: -------------------------------------------------------------------------------- 1 | $name = rand(1, 5), 27 | 'slug' => Str::slug('tap-' . $name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/MovieFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'origin_name' => $name, 28 | 'slug' => Str::slug($name.microtime(true)), 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /database/factories/RegionFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'slug' => Str::slug($name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/StudioFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'slug' => Str::slug($name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/TagFactory.php: -------------------------------------------------------------------------------- 1 | $name = $this->faker->name, 27 | 'slug' => Str::slug($name), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/migrations/2015_08_04_131614_create_menus_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name', 100); 19 | $table->string('type', 20)->nullable(); 20 | $table->string('link', 255)->nullable(); 21 | $table->integer('parent_id')->unsigned()->nullable(); 22 | $table->integer('lft')->unsigned()->nullable(); 23 | $table->integer('rgt')->unsigned()->nullable(); 24 | $table->integer('depth')->unsigned()->nullable(); 25 | $table->timestamps(); 26 | $table->softDeletes(); 27 | }); 28 | } 29 | 30 | /** 31 | * Reverse the migrations. 32 | * 33 | * @return void 34 | */ 35 | public function down() 36 | { 37 | Schema::dropIfExists('menus'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/migrations/2015_08_04_131614_create_settings_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('key')->unique(); 19 | $table->string('name'); 20 | $table->string('description')->nullable(); 21 | $table->text('value')->nullable(); 22 | $table->text('field'); 23 | $table->string('group')->nullable()->index(); 24 | $table->boolean('active')->index(); 25 | $table->timestamps(); 26 | 27 | $table->index(['group', 'active']); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | * 34 | * @return void 35 | */ 36 | public function down() 37 | { 38 | Schema::dropIfExists('settings'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/2020_03_31_114745_remove_backpackuser_model.php: -------------------------------------------------------------------------------- 1 | replaceModels($model_has_roles); 23 | } 24 | if (\Illuminate\Support\Facades\Schema::hasTable($model_has_permissions)) { 25 | $this->replaceModels($model_has_permissions); 26 | } 27 | } 28 | 29 | public function replaceModels($table_name) 30 | { 31 | Log::info('Replacing BackpackUser model in '.$table_name); 32 | 33 | // if you've ended up with duplicate entries (both for App\User and App\Models\BackpackUser) 34 | // we can just delete them 35 | $userEntries = DB::table($table_name) 36 | ->where('model_type', "App\User") 37 | ->get(); 38 | 39 | foreach ($userEntries as $entry) { 40 | DB::table($table_name) 41 | ->where('role_id', $entry->role_id) 42 | ->where('model_type', 'App\Models\BackpackUser') 43 | ->where('model_id', $entry->model_id) 44 | ->delete(); 45 | } 46 | 47 | // for the rest of them, we can just replace the BackpackUser model with User 48 | DB::table($table_name) 49 | ->where('model_type', "App\Models\BackpackUser") 50 | ->update([ 51 | 'model_type' => "App\User", 52 | ]); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /database/migrations/2022_07_09_153613_create_themes_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name')->index(); 19 | $table->string('display_name'); 20 | $table->string('preview_image')->nullable(); 21 | $table->string('author'); 22 | $table->string('package_name'); 23 | $table->text('value')->nullable(); 24 | $table->boolean('active')->default(false); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('themes'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153442_create_categories_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->unique(); 19 | $table->string('slug')->unique()->index(); 20 | $table->string('seo_title')->nullable(); 21 | $table->string('seo_des')->nullable(); 22 | $table->string('seo_key')->nullable(); 23 | $table->unsignedBigInteger('user_id')->nullable()->index(); 24 | $table->string('user_name')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('categories'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153517_create_actors_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('name_md5')->unique(); 20 | $table->string('slug')->index(); 21 | $table->enum('gender', ['male', 'female', 'other'])->nullable(); 22 | $table->string('bio')->nullable(); 23 | $table->string('thumb_url', 2048)->nullable(); 24 | $table->string('seo_title')->nullable(); 25 | $table->string('seo_des')->nullable(); 26 | $table->string('seo_key')->nullable(); 27 | $table->timestamps(); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | * 34 | * @return void 35 | */ 36 | public function down() 37 | { 38 | Schema::dropIfExists('actors'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153517_create_directors_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('name_md5')->unique(); 20 | $table->string('slug')->index(); 21 | $table->enum('gender', ['male', 'female', 'other'])->nullable(); 22 | $table->string('bio')->nullable(); 23 | $table->string('thumb_url', 2048)->nullable(); 24 | $table->string('seo_title')->nullable(); 25 | $table->string('seo_des')->nullable(); 26 | $table->string('seo_key')->nullable(); 27 | $table->timestamps(); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | * 34 | * @return void 35 | */ 36 | public function down() 37 | { 38 | Schema::dropIfExists('directors'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153517_create_regions_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->unique(); 19 | $table->string('slug')->unique()->index(); 20 | $table->string('seo_title')->nullable(); 21 | $table->string('seo_des')->nullable(); 22 | $table->string('seo_key')->nullable(); 23 | $table->unsignedBigInteger('user_id')->nullable()->index(); 24 | $table->string('user_name')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('regions'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153517_create_studios_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('name_md5')->unique(); 20 | $table->string('slug')->index(); 21 | $table->string('thumb_url', 2048)->nullable(); 22 | $table->string('seo_title')->nullable(); 23 | $table->string('seo_des')->nullable(); 24 | $table->string('seo_key')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('studios'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153517_create_tags_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('name_md5')->unique(); 20 | $table->string('slug')->index(); 21 | $table->string('seo_title')->nullable(); 22 | $table->string('seo_des')->nullable(); 23 | $table->string('seo_key')->nullable(); 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('tags'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153613_create_movies_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name', 1024); 19 | $table->string('origin_name', 1024); 20 | $table->string('slug')->unique(); 21 | $table->text('content')->nullable(); 22 | $table->string('thumb_url', 2048)->nullable(); 23 | $table->string('poster_url', 2048)->nullable(); 24 | $table->enum('type', ['single', 'series']); 25 | $table->enum('status', ['trailer', 'ongoing', 'completed']); 26 | $table->string('trailer_url', 2048)->nullable(); 27 | $table->string('episode_time')->nullable(); 28 | $table->string('episode_current')->nullable(); 29 | $table->string('episode_total')->nullable(); 30 | $table->string('quality')->nullable()->default('HD'); 31 | $table->string('language')->nullable()->default('Vietsub'); 32 | $table->string('notify', 512)->nullable(); 33 | $table->string('showtimes', 512)->nullable(); 34 | $table->integer('publish_year')->index()->nullable(); 35 | $table->boolean('is_shown_in_theater')->default(false); 36 | $table->boolean('is_recommended')->default(false); 37 | $table->boolean('is_copyright')->default(false); 38 | $table->boolean('is_sensitive_content')->default(false); 39 | 40 | $table->integer('episode_server_count')->default(0); 41 | $table->integer('episode_data_count')->default(0); 42 | 43 | $table->integer('view_total')->default(0); 44 | $table->integer('view_day')->default(0); 45 | $table->integer('view_week')->default(0); 46 | $table->integer('view_month')->default(0); 47 | $table->integer('rating_count')->default(0); 48 | $table->decimal('rating_star', 3, 1)->default(0); 49 | 50 | $table->string('update_handler', 1024)->nullable(); 51 | $table->string('update_identity', 2048)->nullable(); 52 | $table->string('update_checksum', 2048)->nullable(); 53 | 54 | $table->unsignedBigInteger('user_id')->nullable()->index(); 55 | $table->string('user_name')->nullable(); 56 | $table->timestamps(); 57 | }); 58 | } 59 | 60 | /** 61 | * Reverse the migrations. 62 | * 63 | * @return void 64 | */ 65 | public function down() 66 | { 67 | Schema::dropIfExists('movies'); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /database/migrations/2022_07_10_153614_create_episodes_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | 19 | $table->unsignedBigInteger('movie_id')->index(); 20 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 21 | 22 | $table->string('server'); 23 | $table->string('name'); 24 | $table->string('slug'); 25 | $table->string('type'); 26 | $table->string('link')->nullable(); 27 | $table->boolean('has_report')->default(false); 28 | $table->string('report_message', 512)->nullable(); 29 | $table->timestamps(); 30 | 31 | $table->index(['movie_id', 'slug']); 32 | }); 33 | } 34 | 35 | /** 36 | * Reverse the migrations. 37 | * 38 | * @return void 39 | */ 40 | public function down() 41 | { 42 | Schema::dropIfExists('episodes'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /database/migrations/2022_07_11_062342_create_actor_movie_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('movie_id')->index(); 18 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 19 | 20 | $table->unsignedBigInteger('actor_id')->index(); 21 | $table->foreign('actor_id')->references('id')->on('actors')->onDelete('cascade'); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('actor_movie'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2022_07_11_062342_create_category_movie_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('movie_id')->index(); 18 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 19 | 20 | $table->unsignedBigInteger('category_id')->index(); 21 | $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('category_movie'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2022_07_11_062342_create_director_movie_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('movie_id')->index(); 18 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 19 | 20 | $table->unsignedBigInteger('director_id')->index(); 21 | $table->foreign('director_id')->references('id')->on('directors')->onDelete('cascade'); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('director_movie'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2022_07_11_062342_create_movie_region_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('movie_id')->index(); 18 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 19 | 20 | $table->unsignedBigInteger('region_id')->index(); 21 | $table->foreign('region_id')->references('id')->on('regions')->onDelete('cascade'); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('movie_region'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2022_07_11_062342_create_movie_studio_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('movie_id')->index(); 18 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 19 | 20 | $table->unsignedBigInteger('studio_id')->index(); 21 | $table->foreign('studio_id')->references('id')->on('studios')->onDelete('cascade'); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('movie_studio'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2022_07_11_062342_create_movie_tag_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('movie_id')->index(); 18 | $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); 19 | 20 | $table->unsignedBigInteger('tag_id')->index(); 21 | $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('movie_tag'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2022_11_02_071552_create_catalogs_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name')->unique(); 19 | $table->string('slug')->unique()->index(); 20 | $table->integer('paginate')->default(20); 21 | $table->string('value')->nullable(); 22 | $table->string('seo_title')->nullable(); 23 | $table->string('seo_des')->nullable(); 24 | $table->string('seo_key')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('catalogs'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2023_06_06_185118_add_fulltext_index_to_movies.php: -------------------------------------------------------------------------------- 1 | 'Phim mới', 21 | 'slug' => 'phim-moi', 22 | 'paginate' => 20, 23 | 'value' => '|is_copyright|0|updated_at|desc', 24 | 'seo_title' => 'Title Phim mới', 25 | 'seo_des' => 'Des Phim mới', 26 | 'seo_key' => 'Key Phim mới', 27 | ], 28 | [ 29 | 'name' => 'Phim bộ', 30 | 'slug' => 'phim-bo', 31 | 'paginate' => 20, 32 | 'value' => '|type|series|updated_at|desc', 33 | 'seo_title' => 'Title Phim bộ', 34 | 'seo_des' => 'Des Phim bộ', 35 | 'seo_key' => 'Key Phim bộ', 36 | ], 37 | [ 38 | 'name' => 'Phim lẻ', 39 | 'slug' => 'phim-le', 40 | 'paginate' => 20, 41 | 'value' => '|type|single|updated_at|desc', 42 | 'seo_title' => 'Title Phim lẻ', 43 | 'seo_des' => 'Des Phim lẻ', 44 | 'seo_key' => 'Key Phim lẻ', 45 | ] 46 | ]; 47 | 48 | foreach ($catalogs as $index => $catalog) { 49 | $result = Catalog::firstOrCreate(collect($catalog)->only('slug')->toArray(), collect($catalog)->except('slug')->toArray()); 50 | 51 | if (!$result) { 52 | $this->command->info("Insert failed at record $index"); 53 | 54 | return; 55 | } 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /database/seeders/CategoriesTableSeeder.php: -------------------------------------------------------------------------------- 1 | "Hành Động", 21 | "slug" => "hanh-dong", 22 | ], 23 | [ 24 | "name" => "Tình Cảm", 25 | "slug" => "tinh-cam", 26 | ], 27 | [ 28 | "name" => "Hài Hước", 29 | "slug" => "hai-huoc", 30 | ], 31 | [ 32 | "name" => "Cổ Trang", 33 | "slug" => "co-trang", 34 | ], 35 | [ 36 | "name" => "Tâm Lý", 37 | "slug" => "tam-ly", 38 | ], 39 | [ 40 | "name" => "Hình Sự", 41 | "slug" => "hinh-su", 42 | ], 43 | [ 44 | "name" => "Chiến Tranh", 45 | "slug" => "chien-tranh", 46 | ], 47 | [ 48 | "name" => "Thể Thao", 49 | "slug" => "the-thao", 50 | ], 51 | [ 52 | "name" => "Võ Thuật", 53 | "slug" => "vo-thuat", 54 | ], 55 | [ 56 | "name" => "Viễn Tưởng", 57 | "slug" => "vien-tuong", 58 | ], 59 | [ 60 | "name" => "Phiêu Lưu", 61 | "slug" => "phieu-luu", 62 | ], 63 | [ 64 | "name" => "Khoa Học", 65 | "slug" => "khoa-hoc", 66 | ], 67 | [ 68 | "name" => "Kinh Dị", 69 | "slug" => "kinh-di", 70 | ], 71 | [ 72 | "name" => "Âm Nhạc", 73 | "slug" => "am-nhac", 74 | ], 75 | [ 76 | "name" => "Thần Thoại", 77 | "slug" => "than-thoai", 78 | ], 79 | [ 80 | "name" => "Tài Liệu", 81 | "slug" => "tai-lieu", 82 | ], 83 | [ 84 | "name" => "Gia Đình", 85 | "slug" => "gia-dinh", 86 | ], 87 | [ 88 | "name" => "Chính kịch", 89 | "slug" => "chinh-kich", 90 | ], 91 | [ 92 | "name" => "Bí ẩn", 93 | "slug" => "bi-an", 94 | ], 95 | [ 96 | "name" => "Học Đường", 97 | "slug" => "hoc-duong", 98 | ], 99 | [ 100 | "name" => "Kinh Điển", 101 | "slug" => "kinh-dien", 102 | ], 103 | [ 104 | "name" => "Phim 18+", 105 | "slug" => "phim-18", 106 | ], 107 | ]; 108 | 109 | foreach ($categories as $index => $category) { 110 | $result = Category::updateOrCreate($category); 111 | 112 | if (!$result) { 113 | $this->command->info("Insert failed at record $index."); 114 | 115 | return; 116 | } 117 | } 118 | 119 | $this->command->info('Inserted ' . count($categories) . ' categories.'); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /database/seeders/MenusTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'Trang chủ', 'link' => '/', 'type' => 'internal_link']); 24 | $categoryGroup = Menu::firstOrCreate(['name' => 'Thể loại', 'link' => '#', 'type' => 'internal_link']); 25 | $categories = Category::all(); 26 | foreach ($categories as $category) { 27 | Menu::updateOrCreate([ 28 | 'name' => $category->name, 29 | ], [ 30 | 'link' => $category->getUrl(false), 31 | 'type' => 'internal_link', 32 | 'parent_id' => $categoryGroup->id 33 | ]); 34 | } 35 | 36 | $regionGroup = Menu::firstOrCreate(['name' => 'Quốc gia', 'link' => '#', 'type' => 'internal_link']); 37 | $regions = Region::all(); 38 | foreach ($regions as $region) { 39 | Menu::updateOrCreate([ 40 | 'name' => $region->name, 41 | ], [ 42 | 'link' => $region->getUrl(false), 43 | 'type' => 'internal_link', 44 | 'parent_id' => $regionGroup->id 45 | ]); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /database/seeders/PermissionsSeeder.php: -------------------------------------------------------------------------------- 1 | "Admin", 'guard_name' => 'backpack']); 83 | foreach ($permissions as $index => $permission) { 84 | $result = Permission::firstOrCreate([ 85 | 'name' => $permission, 86 | 'guard_name' => 'backpack' 87 | ]); 88 | 89 | $admin->givePermissionTo($permission); 90 | 91 | if (!$result) { 92 | $this->command->info("Insert failed at record $index."); 93 | 94 | return; 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /database/seeders/RegionsTableSeeder.php: -------------------------------------------------------------------------------- 1 | "Trung Quốc", 22 | "slug" => "trung-quoc", 23 | ], 24 | [ 25 | "name" => "Hàn Quốc", 26 | "slug" => "han-quoc", 27 | ], 28 | [ 29 | "name" => "Nhật Bản", 30 | "slug" => "nhat-ban", 31 | ], 32 | [ 33 | "name" => "Thái Lan", 34 | "slug" => "thai-lan", 35 | ], 36 | [ 37 | "name" => "Âu Mỹ", 38 | "slug" => "au-my", 39 | ], 40 | [ 41 | "name" => "Đài Loan", 42 | "slug" => "dai-loan", 43 | ], 44 | [ 45 | "name" => "Hồng Kông", 46 | "slug" => "hong-kong", 47 | ], 48 | [ 49 | "name" => "Ấn Độ", 50 | "slug" => "an-do", 51 | ], 52 | [ 53 | "name" => "Anh", 54 | "slug" => "anh", 55 | ], 56 | [ 57 | "name" => "Pháp", 58 | "slug" => "phap", 59 | ], 60 | [ 61 | "name" => "Canada", 62 | "slug" => "canada", 63 | ], 64 | [ 65 | "name" => "Quốc Gia Khác", 66 | "slug" => "quoc-gia-khac", 67 | ], 68 | [ 69 | "name" => "Đức", 70 | "slug" => "duc", 71 | ], 72 | [ 73 | "name" => "Tây Ban Nha", 74 | "slug" => "tay-ban-nha", 75 | ], 76 | [ 77 | "name" => "Thổ Nhĩ Kỳ", 78 | "slug" => "tho-nhi-ky", 79 | ], 80 | [ 81 | "name" => "Hà Lan", 82 | "slug" => "ha-lan", 83 | ], 84 | [ 85 | "name" => "Indonesia", 86 | "slug" => "indonesia", 87 | ], 88 | [ 89 | "name" => "Nga", 90 | "slug" => "nga", 91 | ], 92 | [ 93 | "name" => "Mexico", 94 | "slug" => "mexico", 95 | ], 96 | [ 97 | "name" => "Ba lan", 98 | "slug" => "ba-lan", 99 | ], 100 | [ 101 | "name" => "Úc", 102 | "slug" => "uc", 103 | ], 104 | [ 105 | "name" => "Thụy Điển", 106 | "slug" => "thuy-dien", 107 | ], 108 | [ 109 | "name" => "Malaysia", 110 | "slug" => "malaysia", 111 | ], 112 | [ 113 | "name" => "Brazil", 114 | "slug" => "brazil", 115 | ], 116 | [ 117 | "name" => "Philippines", 118 | "slug" => "philippines", 119 | ], 120 | [ 121 | "name" => "Bồ Đào Nha", 122 | "slug" => "bo-dao-nha", 123 | ], 124 | [ 125 | "name" => "Ý", 126 | "slug" => "y", 127 | ], 128 | [ 129 | "name" => "Đan Mạch", 130 | "slug" => "dan-mach", 131 | ], 132 | [ 133 | "name" => "UAE", 134 | "slug" => "uae", 135 | ], 136 | [ 137 | "name" => "Na Uy", 138 | "slug" => "na-uy", 139 | ], 140 | [ 141 | "name" => "Thụy Sĩ", 142 | "slug" => "thuy-si", 143 | ], 144 | [ 145 | "name" => "Châu Phi", 146 | "slug" => "chau-phi", 147 | ], 148 | [ 149 | "name" => "Nam Phi", 150 | "slug" => "nam-phi", 151 | ], 152 | [ 153 | "name" => "Ukraina", 154 | "slug" => "ukraina", 155 | ], 156 | [ 157 | "name" => "Ả Rập Xê Út", 158 | "slug" => "a-rap-xe-ut", 159 | ], 160 | ]; 161 | 162 | foreach ($regions as $index => $region) { 163 | $result = Region::updateOrCreate($region); 164 | 165 | if (!$result) { 166 | $this->command->info("Insert failed at record $index."); 167 | 168 | return; 169 | } 170 | } 171 | 172 | $this->command->info('Inserted ' . count($regions) . ' regions.'); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /draft.yml: -------------------------------------------------------------------------------- 1 | php artisan make:migration:schema create_categories_table --schema="name:string:unique,slug:string:unique,seo_title:string,seo_des:string,seo_key:string" 2 | php artisan make:migration:schema create_countries_table --schema="name:string:unique,slug:string:unique,seo_title:string,seo_des:string,seo_key:string" 3 | php artisan make:migration:schema create_movies_table --schema="name:string:unique,slug:string:unique,seo_title:string,seo_des:string,seo_key:string" 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "mix", 6 | "watch": "mix watch", 7 | "watch-poll": "mix watch -- --watch-options-poll=1000", 8 | "hot": "mix watch --hot", 9 | "prod": "npm run production", 10 | "production": "mix --production" 11 | }, 12 | "devDependencies": { 13 | "axios": "^0.21", 14 | "laravel-mix": "^6.0.6", 15 | "lodash": "^4.17.19", 16 | "postcss": "^8.1.14" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /resources/views/core/base/columns/relationship.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $column['value'] = $column['value'] ?? data_get($entry, $column['name']); 3 | $column['escaped'] = $column['escaped'] ?? true; 4 | $column['text'] = $column['default'] ?? '-'; 5 | 6 | if ($column['value'] instanceof \Closure) { 7 | $column['value'] = $column['value']($entry); 8 | } 9 | 10 | if (!empty($column['value'])) { 11 | $column['text'] = isset($column['value']->name) ? $column['value']->name : $column['value']->pluck('name')->implode(', '); 12 | } 13 | @endphp 14 | 15 | 16 | @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start') 17 | @if ($column['escaped']) 18 | {{ $column['text'] }} 19 | @else 20 | {!! $column['text'] !!} 21 | @endif 22 | @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end') 23 | 24 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/checklist.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @php 3 | $key_attribute = (new $field['model']())->getKeyName(); 4 | $field['attribute'] = $field['attribute'] ?? (new $field['model']())->identifiableAttribute(); 5 | $field['number_of_columns'] = $field['number_of_columns'] ?? 3; 6 | 7 | // calculate the checklist options 8 | if (!isset($field['options'])) { 9 | $field['options'] = $field['model'] 10 | ::all() 11 | ->pluck($field['attribute'], $key_attribute) 12 | ->toArray(); 13 | } else { 14 | $field['options'] = call_user_func($field['options'], $field['model']::query()); 15 | } 16 | 17 | // calculate the value of the hidden input 18 | $field['value'] = old_empty_or_null($field['name'], []) ?? ($field['value'] ?? ($field['default'] ?? [])); 19 | if (!empty($field['value'])) { 20 | if (is_a($field['value'], \Illuminate\Support\Collection::class)) { 21 | $field['value'] = $field['value']->pluck($key_attribute)->toArray(); 22 | } elseif (is_string($field['value'])) { 23 | $field['value'] = json_decode($field['value']); 24 | } 25 | } 26 | 27 | // define the init-function on the wrapper 28 | $field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitChecklist'; 29 | @endphp 30 | 31 | @include('crud::fields.inc.wrapper_start') 32 | 33 | @include('crud::fields.inc.translatable_icon') 34 | 35 | 36 | 37 |
38 | @foreach ($field['options'] as $key => $option) 39 |
40 |
41 | 44 |
45 |
46 | @endforeach 47 |
48 | 49 | {{-- HINT --}} 50 | @if (isset($field['hint'])) 51 |

{!! $field['hint'] !!}

52 | @endif 53 | @include('crud::fields.inc.wrapper_end') 54 | 55 | 56 | {{-- ########################################## --}} 57 | {{-- Extra CSS and JS for this particular field --}} 58 | {{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}} 59 | {{-- FIELD JS - will be loaded in the after_scripts section --}} 60 | @push('crud_fields_scripts') 61 | @loadOnce('bpFieldInitChecklist') 62 | 106 | @endLoadOnce 107 | @endpush 108 | {{-- End of Extra CSS and JS --}} 109 | {{-- ########################################## --}} 110 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/ckfinder.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @include('crud::fields.inc.wrapper_start') 3 | @php 4 | $field['has_preview'] = isset($field['has_preview']) ? $field['has_preview'] : false; 5 | $field['preview']['width'] = isset($field['preview']['width']) ? $field['preview']['width'] : '90%'; 6 | $field['preview']['height'] = isset($field['preview']['height']) ? $field['preview']['height'] : '90%'; 7 | @endphp 8 | 9 |
10 | 13 | 14 | 16 | 17 |
18 | @if ($field['has_preview'] && old($field['name'], isset($entry) ? $entry->{$field['name']} : '')) 19 | 22 | @endif 23 | 24 | 25 | 26 | {{-- HINT --}} 27 | @if (isset($field['hint'])) 28 |

{!! $field['hint'] !!}

29 | @endif 30 | @include('crud::fields.inc.wrapper_end') 31 | 32 | @if ($crud->fieldTypeNotLoaded($field)) 33 | @php 34 | $crud->markFieldTypeAsLoaded($field); 35 | @endphp 36 | 37 | {{-- FIELD EXTRA CSS --}} 38 | {{-- push things in the after_styles section --}} 39 | @push('crud_fields_styles') 40 | 41 | @endpush 42 | 43 | {{-- FIELD EXTRA JS --}} 44 | {{-- push things in the after_scripts section --}} 45 | @push('crud_fields_scripts') 46 | @include('ckfinder::setup') 47 | 75 | @endpush 76 | @endif 77 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/fields_option.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $value = isset($field) ? old_empty_or_null($field['name'], '') ?? ($field['value'] ?? null) : null; 3 | @endphp 4 | 5 | @php 6 | $progress = [ 7 | 'episodes' => 'Tập mới', 8 | 'status' => 'Trạng thái phim', 9 | 'episode_time' => 'Thời lượng tập phim', 10 | 'episode_current' => 'Số tập phim hiện tại', 11 | 'episode_total' => 'Tổng số tập phim', 12 | ]; 13 | 14 | $info = [ 15 | 'name' => 'Tên phim', 16 | 'origin_name' => 'Tên gốc phim', 17 | 'content' => 'Mô tả nội dung phim', 18 | 'thumb_url' => 'Ảnh Thumb', 19 | 'poster_url' => 'Ảnh Poster', 20 | 'trailer_url' => 'Trailer URL', 21 | 'quality' => 'Chất lượng phim', 22 | 'language' => 'Ngôn ngữ', 23 | 'notify' => 'Nội dung thông báo', 24 | 'showtimes' => 'Giờ chiếu phim', 25 | 'publish_year' => 'Năm xuất bản', 26 | 'is_shown_in_theater' => 'Đánh dấu phim chiếu rạp', 27 | 'is_copyright' => 'Đánh dấu có bản quyền', 28 | ]; 29 | 30 | $relations = [ 31 | 'type' => 'Định dạng phim', 32 | 'actors' => 'Diễn viên', 33 | 'directors' => 'Đạo diễn', 34 | 'categories' => 'Thể loại', 35 | 'regions' => 'Khu vực', 36 | 'tags' => 'Từ khóa', 37 | 'studios' => 'Studio', 38 | ]; 39 | @endphp 40 | 41 |
42 |
43 |
44 | 45 | 46 |
47 | @foreach ($progress as $key => $option) 48 |
49 | 51 | 52 |
53 | @endforeach 54 |
55 |
56 |
57 | 58 | 59 |
60 | @foreach ($info as $key => $option) 61 |
62 | 64 | 65 |
66 | @endforeach 67 |
68 |
69 |
70 | 71 | 72 |
73 | @foreach ($relations as $key => $option) 74 |
75 | 77 | 78 |
79 | @endforeach 80 |
81 | 82 |
83 | 84 | {{-- FIELD JS - will be loaded in the after_scripts section --}} 85 | @push('crud_fields_scripts') 86 | 91 | @endpush 92 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/select2_from_array.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @include('crud::fields.inc.wrapper_start') 3 | @php 4 | $field['allows_multiple'] = $field['allows_multiple'] ?? false; 5 | $field['options'] = $field['options'] ?? []; 6 | $field['value'] = $field['value'] ?? []; 7 | 8 | @endphp 9 | 10 | 17 | 18 | {{-- HINT --}} 19 | @if (isset($field['hint'])) 20 |

{!! $field['hint'] !!}

21 | @endif 22 | @include('crud::fields.inc.wrapper_end') 23 | 24 | @if ($crud->fieldTypeNotLoaded($field)) 25 | @php 26 | $crud->markFieldTypeAsLoaded($field); 27 | @endphp 28 | 29 | {{-- FIELD EXTRA CSS --}} 30 | {{-- push things in the after_styles section --}} 31 | @push('crud_fields_styles') 32 | 33 | @endpush 34 | 35 | {{-- FIELD EXTRA JS --}} 36 | {{-- push things in the after_scripts section --}} 37 | @push('crud_fields_scripts') 38 | 43 | @endpush 44 | @endif 45 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/select2_relationship_tags.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @include('crud::fields.inc.wrapper_start') 3 | @php 4 | $key_attribute = (new $field['model']())->getKeyName(); 5 | $field['attribute'] = $field['attribute'] ?? (new $field['model']())->identifiableAttribute(); 6 | 7 | $selected = $field['model'] 8 | ::whereIn('id', old($field['name'], isset($field['value']) ? $field['value']->pluck('id')->toArray() : [])) 9 | ->pluck($field['attribute'], $key_attribute) 10 | ->toArray(); 11 | @endphp 12 | 13 | 19 | 20 | {{-- HINT --}} 21 | @if (isset($field['hint'])) 22 |

{!! $field['hint'] !!}

23 | @endif 24 | @include('crud::fields.inc.wrapper_end') 25 | 26 | @if ($crud->fieldTypeNotLoaded($field)) 27 | @php 28 | $crud->markFieldTypeAsLoaded($field); 29 | @endphp 30 | 31 | {{-- FIELD EXTRA CSS --}} 32 | {{-- push things in the after_styles section --}} 33 | @push('crud_fields_styles') 34 | 35 | @endpush 36 | 37 | {{-- FIELD EXTRA JS --}} 38 | {{-- push things in the after_scripts section --}} 39 | @push('crud_fields_scripts') 40 | 47 | @endpush 48 | @endif 49 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/select2_tags.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @include('crud::fields.inc.wrapper_start') 3 | 4 | @php 5 | $selected = $field['value'] ?? []; 6 | @endphp 7 | 8 | 9 | 15 | 16 | {{-- HINT --}} 17 | @if (isset($field['hint'])) 18 |

{!! $field['hint'] !!}

19 | @endif 20 | @include('crud::fields.inc.wrapper_end') 21 | 22 | @if ($crud->fieldTypeNotLoaded($field)) 23 | @php 24 | $crud->markFieldTypeAsLoaded($field); 25 | @endphp 26 | 27 | {{-- FIELD EXTRA CSS --}} 28 | {{-- push things in the after_styles section --}} 29 | @push('crud_fields_styles') 30 | 31 | @endpush 32 | 33 | {{-- FIELD EXTRA JS --}} 34 | {{-- push things in the after_scripts section --}} 35 | @push('crud_fields_scripts') 36 | 43 | @endpush 44 | @endif 45 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/select_from_table.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $field['allows_null'] = $field['allows_null'] ?? $crud->model::isColumnNullable($field['name']); 3 | $field['value'] = old_empty_or_null($field['name'], '') ?? ($field['value'] ?? ($field['default'] ?? '')); 4 | $field['multiple'] = $field['allows_multiple'] ?? ($field['multiple'] ?? false); 5 | $field['options']['display_by'] = isset($field['options']['display_by']) ? $field['options']['display_by'] : 'name'; 6 | $field['options']['value_by'] = isset($field['options']['value_by']) ? $field['options']['value_by'] : 'id'; 7 | $options = \DB::table($field['options']['table']) 8 | ->pluck($field['options']['display_by'], $field['options']['value_by']) 9 | ->toArray(); 10 | @endphp 11 | 12 | @include('crud::fields.inc.wrapper_start') 13 | 14 | @include('crud::fields.inc.translatable_icon') 15 | @if ($field['multiple']) 16 | 17 | @endif 18 | 19 | 35 | 36 | {{-- HINT --}} 37 | @if (isset($field['hint'])) 38 |

{!! $field['hint'] !!}

39 | @endif 40 | @include('crud::fields.inc.wrapper_end') 41 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/select_theme.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $field['value'] = old_empty_or_null($field['name'], '') ?? ($field['value'] ?? ($field['default'] ?? '')); 3 | $field['multiple'] = $field['allows_multiple'] ?? ($field['multiple'] ?? false); 4 | $options = config('themes', []); 5 | @endphp 6 | 7 | @include('crud::fields.inc.wrapper_start') 8 | 9 | @include('crud::fields.inc.translatable_icon') 10 | @if ($field['multiple']) 11 | 12 | @endif 13 | 14 | 25 | 26 | {{-- HINT --}} 27 | @if (isset($field['hint'])) 28 |

{!! $field['hint'] !!}

29 | @endif 30 | @include('crud::fields.inc.wrapper_end') 31 | -------------------------------------------------------------------------------- /resources/views/core/base/fields/update_fields_option.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $value = isset($field) ? old_empty_or_null($field['name'], '') ?? ($field['value'] ?? null) : null; 3 | @endphp 4 | 5 | @php 6 | $progress = [ 7 | 'episodes' => 'Tập mới', 8 | 'status' => 'Trạng thái phim', 9 | 'episode_time' => 'Thời lượng tập phim', 10 | 'episode_current' => 'Số tập phim hiện tại', 11 | 'episode_total' => 'Tổng số tập phim', 12 | ]; 13 | 14 | $info = [ 15 | 'name' => 'Tên phim', 16 | 'origin_name' => 'Tên gốc phim', 17 | 'content' => 'Mô tả nội dung phim', 18 | 'thumb_url' => 'Ảnh Thumb', 19 | 'poster_url' => 'Ảnh Poster', 20 | 'trailer_url' => 'Trailer URL', 21 | 'quality' => 'Chất lượng phim', 22 | 'language' => 'Ngôn ngữ', 23 | 'notify' => 'Nội dung thông báo', 24 | 'showtimes' => 'Giờ chiếu phim', 25 | 'publish_year' => 'Năm xuất bản', 26 | 'is_shown_in_theater' => 'Đánh dấu phim chiếu rạp', 27 | 'is_copyright' => 'Đánh dấu có bản quyền', 28 | ]; 29 | 30 | $relations = [ 31 | 'type' => 'Định dạng phim', 32 | 'actors' => 'Diễn viên', 33 | 'directors' => 'Đạo diễn', 34 | 'categories' => 'Thể loại', 35 | 'regions' => 'Khu vực', 36 | 'tags' => 'Từ khóa', 37 | 'studios' => 'Studio', 38 | ]; 39 | @endphp 40 | 41 |
42 |
43 |
44 | 45 | 46 |
47 | @foreach ($progress as $key => $option) 48 |
49 | 51 | 52 |
53 | @endforeach 54 |
55 |
56 |
57 | 58 | 59 |
60 | @foreach ($info as $key => $option) 61 |
62 | 64 | 65 |
66 | @endforeach 67 |
68 |
69 |
70 | 71 | 72 |
73 | @foreach ($relations as $key => $option) 74 |
75 | 77 | 78 |
79 | @endforeach 80 |
81 | 82 |
83 | 84 | {{-- FIELD JS - will be loaded in the after_scripts section --}} 85 | @push('after_scripts') 86 | 91 | @endpush 92 | -------------------------------------------------------------------------------- /resources/views/core/base/inc/main_header.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 | {!! setting('site_logo') ?? config('backpack.base.project_logo') !!} 8 |
v{{ config('ophim.version') }}
9 |
10 | 13 | 14 | @include(backpack_view('inc.menu')) 15 |
16 | -------------------------------------------------------------------------------- /resources/views/core/base/inc/topbar_right_content.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /resources/views/core/crud/buttons/bulk_delete.blade.php: -------------------------------------------------------------------------------- 1 | @if ($crud->hasAccess('bulkDelete') && $crud->get('list.bulkActions')) 2 | {{ trans('backpack::crud.delete') }} 3 | @endif 4 | 5 | @push('after_scripts') 6 | 104 | @endpush 105 | -------------------------------------------------------------------------------- /resources/views/core/crud/filters/select2.blade.php: -------------------------------------------------------------------------------- 1 | {{-- Select2 Backpack CRUD filter --}} 2 | 35 | 36 | {{-- ########################################### --}} 37 | {{-- Extra CSS and JS for this particular filter --}} 38 | 39 | {{-- FILTERS EXTRA CSS --}} 40 | {{-- push things in the after_styles section --}} 41 | 42 | @push('crud_list_styles') 43 | {{-- include select2 css --}} 44 | 45 | 46 | 69 | @endpush 70 | 71 | 72 | {{-- FILTERS EXTRA JS --}} 73 | {{-- push things in the after_scripts section --}} 74 | 75 | @push('crud_list_scripts') 76 | {{-- include select2 js --}} 77 | 78 | @if (app()->getLocale() !== 'en') 79 | 80 | @endif 81 | 82 | 138 | @endpush 139 | {{-- End of Extra CSS and JS --}} 140 | {{-- ########################################## --}} 141 | -------------------------------------------------------------------------------- /resources/views/core/crud/filters/simple.blade.php: -------------------------------------------------------------------------------- 1 | {{-- Simple Backpack CRUD filter --}} 2 | 10 | 11 | 12 | {{-- ########################################### --}} 13 | {{-- Extra CSS and JS for this particular filter --}} 14 | 15 | {{-- FILTERS EXTRA CSS --}} 16 | {{-- push things in the after_styles section --}} 17 | 18 | {{-- @push('crud_list_styles') 19 | no css 20 | @endpush --}} 21 | 22 | 23 | {{-- FILTERS EXTRA JS --}} 24 | {{-- push things in the after_scripts section --}} 25 | 26 | @push('crud_list_scripts') 27 | 70 | @endpush 71 | {{-- End of Extra CSS and JS --}} 72 | {{-- ########################################## --}} 73 | -------------------------------------------------------------------------------- /resources/views/core/movies/columns/column_movie_info.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $name = data_get($entry, $column['name']); 3 | $origin_name = data_get($entry, $column['origin_name']); 4 | $publish_year = data_get($entry, $column['publish_year']); 5 | $episode_current = data_get($entry, $column['episode_current']); 6 | $status = data_get($entry, $column['status']); 7 | $movie_type = data_get($entry, $column['movie_type']); 8 | $config_show_type = [ 9 | 'single' => [ 10 | 'class' => 'bg-secondary', 11 | 'label' => 'Phim lẻ', 12 | ], 13 | 'series' => [ 14 | 'class' => 'bg-primary', 15 | 'label' => 'Phim bộ', 16 | ], 17 | ]; 18 | $config_show_status = [ 19 | 'trailer' => [ 20 | 'class' => 'bg-warning', 21 | 'label' => 'Trailer', 22 | ], 23 | 'ongoing' => [ 24 | 'class' => 'bg-info', 25 | 'label' => 'Đang chiếu', 26 | ], 27 | 'completed' => [ 28 | 'class' => 'bg-success', 29 | 'label' => 'Hoàn thành', 30 | ], 31 | ]; 32 | @endphp 33 |
34 | @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start') 35 |
{{ $name }} [{{ $publish_year }}]
36 |
({{ $origin_name }}) [{{ $episode_current }}]
37 |
{{ $config_show_type[$movie_type]['label'] }}
38 |
{{ $config_show_status[$status]['label'] }}
39 | @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end') 40 |
41 | -------------------------------------------------------------------------------- /resources/views/core/movies/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends(backpack_view('blank')) 2 | 3 | @php 4 | $defaultBreadcrumbs = [ 5 | trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'), 6 | $crud->entity_name_plural => url($crud->route), 7 | trans('backpack::crud.add') => false, 8 | ]; 9 | 10 | // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs 11 | $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs; 12 | @endphp 13 | 14 | @section('header') 15 |
16 |

17 | {!! $crud->getHeading() ?? $crud->entity_name_plural !!} 18 | {!! $crud->getSubheading() ?? trans('backpack::crud.add') . ' ' . $crud->entity_name !!}. 19 | 20 | @if ($crud->hasAccess('list')) 21 | 23 | {{ trans('backpack::crud.back_to_all') }} 24 | {{ $crud->entity_name_plural }} 25 | @endif 26 |

27 |
28 | @endsection 29 | 30 | @section('content') 31 |
32 |
33 | 34 | 35 | @include('crud::inc.grouped_errors') 36 | 37 |
hasUploadFields('create')) enctype="multipart/form-data" @endif> 39 | {!! csrf_field() !!} 40 | 41 | @if (view()->exists('vendor.backpack.crud.form_content')) 42 | @include('vendor.backpack.crud.form_content', [ 43 | 'fields' => $crud->fields(), 44 | 'action' => 'create', 45 | ]) 46 | @else 47 | @include('crud::form_content', ['fields' => $crud->fields(), 'action' => 'create']) 48 | @endif 49 | 50 |
{{ json_encode(Assets::loaded()) }}
51 | 52 | @include('crud::inc.form_save_buttons') 53 |
54 |
55 |
56 | @endsection 57 | -------------------------------------------------------------------------------- /resources/views/core/movies/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends(backpack_view('blank')) 2 | 3 | @php 4 | $defaultBreadcrumbs = [ 5 | trans('backpack::crud.admin') => backpack_url('dashboard'), 6 | $crud->entity_name_plural => url($crud->route), 7 | trans('backpack::crud.edit') => false, 8 | ]; 9 | 10 | // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs 11 | $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs; 12 | @endphp 13 | 14 | @section('header') 15 |
16 |

17 | {!! $crud->getHeading() ?? $crud->entity_name_plural !!} 18 | {!! $crud->getSubheading() ?? trans('backpack::crud.edit').' '.$crud->entity_name !!}. 19 | 20 | @if ($crud->hasAccess('list')) 21 | {{ trans('backpack::crud.back_to_all') }} {{ $crud->entity_name_plural }} 22 | @endif 23 |

24 |
25 | @endsection 26 | 27 | @section('content') 28 |
29 |
30 | 31 | 32 | @include('crud::inc.grouped_errors') 33 | 34 |
hasUploadFields('update', $entry->getKey())) 37 | enctype="multipart/form-data" 38 | @endif 39 | > 40 | {!! csrf_field() !!} 41 | {!! method_field('PUT') !!} 42 | 43 | @if ($crud->model->translationEnabled()) 44 |
45 | 46 |
47 | 50 | 55 |
56 |
57 | @endif 58 | 59 | @if(view()->exists('vendor.backpack.crud.form_content')) 60 | @include('vendor.backpack.crud.form_content', ['fields' => $crud->fields(), 'action' => 'edit']) 61 | @else 62 | @include('crud::form_content', ['fields' => $crud->fields(), 'action' => 'edit']) 63 | @endif 64 | 65 |
{{ json_encode(Assets::loaded()) }}
66 | @include('crud::inc.form_save_buttons') 67 |
68 |
69 |
70 | @endsection 71 | 72 | -------------------------------------------------------------------------------- /resources/views/themes/layout.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {!! setting('site_meta_head_tags', '') !!} 6 | 7 | 8 | 9 | 10 | {!! SEO::generate() !!} 11 | @stack('header') 12 | {!! get_theme_option('additional_css') !!} 13 | {!! get_theme_option('additional_header_js') !!} 14 | 15 | 16 | 17 | @yield('body') 18 | {!! get_theme_option('additional_body_js') !!} 19 | 20 | @yield('footer') 21 | @stack('scripts') 22 | {!! get_theme_option('additional_footer_js') !!} 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /routes/admin.php: -------------------------------------------------------------------------------- 1 | config('backpack.base.route_prefix', 'admin'), 14 | 'middleware' => array_merge( 15 | (array) config('backpack.base.web_middleware', 'web'), 16 | (array) config('backpack.base.middleware_key', 'admin') 17 | ), 18 | 'namespace' => 'Ophim\Core\Controllers\Admin', 19 | ], function () { 20 | if (config('backpack.base.setup_dashboard_routes')) { 21 | Route::get('dashboard', 'AdminController@dashboard')->name('backpack.dashboard'); 22 | Route::get('/', 'AdminController@redirect')->name('backpack'); 23 | } 24 | 25 | Route::crud('catalog', 'CatalogCrudController'); 26 | Route::crud('category', 'CategoryCrudController'); 27 | Route::crud('region', 'RegionCrudController'); 28 | Route::crud('movie', 'MovieCrudController'); 29 | Route::crud('actor', 'ActorCrudController'); 30 | Route::crud('director', 'DirectorCrudController'); 31 | Route::crud('studio', 'StudioCrudController'); 32 | Route::crud('tag', 'TagCrudController'); 33 | Route::crud('menu', 'MenuCrudController'); 34 | Route::crud('episode', 'EpisodeCrudController'); 35 | Route::crud('theme', 'ThemeManagementController'); 36 | Route::crud('sitemap', 'SiteMapController'); 37 | Route::get('quick-action/delete-cache', 'QuickActionController@delete_cache'); 38 | }); 39 | 40 | Route::group([ 41 | 'prefix' => config('backpack.base.route_prefix', 'admin'), 42 | 'middleware' => array_merge( 43 | [ 44 | \Ophim\Core\Middleware\EncryptCookies::class, 45 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 46 | \Illuminate\Session\Middleware\StartSession::class, 47 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 48 | \Illuminate\Routing\Middleware\SubstituteBindings::class 49 | ], 50 | (array) config('backpack.base.middleware_key', 'admin') 51 | ), 52 | ], function () { 53 | Route::prefix('/ckfinder')->group(function () { 54 | Route::any('/connector', [CKFinderController::class, 'requestAction'])->name('ckfinder_connector'); 55 | Route::any('/browser', [CKFinderController::class, 'browserAction'])->name('ckfinder_browser'); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/Console/ChangeDomainEpisodeCommand.php: -------------------------------------------------------------------------------- 1 | ['vie.opstream1.com', 'vie.haiphim.com'], 47 | 'vip.opstream15.com' => ['hd.1080phim.com', 'hd1080.opstream2.com'], 48 | 'vip.opstream14.com' => ['kd.hd-bophim.com', 'kd.opstream3.com'], 49 | 'vip.opstream11.com' => ['1080.hdphimonline.com', '1080.opstream4.com'], 50 | 'vip.opstream16.com' => ['hd.hdbophim.com', 'hdbo.opstream5.com'], 51 | 'vip.opstream12.com' => ['aa.nguonphimmoi.com', 'aa.opstream6.com'], 52 | 'vip.opstream13.com' => ['vie2.opstream7.com'], 53 | 'vip.opstream17.com' => ['vip.opstream8.com'], 54 | ); 55 | foreach ($domains as $newDomain => $arrOldDomain) { 56 | foreach ($arrOldDomain as $oldDomain) { 57 | $this->info("Replace: $oldDomain => $newDomain"); 58 | Episode::where('link', 'LIKE', '%' . $oldDomain . '%')->update(['link' => DB::raw("REPLACE(link, '$oldDomain', '$newDomain')")]); 59 | } 60 | } 61 | 62 | $this->info("Replace Done!"); 63 | return 0; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Console/CreateUser.php: -------------------------------------------------------------------------------- 1 | info('Creating a new user'); 36 | 37 | if (!$name = $this->option('name')) { 38 | $name = $this->ask('Name'); 39 | } 40 | 41 | if (!$email = $this->option('email')) { 42 | $email = $this->ask('Email'); 43 | } 44 | 45 | if (!$password = $this->option('password')) { 46 | $password = $this->secret('Password'); 47 | } 48 | 49 | if (!$this->confirm('Is administrator? [y|N]', $isAdmin = false)) { 50 | $isAdmin = false; 51 | } else { 52 | $isAdmin = true; 53 | } 54 | 55 | if ($this->option('encrypt')) { 56 | $password = bcrypt($password); 57 | } 58 | 59 | $auth = config('backpack.base.user_model_fqn', 'App\User'); 60 | $user = new $auth(); 61 | $user->name = $name; 62 | $user->email = $email; 63 | $user->password = $password; 64 | 65 | if ($user->save()) { 66 | $this->info('Successfully created new user'); 67 | if ($isAdmin) { 68 | $user->roles()->attach(Role::firstOrCreate(['name' => 'Admin', 'guard_name' => 'backpack'])); 69 | } 70 | } else { 71 | $this->error('Something went wrong trying to save your user'); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Console/GenerateMenuCommand.php: -------------------------------------------------------------------------------- 1 | call('db:seed', [ 45 | 'class' => MenusTableSeeder::class, 46 | ]); 47 | $this->info('Menu is generated.'); 48 | 49 | return 0; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Console/InstallCommand.php: -------------------------------------------------------------------------------- 1 | progressBar = $this->output->createProgressBar(18); 53 | $this->progressBar->minSecondsBetweenRedraws(0); 54 | $this->progressBar->maxSecondsBetweenRedraws(120); 55 | $this->progressBar->setRedrawFrequency(1); 56 | 57 | $this->progressBar->start(); 58 | 59 | $this->call('vendor:publish', [ 60 | '--provider' => 'Backpack\CRUD\BackpackServiceProvider', 61 | '--tag' => 'config', 62 | ]); 63 | $this->progressBar->advance(); 64 | $this->newLine(1); 65 | 66 | $this->call('vendor:publish', [ 67 | '--provider' => 'Backpack\CRUD\BackpackServiceProvider', 68 | '--tag' => 'config', 69 | ]); 70 | $this->progressBar->advance(); 71 | $this->newLine(1); 72 | 73 | $this->call('vendor:publish', [ 74 | '--provider' => 'Backpack\CRUD\BackpackServiceProvider', 75 | '--tag' => 'public', 76 | ]); 77 | $this->progressBar->advance(); 78 | $this->newLine(1); 79 | 80 | $this->call('vendor:publish', [ 81 | '--provider' => 'Backpack\CRUD\BackpackServiceProvider', 82 | '--tag' => 'gravatar', 83 | ]); 84 | $this->progressBar->advance(); 85 | $this->newLine(1); 86 | 87 | 88 | $this->call('migrate', $this->option('no-interaction') ? ['--no-interaction' => true] : []); 89 | $this->progressBar->advance(); 90 | $this->newLine(1); 91 | 92 | $this->call('backpack:publish-middleware'); 93 | $this->progressBar->advance(); 94 | $this->newLine(1); 95 | 96 | $this->call('vendor:publish', [ 97 | '--tag' => 'cms_menu_content', 98 | '--force' => true 99 | ]); 100 | $this->progressBar->advance(); 101 | $this->newLine(1); 102 | 103 | $this->call('vendor:publish', [ 104 | '--tag' => 'players', 105 | ]); 106 | $this->progressBar->advance(); 107 | $this->newLine(1); 108 | 109 | $this->installCKfinder(); 110 | $this->progressBar->advance(); 111 | $this->newLine(1); 112 | 113 | $this->call('db:seed', [ 114 | 'class' => SettingsTableSeeder::class, 115 | ]); 116 | $this->progressBar->advance(); 117 | $this->newLine(1); 118 | 119 | $this->call('db:seed', [ 120 | 'class' => CatalogsTableSeeder::class, 121 | ]); 122 | $this->progressBar->advance(); 123 | $this->newLine(1); 124 | 125 | $this->call('db:seed', [ 126 | 'class' => MenusTableSeeder::class, 127 | ]); 128 | $this->progressBar->advance(); 129 | $this->newLine(1); 130 | 131 | $this->call('db:seed', [ 132 | 'class' => PermissionsSeeder::class, 133 | ]); 134 | $this->progressBar->advance(); 135 | $this->newLine(1); 136 | 137 | $this->progressBar->finish(); 138 | $this->newLine(1); 139 | $this->info('Ophim installation finished.'); 140 | 141 | return 0; 142 | } 143 | 144 | protected function installCKfinder() 145 | { 146 | $this->call('ckfinder:download'); 147 | $this->call('vendor:publish', [ 148 | '--tag' => 'ckfinder-assets', 149 | ]); 150 | $this->progressBar->advance(); 151 | $this->newLine(1); 152 | 153 | $this->call('vendor:publish', [ 154 | '--tag' => 'ckfinder-config', 155 | ]); 156 | 157 | $this->call('storage:link'); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Contracts/HasUrlInterface.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Actor::class); 44 | 45 | CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); 46 | CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); 47 | CRUD::addColumn(['name' => 'gender', 'label' => 'Giới tính', 'type' => 'text']); 48 | CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']); 49 | } 50 | 51 | /** 52 | * Define what happens when the Create operation is loaded. 53 | * 54 | * @see https://backpackforlaravel.com/docs/crud-operation-create 55 | * @return void 56 | */ 57 | protected function setupCreateOperation() 58 | { 59 | $this->authorize('create', Actor::class); 60 | 61 | CRUD::setValidation(ActorRequest::class); 62 | 63 | CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); 64 | CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); 65 | CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']); 66 | CRUD::addField([ 67 | 'name' => 'gender', 68 | 'label' => "Giới tính", 69 | 'type' => 'select_from_array', 70 | 'options' => ['male' => 'Nam', 'female' => 'Nữ', 'other' => 'Khác'], 71 | 'allows_null' => false, 72 | 'default' => 'one', 73 | ],); 74 | } 75 | 76 | /** 77 | * Define what happens when the Update operation is loaded. 78 | * 79 | * @see https://backpackforlaravel.com/docs/crud-operation-update 80 | * @return void 81 | */ 82 | protected function setupUpdateOperation() 83 | { 84 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 85 | 86 | $this->setupCreateOperation(); 87 | } 88 | 89 | protected function setupDeleteOperation() 90 | { 91 | $this->authorize('delete', $this->crud->model); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Controllers/Admin/AdminController.php: -------------------------------------------------------------------------------- 1 | middleware(backpack_middleware()); 21 | } 22 | 23 | /** 24 | * Show the admin dashboard. 25 | * 26 | * @return \Illuminate\Http\Response 27 | */ 28 | public function dashboard() 29 | { 30 | $this->data['title'] = trans('backpack::base.dashboard'); // set the page title 31 | $this->data['breadcrumbs'] = [ 32 | trans('backpack::crud.admin') => backpack_url('dashboard'), 33 | trans('backpack::base.dashboard') => false, 34 | ]; 35 | $this->data['count_movies'] = Movie::count(); 36 | $this->data['count_episodes'] = Episode::count(); 37 | $this->data['count_episodes_error'] = Episode::where('has_report', true)->count(); 38 | $this->data['count_themes'] = Theme::count(); 39 | $this->data['count_users'] = User::count(); 40 | $this->data['top_view_day'] = Movie::orderBy('view_day', 'desc')->limit(15)->get(); 41 | $this->data['top_view_week'] = Movie::orderBy('view_week', 'desc')->limit(15)->get(); 42 | $this->data['top_view_month'] = Movie::orderBy('view_month', 'desc')->limit(15)->get(); 43 | return view(backpack_view('dashboard'), $this->data); 44 | } 45 | 46 | /** 47 | * Redirect to the dashboard. 48 | * 49 | * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse 50 | */ 51 | public function redirect() 52 | { 53 | // The '/admin' route is not to be used as a page, because it breaks the menu's active state. 54 | return redirect(backpack_url('dashboard')); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Controllers/Admin/CatalogCrudController.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Catalog::class); 44 | 45 | CRUD::addButtonFromModelFunction('line', 'open_view', 'openView', 'beginning'); 46 | 47 | CRUD::column('name')->label('Tên')->type('text'); 48 | CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text'); 49 | CRUD::column('paginate')->label('Item per page')->type('number'); 50 | CRUD::column('value')->label('Value')->type('text'); 51 | CRUD::column('seo_title')->label('SEO Title')->type('text'); 52 | CRUD::column('seo_des')->label('SEO Description')->type('text'); 53 | CRUD::column('seo_key')->label('SEO Keyword')->type('text'); 54 | } 55 | 56 | /** 57 | * Define what happens when the Create operation is loaded. 58 | * 59 | * @see https://backpackforlaravel.com/docs/crud-operation-create 60 | * @return void 61 | */ 62 | protected function setupCreateOperation() 63 | { 64 | $this->authorize('create', Catalog::class); 65 | 66 | CRUD::setValidation(CatalogRequest::class); 67 | 68 | CRUD::field('name')->label('Tên')->type('text'); 69 | CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text'); 70 | CRUD::field('paginate')->label('Paginate')->hint('Item per page')->type('number'); 71 | CRUD::field('value')->label('Value')->hint('relation_tables,relation_field,relation_value|find_by_field_1,find_by_fiel_2,...,find_by_field_n|value_1,value_2,...,value_n|sort_by_field|sort_algo')->type('text'); 72 | CRUD::field('seo_title')->label('SEO Title')->type('text'); 73 | CRUD::field('seo_des')->label('SEO Description')->type('textarea'); 74 | CRUD::field('seo_key')->label('SEO Keyword')->type('text'); 75 | } 76 | 77 | /** 78 | * Define what happens when the Update operation is loaded. 79 | * 80 | * @see https://backpackforlaravel.com/docs/crud-operation-update 81 | * @return void 82 | */ 83 | protected function setupUpdateOperation() 84 | { 85 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 86 | 87 | $this->setupCreateOperation(); 88 | } 89 | 90 | protected function setupDeleteOperation() 91 | { 92 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Controllers/Admin/CategoryCrudController.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Category::class); 44 | 45 | CRUD::column('name')->label('Tên')->type('text'); 46 | CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text'); 47 | CRUD::column('seo_title')->label('SEO Title')->type('text'); 48 | CRUD::column('seo_des')->label('SEO Description')->type('text'); 49 | CRUD::column('seo_key')->label('SEO Keyword')->type('text'); 50 | } 51 | 52 | /** 53 | * Define what happens when the Create operation is loaded. 54 | * 55 | * @see https://backpackforlaravel.com/docs/crud-operation-create 56 | * @return void 57 | */ 58 | protected function setupCreateOperation() 59 | { 60 | $this->authorize('create', Category::class); 61 | 62 | CRUD::setValidation(CategoryRequest::class); 63 | 64 | CRUD::field('name')->label('Tên')->type('text'); 65 | CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text'); 66 | CRUD::field('seo_title')->label('SEO Title')->type('text'); 67 | CRUD::field('seo_des')->label('SEO Description')->type('textarea'); 68 | CRUD::field('seo_key')->label('SEO Keyword')->type('text'); 69 | } 70 | 71 | /** 72 | * Define what happens when the Update operation is loaded. 73 | * 74 | * @see https://backpackforlaravel.com/docs/crud-operation-update 75 | * @return void 76 | */ 77 | protected function setupUpdateOperation() 78 | { 79 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 80 | 81 | 82 | $this->setupCreateOperation(); 83 | } 84 | 85 | protected function setupDeleteOperation() 86 | { 87 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Controllers/Admin/DirectorCrudController.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Director::class); 44 | 45 | /** 46 | * Columns can be defined using the fluent syntax or array syntax: 47 | * - CRUD::column('price')->type('number'); 48 | * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); 49 | */ 50 | 51 | 52 | CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); 53 | CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); 54 | CRUD::addColumn(['name' => 'gender', 'label' => 'Giới tính', 'type' => 'text']); 55 | CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']); 56 | } 57 | 58 | /** 59 | * Define what happens when the Create operation is loaded. 60 | * 61 | * @see https://backpackforlaravel.com/docs/crud-operation-create 62 | * @return void 63 | */ 64 | protected function setupCreateOperation() 65 | { 66 | $this->authorize('create', Director::class); 67 | 68 | CRUD::setValidation(DirectorRequest::class); 69 | 70 | /** 71 | * Fields can be defined using the fluent syntax or array syntax: 72 | * - CRUD::field('price')->type('number'); 73 | * - CRUD::addField(['name' => 'price', 'type' => 'number'])); 74 | */ 75 | 76 | CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); 77 | CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); 78 | CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']); 79 | CRUD::addField([ 80 | 'name' => 'gender', 81 | 'label' => "Giới tính", 82 | 'type' => 'select_from_array', 83 | 'options' => ['male' => 'Nam', 'female' => 'Nữ', 'other' => 'Khác'], 84 | 'allows_null' => false, 85 | 'default' => 'one', 86 | ],); 87 | } 88 | 89 | /** 90 | * Define what happens when the Update operation is loaded. 91 | * 92 | * @see https://backpackforlaravel.com/docs/crud-operation-update 93 | * @return void 94 | */ 95 | protected function setupUpdateOperation() 96 | { 97 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 98 | 99 | 100 | $this->setupCreateOperation(); 101 | } 102 | 103 | protected function setupDeleteOperation() 104 | { 105 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Controllers/Admin/EpisodeCrudController.php: -------------------------------------------------------------------------------- 1 | crud->addButtonFromModelFunction('line', 'open_episode', 'openEpisode', 'beginning'); 42 | $this->crud->denyAccess('create'); 43 | $this->crud->denyAccess('delete'); 44 | } 45 | 46 | /** 47 | * Define what happens when the List operation is loaded. 48 | * 49 | * @see https://backpackforlaravel.com/docs/crud-operation-list-entries 50 | * @return void 51 | */ 52 | protected function setupListOperation() 53 | { 54 | $this->authorize('browse', Episode::class); 55 | 56 | /** 57 | * Columns can be defined using the fluent syntax or array syntax: 58 | * - CRUD::column('price')->type('number'); 59 | * - CRUD::addColumn(['name' => 'price', 'type' => 'number','tab'=>'Thông tin phim']); 60 | */ 61 | $this->crud->enableExportButtons(); 62 | $this->crud->addClause('where', 'has_report', true); 63 | 64 | CRUD::addColumn([ 65 | 'name' => 'movie', 'label' => 'Phim', 'type' => 'relationship', 66 | 'searchLogic' => function ($query, $column, $searchTerm) { 67 | $query->orWhereHas('movie', function ($movie) use ($searchTerm) { 68 | $movie->where('name', 'like', '%' . $searchTerm . '%') 69 | ->orWhere('origin_name', 'like', '%' . $searchTerm . '%'); 70 | }); 71 | } 72 | ]); 73 | CRUD::addColumn(['name' => 'name', 'label' => 'Tập', 'type' => 'text']); 74 | CRUD::addColumn(['name' => 'type', 'label' => 'Type', 'type' => 'text']); 75 | CRUD::addColumn(['name' => 'link', 'label' => 'Link', 'type' => 'textarea']); 76 | } 77 | 78 | /** 79 | * Define what happens when the Create operation is loaded. 80 | * 81 | * @see https://backpackforlaravel.com/docs/crud-operation-create 82 | * @return void 83 | */ 84 | protected function setupCreateOperation() 85 | { 86 | abort(404); 87 | } 88 | 89 | /** 90 | * Define what happens when the Update operation is loaded. 91 | * 92 | * @see https://backpackforlaravel.com/docs/crud-operation-update 93 | * @return void 94 | */ 95 | protected function setupUpdateOperation() 96 | { 97 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 98 | 99 | 100 | CRUD::addField(['name' => 'type', 'label' => 'Type', 'type' => 'select_from_array', 'options' => config('ophim.episodes.types')]); 101 | CRUD::addField(['name' => 'link', 'label' => 'Nguồn phát', 'type' => 'url']); 102 | CRUD::addField(['name' => 'has_report', 'label' => 'Đánh dấu đang lỗi', 'type' => 'checkbox']); 103 | CRUD::addField(['name' => 'report_message', 'label' => 'Report message', 'type' => 'textarea']); 104 | } 105 | 106 | public function bulkDelete() 107 | { 108 | $this->crud->hasAccessOrFail('bulkDelete'); 109 | $entries = request()->input('entries', []); 110 | $deletedEntries = []; 111 | 112 | foreach ($entries as $key => $id) { 113 | if ($entry = $this->crud->model->find($id)) { 114 | $deletedEntries[] = $entry->update(['has_report' => 0, 'report_message' => '']); 115 | } 116 | } 117 | 118 | return $deletedEntries; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Controllers/Admin/MenuCrudController.php: -------------------------------------------------------------------------------- 1 | crud->setModel(Menu::class); 30 | $this->crud->setRoute(config('backpack.base.route_prefix') . '/menu'); 31 | $this->crud->setEntityNameStrings('menu item', 'menu items'); 32 | $this->crud->enableReorder('name', 2); 33 | } 34 | 35 | /** 36 | * Define what happens when the List operation is loaded. 37 | * 38 | * @see https://backpackforlaravel.com/docs/crud-operation-list-entries 39 | * @return void 40 | */ 41 | protected function setupListOperation() 42 | { 43 | $this->authorize('browse', Menu::class); 44 | 45 | $this->crud->addColumn([ 46 | 'name' => 'name', 47 | 'label' => 'Label', 48 | ]); 49 | $this->crud->addColumn([ 50 | 'label' => 'Parent', 51 | 'type' => 'select', 52 | 'name' => 'parent_id', 53 | 'entity' => 'parent', 54 | 'attribute' => 'name', 55 | 'model' => Menu::class, 56 | ]); 57 | $this->crud->addColumn([ 58 | 'name' => 'link', 59 | 'label' => 'Link', 60 | 'type' => 'url', 61 | ]); 62 | } 63 | 64 | /** 65 | * Define what happens when the Create operation is loaded. 66 | * 67 | * @see https://backpackforlaravel.com/docs/crud-operation-create 68 | * @return void 69 | */ 70 | protected function setupCreateOperation() 71 | { 72 | $this->authorize('create', Menu::class); 73 | 74 | $this->crud->addField([ 75 | 'name' => 'name', 76 | 'label' => 'Label', 77 | ]); 78 | $this->crud->addField([ 79 | 'label' => 'Parent', 80 | 'type' => 'select', 81 | 'name' => 'parent_id', 82 | 'entity' => 'parent', 83 | 'attribute' => 'name', 84 | Menu::class 85 | ]); 86 | 87 | $this->crud->addField([ 88 | 'name' => ['type', 'link', 'internal_link'], 89 | 'label' => 'Type', 90 | 'type' => 'page_or_link', 91 | ]); 92 | } 93 | 94 | /** 95 | * Define what happens when the Update operation is loaded. 96 | * 97 | * @see https://backpackforlaravel.com/docs/crud-operation-update 98 | * @return void 99 | */ 100 | protected function setupUpdateOperation() 101 | { 102 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 103 | 104 | 105 | $this->setupCreateOperation(); 106 | } 107 | 108 | protected function setupDeleteOperation() 109 | { 110 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 111 | } 112 | 113 | public function bulkDelete() 114 | { 115 | $this->crud->hasAccessOrFail('bulkDelete'); 116 | $entries = request()->input('entries', []); 117 | $deletedEntries = []; 118 | foreach ($entries as $key => $id) { 119 | if ($entry = $this->crud->model->find($id)) { 120 | $deletedEntries[] = $entry->delete(); 121 | } 122 | } 123 | 124 | return $deletedEntries; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Controllers/Admin/PluginController.php: -------------------------------------------------------------------------------- 1 | crud->denyAccess('update'); 28 | } 29 | 30 | /** 31 | * Define what happens when the List operation is loaded. 32 | * 33 | * @see https://backpackforlaravel.com/docs/crud-operation-list-entries 34 | * @return void 35 | */ 36 | protected function setupListOperation() 37 | { 38 | if (!backpack_user()->hasPermissionTo('Browse plugin')) { 39 | abort(403); 40 | } 41 | 42 | CRUD::column('name')->label('Plugin')->type('text'); 43 | CRUD::column('version')->label('Version')->type('text'); 44 | $this->crud->addButtonFromModelFunction('line', 'editBtn', 'editBtn', 'beginning'); 45 | $this->crud->addButtonFromModelFunction('line', 'openBtn', 'openBtn', 'beginning'); 46 | } 47 | 48 | /** 49 | * Define what happens when the Update operation is loaded. 50 | * 51 | * @see https://backpackforlaravel.com/docs/crud-operation-update 52 | * @return void 53 | */ 54 | protected function setupUpdateOperation() 55 | { 56 | $plugin = $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()); 57 | 58 | $fields = $plugin->options; 59 | 60 | CRUD::addField(['name' => 'fields', 'type' => 'hidden', 'value' => collect($fields)->implode('name', ',')]); 61 | 62 | foreach ($fields as $field) { 63 | CRUD::addField($field); 64 | } 65 | } 66 | 67 | public function show($id) 68 | { 69 | /** @var Plugin */ 70 | $plugin = Plugin::findOrFail($id); 71 | 72 | return $plugin->open(); 73 | } 74 | 75 | /** 76 | * Show the form for editing the specified resource. 77 | * 78 | * @return \Illuminate\Contracts\View\View 79 | */ 80 | public function edit($id) 81 | { 82 | if (!backpack_user()->hasPermissionTo('Update plugin')) { 83 | abort(403); 84 | } 85 | $id = $this->crud->getCurrentEntryId() ?? $id; 86 | 87 | $this->data['entry'] = $this->crud->getEntryWithLocale($id); 88 | $this->crud->setOperationSetting('fields', $this->getUpdateFields()); 89 | 90 | $this->data['crud'] = $this->crud; 91 | $this->data['saveAction'] = $this->crud->getSaveAction(); 92 | $this->data['title'] = $this->crud->getTitle() ?? trans('backpack::crud.edit') . ' ' . $this->crud->entity_name; 93 | $this->data['id'] = $id; 94 | 95 | // load the view from /resources/views/vendor/backpack/crud/ if it exists, otherwise load the one in the package 96 | return view($this->crud->getEditView(), $this->data); 97 | } 98 | 99 | /** 100 | * Update the specified resource in the database. 101 | * 102 | * @return array|\Illuminate\Http\RedirectResponse 103 | */ 104 | public function update($plugin) 105 | { 106 | if (!backpack_user()->hasPermissionTo('Update plugin')) { 107 | abort(403); 108 | } 109 | 110 | // execute the FormRequest authorization and validation, if one is required 111 | $request = $this->crud->validateRequest(); 112 | 113 | // register any Model Events defined on fields 114 | $this->crud->registerFieldEvents(); 115 | 116 | // update the row in the db 117 | $item = $this->crud->update( 118 | $request->get($this->crud->model->getKeyName()), 119 | [ 120 | 'value' => request()->only(explode(',', request('fields'))) 121 | ] 122 | ); 123 | $this->data['entry'] = $this->crud->entry = $item; 124 | 125 | // show a success message 126 | Alert::success(trans('backpack::crud.update_success'))->flash(); 127 | 128 | return redirect(backpack_url('plugin')); 129 | } 130 | 131 | /** 132 | * Get all fields needed for the EDIT ENTRY form. 133 | * 134 | * @param int $id The id of the entry that is being edited. 135 | * @return array The fields with attributes, fake attributes and values. 136 | */ 137 | public function getUpdateFields($id = false) 138 | { 139 | $fields = $this->crud->fields(); 140 | $entry = ($id != false) ? $this->getEntry($id) : $this->crud->getCurrentEntry(); 141 | $options = $entry->value ?? []; 142 | 143 | foreach ($options as $k => $v) { 144 | $fields[$k]['value'] = $v; 145 | } 146 | 147 | if (!array_key_exists('id', $fields)) { 148 | $fields['id'] = [ 149 | 'name' => $entry->getKeyName(), 150 | 'value' => $entry->getKey(), 151 | 'type' => 'hidden', 152 | ]; 153 | } 154 | 155 | return $fields; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Controllers/Admin/QuickActionController.php: -------------------------------------------------------------------------------- 1 | flash(); 21 | return back(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Controllers/Admin/RegionCrudController.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Region::class); 44 | 45 | /** 46 | * Columns can be defined using the fluent syntax or array syntax: 47 | * - CRUD::column('price')->label('price')->type('number'); 48 | * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); 49 | */ 50 | CRUD::column('name')->label('Tên khu vực')->type('text'); 51 | CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text'); 52 | CRUD::column('seo_title')->label('SEO Title')->type('text'); 53 | CRUD::column('seo_des')->label('SEO Description')->type('text'); 54 | CRUD::column('seo_key')->label('SEO Keyword')->type('text'); 55 | } 56 | 57 | /** 58 | * Define what happens when the Create operation is loaded. 59 | * 60 | * @see https://backpackforlaravel.com/docs/crud-operation-create 61 | * @return void 62 | */ 63 | protected function setupCreateOperation() 64 | { 65 | $this->authorize('create', Region::class); 66 | 67 | CRUD::setValidation(RegionRequest::class); 68 | 69 | /** 70 | * Fields can be defined using the fluent syntax or array syntax: 71 | * - CRUD::field('price')->label('price')->type('number'); 72 | * - CRUD::addField(['name' => 'price', 'type' => 'number'])); 73 | */ 74 | CRUD::field('name')->label('Tên khu vực')->type('text'); 75 | CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text'); 76 | CRUD::field('seo_title')->label('SEO Title')->type('text'); 77 | CRUD::field('seo_des')->label('SEO Description')->type('textarea'); 78 | CRUD::field('seo_key')->label('SEO Keyword')->type('text'); 79 | } 80 | /** 81 | * Define what happens when the Update operation is loaded. 82 | * 83 | * @see https://backpackforlaravel.com/docs/crud-operation-update 84 | * @return void 85 | */ 86 | protected function setupUpdateOperation() 87 | { 88 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 89 | 90 | 91 | $this->setupCreateOperation(); 92 | } 93 | 94 | protected function setupDeleteOperation() 95 | { 96 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Controllers/Admin/StudioCrudController.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Studio::class); 44 | 45 | /** 46 | * Columns can be defined using the fluent syntax or array syntax: 47 | * - CRUD::column('price')->type('number'); 48 | * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); 49 | */ 50 | 51 | CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); 52 | CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); 53 | CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']); 54 | } 55 | 56 | /** 57 | * Define what happens when the Create operation is loaded. 58 | * 59 | * @see https://backpackforlaravel.com/docs/crud-operation-create 60 | * @return void 61 | */ 62 | protected function setupCreateOperation() 63 | { 64 | $this->authorize('create', Studio::class); 65 | 66 | CRUD::setValidation(StudioRequest::class); 67 | 68 | /** 69 | * Fields can be defined using the fluent syntax or array syntax: 70 | * - CRUD::field('price')->type('number'); 71 | * - CRUD::addField(['name' => 'price', 'type' => 'number'])); 72 | */ 73 | 74 | CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); 75 | CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); 76 | CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']); 77 | } 78 | 79 | /** 80 | * Define what happens when the Update operation is loaded. 81 | * 82 | * @see https://backpackforlaravel.com/docs/crud-operation-update 83 | * @return void 84 | */ 85 | protected function setupUpdateOperation() 86 | { 87 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 88 | 89 | 90 | $this->setupCreateOperation(); 91 | } 92 | 93 | protected function setupDeleteOperation() 94 | { 95 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Controllers/Admin/TagCrudController.php: -------------------------------------------------------------------------------- 1 | authorize('browse', Tag::class); 44 | 45 | /** 46 | * Columns can be defined using the fluent syntax or array syntax: 47 | * - CRUD::column('price')->type('number'); 48 | * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); 49 | */ 50 | 51 | CRUD::addColumn(['name' => 'name', 'type' => 'text']); 52 | CRUD::addColumn(['name' => 'slug', 'type' => 'text']); 53 | } 54 | 55 | /** 56 | * Define what happens when the Create operation is loaded. 57 | * 58 | * @see https://backpackforlaravel.com/docs/crud-operation-create 59 | * @return void 60 | */ 61 | protected function setupCreateOperation() 62 | { 63 | $this->authorize('create', Tag::class); 64 | 65 | CRUD::setValidation(TagRequest::class); 66 | 67 | /** 68 | * Fields can be defined using the fluent syntax or array syntax: 69 | * - CRUD::field('price')->type('number'); 70 | * - CRUD::addField(['name' => 'price', 'type' => 'number'])); 71 | */ 72 | 73 | CRUD::addField(['name' => 'name', 'type' => 'text']); 74 | CRUD::addField(['name' => 'slug', 'type' => 'text']); 75 | } 76 | 77 | /** 78 | * Define what happens when the Update operation is loaded. 79 | * 80 | * @see https://backpackforlaravel.com/docs/crud-operation-update 81 | * @return void 82 | */ 83 | protected function setupUpdateOperation() 84 | { 85 | $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 86 | 87 | 88 | $this->setupCreateOperation(); 89 | } 90 | 91 | protected function setupDeleteOperation() 92 | { 93 | $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | options, 'value', 'name') ?? [], 18 | is_array($theme->value) ? $theme->value : [] 19 | )); 20 | 21 | return $props[$key] ?? $fallback; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Middleware/CKFinderAuth.php: -------------------------------------------------------------------------------- 1 | function () { 21 | return true; 22 | }]); 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | 'ckCsrfToken' 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /src/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | 'ckfinder/*', 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /src/Models/Catalog.php: -------------------------------------------------------------------------------- 1 | slug; 60 | if (strpos($site_routes, '{id}')) $params['id'] = $this->id; 61 | return route('types.movies.index', $params); 62 | } 63 | 64 | public function generateSeoTags() 65 | { 66 | $seo_title = $this->seo_title; 67 | $seo_des = $this->seo_des; 68 | $seo_key = $this->seo_key; 69 | $getUrl = $this->getUrl(); 70 | $site_meta_siteName = setting('site_meta_siteName'); 71 | 72 | SEOMeta::setTitle($seo_title, false) 73 | ->setDescription($seo_des) 74 | ->addKeyword([$seo_key]) 75 | ->setCanonical($getUrl) 76 | ->setPrev(request()->root()) 77 | ->setPrev(request()->root()); 78 | 79 | OpenGraph::setSiteName($site_meta_siteName) 80 | ->setType('website') 81 | ->setTitle($seo_title, false) 82 | ->addProperty('locale', 'vi-VN') 83 | ->addProperty('url', $getUrl) 84 | ->setDescription($seo_des); 85 | 86 | TwitterCard::setSite($site_meta_siteName) 87 | ->setTitle($seo_title, false) 88 | ->setType('summary') 89 | ->setDescription($seo_des) 90 | ->setUrl($getUrl); 91 | 92 | JsonLdMulti::newJsonLd() 93 | ->setSite($site_meta_siteName) 94 | ->setTitle($seo_title, false) 95 | ->setType('WebPage') 96 | ->setDescription($seo_des) 97 | ->setUrl($getUrl); 98 | 99 | $breadcrumb = []; 100 | array_push($breadcrumb, [ 101 | '@type' => 'ListItem', 102 | 'position' => 1, 103 | 'name' => 'Home', 104 | 'item' => url('/') 105 | ]); 106 | array_push($breadcrumb, [ 107 | '@type' => 'ListItem', 108 | 'position' => 2, 109 | 'name' => $this->name, 110 | 'item' => $getUrl 111 | ]); 112 | array_push($breadcrumb, [ 113 | '@type' => 'ListItem', 114 | 'position' => 3, 115 | 'name' => "Trang " . (request()->get('page') ?: 1), 116 | ]); 117 | JsonLdMulti::newJsonLd() 118 | ->setType('BreadcrumbList') 119 | ->addValue('name', '') 120 | ->addValue('description', '') 121 | ->addValue('itemListElement', $breadcrumb); 122 | } 123 | 124 | public function openView($crud = false) 125 | { 126 | return ' View'; 127 | } 128 | 129 | 130 | /* 131 | |-------------------------------------------------------------------------- 132 | | RELATIONS 133 | |-------------------------------------------------------------------------- 134 | */ 135 | 136 | /* 137 | |-------------------------------------------------------------------------- 138 | | SCOPES 139 | |-------------------------------------------------------------------------- 140 | */ 141 | 142 | /* 143 | |-------------------------------------------------------------------------- 144 | | ACCESSORS 145 | |-------------------------------------------------------------------------- 146 | */ 147 | 148 | /* 149 | |-------------------------------------------------------------------------- 150 | | MUTATORS 151 | |-------------------------------------------------------------------------- 152 | */ 153 | } 154 | -------------------------------------------------------------------------------- /src/Models/Menu.php: -------------------------------------------------------------------------------- 1 | belongsTo(static::class, 'parent_id'); 23 | } 24 | 25 | public function children() 26 | { 27 | return $this->hasMany(static::class, 'parent_id'); 28 | } 29 | 30 | /** 31 | * Get all menu items, in a hierarchical collection. 32 | * Only supports 2 levels of indentation. 33 | */ 34 | public static function getTree() 35 | { 36 | $menu = self::fromCache()->all()->sortBy('lft'); 37 | 38 | if ($menu->count()) { 39 | foreach ($menu as $k => $menu_item) { 40 | $menu_item->children = collect([]); 41 | 42 | foreach ($menu as $i => $menu_subitem) { 43 | if ($menu_subitem->parent_id == $menu_item->id) { 44 | $menu_item->children->push($menu_subitem); 45 | 46 | // remove the subitem for the first level 47 | $menu = $menu->reject(function ($item) use ($menu_subitem) { 48 | return $item->id == $menu_subitem->id; 49 | }); 50 | } 51 | } 52 | } 53 | } 54 | 55 | return $menu; 56 | } 57 | 58 | public function url() 59 | { 60 | switch ($this->type) { 61 | case 'external_link': 62 | return $this->link; 63 | break; 64 | 65 | case 'internal_link': 66 | return is_null($this->link) ? '#' : url($this->link); 67 | break; 68 | 69 | default: //page_link 70 | if ($this->page) { 71 | return url($this->page->slug); 72 | } 73 | break; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Models/Studio.php: -------------------------------------------------------------------------------- 1 | slug); 63 | } 64 | 65 | protected function titlePattern(): string 66 | { 67 | return Setting::get('site_studio_title', ''); 68 | } 69 | 70 | protected function descriptionPattern(): string 71 | { 72 | return Setting::get('site_region_des', ''); 73 | } 74 | 75 | protected function keywordsPattern(): string 76 | { 77 | return Setting::get('site_region_key', ''); 78 | } 79 | 80 | public function generateSeoTags() 81 | { 82 | $seo_title = $this->getTitle(); 83 | $seo_des = Str::limit($this->getDescription(), 150, '...'); 84 | $seo_key = $this->getKeywords(); 85 | 86 | SEOMeta::setTitle($seo_title, false) 87 | ->setDescription($seo_des) 88 | ->addKeyword([$seo_key]) 89 | ->setCanonical($this->getUrl()) 90 | ->setPrev(request()->root()) 91 | ->setPrev(request()->root()); 92 | // ->addMeta($meta, $value, 'property'); 93 | 94 | OpenGraph::setSiteName(setting('site_meta_siteName')) 95 | ->setTitle($seo_title, false) 96 | ->addProperty('type', 'movie') 97 | ->addProperty('locale', 'vi-VN') 98 | ->addProperty('url', $this->getUrl()) 99 | ->setDescription($seo_des) 100 | ->addImages([$this->thumb_url, $this->poster_url]); 101 | 102 | TwitterCard::setSite(setting('site_meta_siteName')) 103 | ->setTitle($seo_title, false) 104 | ->setType('movie') 105 | ->setImage($this->thumb_url) 106 | ->setDescription($seo_des) 107 | ->setUrl($this->getUrl()); 108 | // ->addValue($key, $value); 109 | 110 | JsonLdMulti::newJsonLd() 111 | ->setSite(setting('site_meta_siteName')) 112 | ->setTitle($seo_title, false) 113 | ->setType('movie') 114 | ->setDescription($seo_des) 115 | ->setUrl($this->getUrl()); 116 | // ->addValue($key, $value); 117 | } 118 | 119 | 120 | 121 | /* 122 | |-------------------------------------------------------------------------- 123 | | RELATIONS 124 | |-------------------------------------------------------------------------- 125 | */ 126 | 127 | public function movies() 128 | { 129 | return $this->belongsToMany(Movie::class); 130 | } 131 | 132 | /* 133 | |-------------------------------------------------------------------------- 134 | | SCOPES 135 | |-------------------------------------------------------------------------- 136 | */ 137 | 138 | /* 139 | |-------------------------------------------------------------------------- 140 | | ACCESSORS 141 | |-------------------------------------------------------------------------- 142 | */ 143 | 144 | /* 145 | |-------------------------------------------------------------------------- 146 | | MUTATORS 147 | |-------------------------------------------------------------------------- 148 | */ 149 | } 150 | -------------------------------------------------------------------------------- /src/Models/Theme.php: -------------------------------------------------------------------------------- 1 | 'array', 33 | ]; 34 | 35 | public static function getActivatedTheme(): ?self 36 | { 37 | return Theme::where('active', true)->first() ?: Theme::first(); 38 | } 39 | 40 | public function getVersionAttribute() 41 | { 42 | if (!\Composer\InstalledVersions::isInstalled($this->package_name)) { 43 | return 'Unknown'; 44 | } 45 | 46 | return \PackageVersions\Versions::getVersion($this->package_name); 47 | } 48 | 49 | public function getOptionsAttribute() 50 | { 51 | $allThemes = config('themes', []); 52 | 53 | if (!isset($allThemes[strtolower($this->name)]['options'])) { 54 | return []; 55 | } 56 | 57 | return $allThemes[strtolower($this->name)]['options']; 58 | } 59 | 60 | public function editBtn($crud = false) 61 | { 62 | return 'id}/edit") . '" class="btn btn-primary">Edit'; 63 | } 64 | 65 | public function deleteBtn($crud = false) 66 | { 67 | if ($this->getVersionAttribute() === 'Unknown') { 68 | 69 | $template = << 71 | {csrfField} 72 | 73 | 74 | EOT; 75 | $html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/delete"), $template); 76 | $html = str_replace("{csrfField}", csrf_field(), $html); 77 | $html = str_replace("{display_name}", $this->display_name, $html); 78 | 79 | return $html; 80 | } 81 | return ''; 82 | } 83 | 84 | public function activeBtn($crud = false) 85 | { 86 | $template = << 88 | {csrfField} 89 | 90 | 91 | EOT; 92 | 93 | $html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/active"), $template); 94 | $html = str_replace("{csrfField}", csrf_field(), $html); 95 | $html = str_replace("{display_name}", $this->display_name, $html); 96 | 97 | if ($this->active) { 98 | $html = str_replace("{name}", 'Re-Activate', $html); 99 | $html = str_replace("{btnType}", 'btn-secondary', $html); 100 | } else { 101 | $html = str_replace("{name}", 'Activate', $html); 102 | $html = str_replace("{btnType}", 'btn-primary', $html); 103 | } 104 | 105 | return $html; 106 | } 107 | 108 | public function resetBtn($crud = false) 109 | { 110 | $template = << 112 | {csrfField} 113 | 114 | 115 | EOT; 116 | 117 | $html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/reset"), $template); 118 | $html = str_replace("{csrfField}", csrf_field(), $html); 119 | $html = str_replace("{btnType}", 'btn-warning', $html); 120 | $html = str_replace("{name}", 'Reset', $html); 121 | 122 | return $html; 123 | } 124 | 125 | public function active() 126 | { 127 | static::where('active', true)->update(['active' => false]); 128 | 129 | $publishTags = config('themes', [])[$this->name]['publishes'] ?? []; 130 | 131 | foreach ($publishTags as $tag) { 132 | Artisan::call('vendor:publish', [ 133 | '--tag' => $tag, 134 | '--force' => true 135 | ]); 136 | } 137 | 138 | return $this->update(['active' => true]); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Models/User.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse user'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create user'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update user'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete user'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/CatalogPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse catalog'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create catalog'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update catalog'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete catalog'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/CategoryPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse category'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create category'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update category'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete category'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/CrawlSchedulePolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse crawl schedule'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create crawl schedule'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update crawl schedule'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete crawl schedule'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/DirectorPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse director'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create director'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update director'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete director'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/EpisodePolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse episode'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create episode'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update episode'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete episode'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Policies/MenuPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse menu'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create menu'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update menu'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete menu'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/MoviePolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse movie'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create movie'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update movie'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete movie'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/PermissionPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 15 | return true; 16 | } 17 | } 18 | 19 | public function browse($user) 20 | { 21 | return $user->hasPermissionTo('Browse permission'); 22 | } 23 | 24 | public function create($user) 25 | { 26 | return $user->hasPermissionTo('Create permission'); 27 | } 28 | 29 | public function update($user, $entry) 30 | { 31 | return $user->hasPermissionTo('Update permission'); 32 | } 33 | 34 | public function delete($user, $entry) 35 | { 36 | return $user->hasPermissionTo('Delete permission'); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/Policies/RegionPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse region'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create region'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update region'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete region'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/RolePolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse role'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create role'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update role'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete role'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/StudioPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse studio'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create studio'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update studio'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete studio'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/TagPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse tag'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create tag'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update tag'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete tag'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Policies/UserPolicy.php: -------------------------------------------------------------------------------- 1 | hasRole('Admin')) { 14 | return true; 15 | } 16 | } 17 | 18 | public function browse($user) 19 | { 20 | return $user->hasPermissionTo('Browse user'); 21 | } 22 | 23 | public function create($user) 24 | { 25 | return $user->hasPermissionTo('Create user'); 26 | } 27 | 28 | public function update($user, $entry) 29 | { 30 | return $user->hasPermissionTo('Update user'); 31 | } 32 | 33 | public function delete($user, $entry) 34 | { 35 | return $user->hasPermissionTo('Delete user'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Requests/ActorRequest.php: -------------------------------------------------------------------------------- 1 | check(); 19 | } 20 | 21 | /** 22 | * Get the validation rules that apply to the request. 23 | * 24 | * @return array 25 | */ 26 | public function rules() 27 | { 28 | $this->name_md5 = md5($this->name); 29 | 30 | return [ 31 | 'name' => ['required', 'max:255', new UniqueName('actors', 'name', 'name_md5', 'id', $this->id)], 32 | 'slug' => 'max:255|unique:actors,slug,' . $this->id . ',id', 33 | ]; 34 | } 35 | 36 | /** 37 | * Get the validation attributes that apply to the request. 38 | * 39 | * @return array 40 | */ 41 | public function attributes() 42 | { 43 | return [ 44 | // 45 | ]; 46 | } 47 | 48 | /** 49 | * Get the validation messages that apply to the request. 50 | * 51 | * @return array 52 | */ 53 | public function messages() 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Requests/CatalogRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'name' => 'required|min:5|max:255', 29 | 'slug' => 'max:255|unique:catalogs,slug,' . $this->id . ',id', 30 | 'value' => 'string', 31 | 'seo_title' => 'string|max:255', 32 | 'seo_des' => 'string|max:255', 33 | 'seo_key' => 'string|max:255', 34 | ]; 35 | } 36 | 37 | /** 38 | * Get the validation attributes that apply to the request. 39 | * 40 | * @return array 41 | */ 42 | public function attributes() 43 | { 44 | return [ 45 | // 46 | ]; 47 | } 48 | 49 | /** 50 | * Get the validation messages that apply to the request. 51 | * 52 | * @return array 53 | */ 54 | public function messages() 55 | { 56 | return [ 57 | // 58 | ]; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Requests/CategoryRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'name' => 'required|min:5|max:255', 29 | 'slug' => 'max:255|unique:categories,slug,' . $this->id . ',id', 30 | 'seo_title' => 'string|max:255', 31 | 'seo_des' => 'string|max:255', 32 | 'seo_key' => 'string|max:255', 33 | ]; 34 | } 35 | 36 | /** 37 | * Get the validation attributes that apply to the request. 38 | * 39 | * @return array 40 | */ 41 | public function attributes() 42 | { 43 | return [ 44 | // 45 | ]; 46 | } 47 | 48 | /** 49 | * Get the validation messages that apply to the request. 50 | * 51 | * @return array 52 | */ 53 | public function messages() 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Requests/CrawlScheduleRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'type' => 'required', 29 | 'fields' => 'required' 30 | ]; 31 | } 32 | 33 | /** 34 | * Get the validation attributes that apply to the request. 35 | * 36 | * @return array 37 | */ 38 | public function attributes() 39 | { 40 | return [ 41 | // 42 | ]; 43 | } 44 | 45 | /** 46 | * Get the validation messages that apply to the request. 47 | * 48 | * @return array 49 | */ 50 | public function messages() 51 | { 52 | return [ 53 | // 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Requests/DirectorRequest.php: -------------------------------------------------------------------------------- 1 | check(); 19 | } 20 | 21 | /** 22 | * Get the validation rules that apply to the request. 23 | * 24 | * @return array 25 | */ 26 | public function rules() 27 | { 28 | $this->name_md5 = md5($this->name); 29 | 30 | return [ 31 | 'name' => ['required', 'max:255', new UniqueName('directors', 'name', 'name_md5', 'id', $this->id)], 32 | 'slug' => 'max:255|unique:directors,slug,' . $this->id . ',id', 33 | ]; 34 | } 35 | 36 | /** 37 | * Get the validation attributes that apply to the request. 38 | * 39 | * @return array 40 | */ 41 | public function attributes() 42 | { 43 | return [ 44 | // 45 | ]; 46 | } 47 | 48 | /** 49 | * Get the validation messages that apply to the request. 50 | * 51 | * @return array 52 | */ 53 | public function messages() 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Requests/MenuRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'name' => 'required|max:255', 29 | 'type' => 'required', 30 | 'link' => 'required|max:2048' 31 | ]; 32 | } 33 | 34 | /** 35 | * Get the validation attributes that apply to the request. 36 | * 37 | * @return array 38 | */ 39 | public function attributes() 40 | { 41 | return [ 42 | // 43 | ]; 44 | } 45 | 46 | /** 47 | * Get the validation messages that apply to the request. 48 | * 49 | * @return array 50 | */ 51 | public function messages() 52 | { 53 | return [ 54 | // 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Requests/MovieRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'name' => 'required|max:512', 29 | 'origin_name' => 'required|max:512', 30 | 'slug' => 'max:255|unique:movies,slug,' . $this->id . ',id', 31 | 'type' => 'required|in:single,series', 32 | 'status' => 'required|in:trailer,ongoing,completed', 33 | ]; 34 | } 35 | 36 | /** 37 | * Get the validation attributes that apply to the request. 38 | * 39 | * @return array 40 | */ 41 | public function attributes() 42 | { 43 | return [ 44 | // 45 | ]; 46 | } 47 | 48 | /** 49 | * Get the validation messages that apply to the request. 50 | * 51 | * @return array 52 | */ 53 | public function messages() 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Requests/RegionRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'name' => 'required|min:5|max:255', 29 | 'slug' => 'max:255|unique:regions,slug,' . $this->id . ',id', 30 | 'seo_title' => 'string|max:255', 31 | 'seo_des' => 'string|max:255', 32 | 'seo_key' => 'string|max:255', 33 | ]; 34 | } 35 | 36 | /** 37 | * Get the validation attributes that apply to the request. 38 | * 39 | * @return array 40 | */ 41 | public function attributes() 42 | { 43 | return [ 44 | // 45 | ]; 46 | } 47 | 48 | /** 49 | * Get the validation messages that apply to the request. 50 | * 51 | * @return array 52 | */ 53 | public function messages() 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Requests/StudioRequest.php: -------------------------------------------------------------------------------- 1 | check(); 18 | } 19 | 20 | /** 21 | * Get the validation rules that apply to the request. 22 | * 23 | * @return array 24 | */ 25 | public function rules() 26 | { 27 | return [ 28 | 'name' => 'required|string|max:512', 29 | 'slug' => 'max:255|unique:studios,slug,' . $this->id . ',id', 30 | ]; 31 | } 32 | 33 | /** 34 | * Get the validation attributes that apply to the request. 35 | * 36 | * @return array 37 | */ 38 | public function attributes() 39 | { 40 | return [ 41 | // 42 | ]; 43 | } 44 | 45 | /** 46 | * Get the validation messages that apply to the request. 47 | * 48 | * @return array 49 | */ 50 | public function messages() 51 | { 52 | return [ 53 | // 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Requests/TagRequest.php: -------------------------------------------------------------------------------- 1 | check(); 20 | } 21 | 22 | /** 23 | * Get the validation rules that apply to the request. 24 | * 25 | * @return array 26 | */ 27 | public function rules() 28 | { 29 | return [ 30 | 'name' => ['required', 'max:255', new UniqueName('tags', 'name', 'name_md5', 'id', $this->id)], 31 | ]; 32 | } 33 | 34 | /** 35 | * Get the validation attributes that apply to the request. 36 | * 37 | * @return array 38 | */ 39 | public function attributes() 40 | { 41 | return [ 42 | // 43 | ]; 44 | } 45 | 46 | /** 47 | * Get the validation messages that apply to the request. 48 | * 49 | * @return array 50 | */ 51 | public function messages() 52 | { 53 | return [ 54 | // 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Rules/UniqueName.php: -------------------------------------------------------------------------------- 1 | table = $table; 24 | $this->md5Field = $md5Field; 25 | $this->excludeField = $excludeField; 26 | $this->excludeVal = $excludeVal; 27 | $this->nameField = $nameField; 28 | } 29 | 30 | /** 31 | * Determine if the validation rule passes. 32 | * 33 | * @param string $attribute 34 | * @param mixed $value 35 | * @return bool 36 | */ 37 | public function passes($attribute, $value) 38 | { 39 | return DB::table($this->table)->where($this->excludeField, '!=', $this->excludeVal)->where($this->md5Field, md5($value))->doesntExist(); 40 | } 41 | 42 | /** 43 | * Get the validation error message. 44 | * 45 | * @return string 46 | */ 47 | public function message() 48 | { 49 | return ":attribute must be unique"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Theme.php: -------------------------------------------------------------------------------- 1 | payload = $payload; 19 | 20 | $this->name = ThemeModel::getActivatedTheme()->name; 21 | 22 | if (is_null($this->name)) { 23 | throw new \Exception("Not found any theme. Please install and active one.");; 24 | } 25 | 26 | $this->themePath = $this->namespace . '::' . $this->name; 27 | } 28 | 29 | public function render($template, array $data = []) 30 | { 31 | $viewPath = sprintf("%s.%s", $this->themePath, $template); 32 | if (!view()->exists($viewPath)) { 33 | throw new Exception("Theme {$this->name}'s {$template} view is not installed. Please check your installation"); 34 | } 35 | 36 | return view($viewPath, array_merge($this->payload, $data)); 37 | } 38 | 39 | public function addPayload(array $data) 40 | { 41 | $this->payload = array_merge($this->payload, $data); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Traits/ActorLog.php: -------------------------------------------------------------------------------- 1 | user_id = auth('backpack')->id() ?: $instance->user_id; 11 | $instance->user_name = auth('backpack')->user() ? auth('backpack')->user()->name : $instance->username; 12 | }); 13 | 14 | static::updating(function ($instance) { 15 | $instance->user_id = auth('backpack')->id() ?: $instance->user_id; 16 | $instance->user_name = auth('backpack')->user() ? auth('backpack')->user()->name : $instance->username; 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Traits/HasDescription.php: -------------------------------------------------------------------------------- 1 | descriptionPattern(); 18 | 19 | preg_match_all('/{.*?}/', $pattern, $vars); 20 | 21 | foreach ($vars[0] as $var) { 22 | try { 23 | $x = str_replace('{', '', $var); 24 | $x = str_replace('}', '', $x); 25 | $keys = explode('.', (string) $x); 26 | $data = $this; 27 | foreach ($keys as $key) { 28 | $data = $data->{$key}; 29 | } 30 | $pattern = str_replace($var, $data, $pattern); 31 | } catch (\Exception $e) { 32 | } 33 | } 34 | 35 | return $pattern; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Traits/HasFactory.php: -------------------------------------------------------------------------------- 1 | keywordsPattern(); 18 | 19 | preg_match_all('/{.*?}/', $pattern, $vars); 20 | 21 | foreach ($vars[0] as $var) { 22 | try { 23 | $x = str_replace('{', '', $var); 24 | $x = str_replace('}', '', $x); 25 | $keys = explode('.', (string) $x); 26 | $data = $this; 27 | foreach ($keys as $key) { 28 | $data = $data->{$key}; 29 | } 30 | $pattern = str_replace($var, $data, $pattern); 31 | } catch (\Exception $e) { 32 | } 33 | } 34 | 35 | return $pattern; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Traits/HasTitle.php: -------------------------------------------------------------------------------- 1 | titlePattern(); 18 | 19 | preg_match_all('/{.*?}/', $pattern, $vars); 20 | 21 | foreach ($vars[0] as $var) { 22 | try { 23 | $x = str_replace('{', '', $var); 24 | $x = str_replace('}', '', $x); 25 | $keys = explode('.', (string) $x); 26 | $data = $this; 27 | foreach ($keys as $key) { 28 | $data = $data->{$key}; 29 | } 30 | $pattern = str_replace($var, $data, $pattern); 31 | } catch (\Exception $e) { 32 | } 33 | } 34 | 35 | return $pattern; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Traits/HasUniqueName.php: -------------------------------------------------------------------------------- 1 | name_md5 = md5($instance->name); 18 | }); 19 | 20 | static::updating(function ($instance) { 21 | $instance->name_md5 = md5($instance->name); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Traits/Operations/BulkDeleteOperation.php: -------------------------------------------------------------------------------- 1 | $routeName.'.bulkDelete', 13 | 'uses' => $controller.'@bulkDelete', 14 | 'operation' => 'bulkDelete', 15 | ]); 16 | } 17 | 18 | protected function setupBulkDeleteDefaults() 19 | { 20 | $this->crud->allowAccess('bulkDelete'); 21 | 22 | $this->crud->operation('bulkDelete', function () { 23 | $this->crud->loadDefaultOperationSettingsFromConfig(); 24 | }); 25 | 26 | $this->crud->operation('list', function () { 27 | $this->crud->enableBulkActions(); 28 | $this->crud->addButton('bottom', 'bulk_delete', 'view', 'crud::buttons.bulk_delete'); 29 | }); 30 | } 31 | 32 | public function bulkDelete() 33 | { 34 | $this->crud->hasAccessOrFail('bulkDelete'); 35 | $entries = request()->input('entries', []); 36 | $deletedEntries = []; 37 | 38 | foreach ($entries as $key => $id) { 39 | if ($entry = $this->crud->model->find($id)) { 40 | $deletedEntries[] = $entry->delete(); 41 | } 42 | } 43 | 44 | return $deletedEntries; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Traits/Sluggable.php: -------------------------------------------------------------------------------- 1 | slug)) { 18 | $slug = Str::slug($instance->name) ?: $instance->name; 19 | $instance->slug = static::where('slug', $slug)->exists() 20 | ? sprintf("%s-%s%s", $slug, floor(microtime(true) * 1000), rand(1, 100)) 21 | : $slug; 22 | } 23 | }); 24 | 25 | static::updating(function ($instance) { 26 | if (empty($instance->slug)) { 27 | $slug = Str::slug($instance->name) ?: $instance->name; 28 | $instance->slug = static::where('slug', $slug)->exists() 29 | ? sprintf("%s-%s%s", $slug, floor(microtime(true) * 1000), rand(1, 100)) 30 | : $slug; 31 | } 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/databases/DatabaseTesting.php: -------------------------------------------------------------------------------- 1 | call([ 30 | CategoriesTableSeeder::class, 31 | RegionsTableSeeder::class, 32 | ThemesTableSeeder::class, 33 | MenusTableSeeder::class, 34 | SettingsTableSeeder::class, 35 | ]); 36 | 37 | Actor::factory(100)->create(); 38 | Director::factory(100)->create(); 39 | Tag::factory(100)->create(); 40 | 41 | for ($i = 1; $i < 1000; $i++) { 42 | Movie::factory(1) 43 | ->state([ 44 | 'publish_year' => rand(2018, 2022) 45 | ]) 46 | ->hasAttached(Region::all()->random()) 47 | ->hasAttached(Category::all()->random(3)) 48 | ->hasAttached(Actor::all()->random(rand(1, 5))) 49 | ->hasAttached(Director::all()->random(1)) 50 | ->hasAttached(Tag::all()->random(5)) 51 | ->has(Episode::factory(5)->state([ 52 | 'server' => 'Vietsub #1', 53 | 'type' => 'embed', 54 | 'link' => 'https://aa.nguonphimmoi.com/20220309/2918_589b816d/index.m3u8' 55 | ])) 56 | ->create(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel applications. By default, we are compiling the CSS 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | 15 | --------------------------------------------------------------------------------