vsmov 1.0.0

This commit is contained in:
Clemencia John
2026-04-15 21:11:19 -07:00
parent 311c74228c
commit 68260d170a
147 changed files with 12113 additions and 0 deletions

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,65 @@
<?php
namespace Vsmov\Core\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Vsmov\Core\Models\Episode;
class ChangeDomainEpisodeCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'vsmov:episode:change_domain_play';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Change episode domain play stream';
protected $progressBar;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$domains = array(
'vip.opstream10.com' => ['vie.opstream1.com', 'vie.haiphim.com'],
'vip.opstream15.com' => ['hd.1080phim.com', 'hd1080.opstream2.com'],
'vip.opstream14.com' => ['kd.hd-bophim.com', 'kd.opstream3.com'],
'vip.opstream11.com' => ['1080.hdphimonline.com', '1080.opstream4.com'],
'vip.opstream16.com' => ['hd.hdbophim.com', 'hdbo.opstream5.com'],
'vip.opstream12.com' => ['aa.nguonphimmoi.com', 'aa.opstream6.com'],
'vip.opstream13.com' => ['vie2.opstream7.com'],
'vip.opstream17.com' => ['vip.opstream8.com'],
);
foreach ($domains as $newDomain => $arrOldDomain) {
foreach ($arrOldDomain as $oldDomain) {
$this->info("Replace: $oldDomain => $newDomain");
Episode::where('link', 'LIKE', '%' . $oldDomain . '%')->update(['link' => DB::raw("REPLACE(link, '$oldDomain', '$newDomain')")]);
}
}
$this->info("Replace Done!");
return 0;
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace Vsmov\Core\Console;
use Illuminate\Console\Command;
use Spatie\Permission\Models\Role;
class CreateUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'vsmov:user
{--N|name= : The name of the new user}
{--E|email= : The user\'s email address}
{--P|password= : User\'s password}
{--encrypt=true : Encrypt user\'s password if it\'s plain text ( true by default )}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new user';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Creating a new user');
if (!$name = $this->option('name')) {
$name = $this->ask('Name');
}
if (!$email = $this->option('email')) {
$email = $this->ask('Email');
}
if (!$password = $this->option('password')) {
$password = $this->secret('Password');
}
if (!$this->confirm('Is administrator? [y|N]', $isAdmin = false)) {
$isAdmin = false;
} else {
$isAdmin = true;
}
if ($this->option('encrypt')) {
$password = bcrypt($password);
}
$auth = config('backpack.base.user_model_fqn', 'App\User');
$user = new $auth();
$user->name = $name;
$user->email = $email;
$user->password = $password;
if ($user->save()) {
$this->info('Successfully created new user');
if ($isAdmin) {
$user->roles()->attach(Role::firstOrCreate(['name' => 'Admin', 'guard_name' => 'backpack']));
}
} else {
$this->error('Something went wrong trying to save your user');
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Vsmov\Core\Console;
use Illuminate\Console\Command;
use Vsmov\Core\Database\Seeders\MenusTableSeeder;
class GenerateMenuCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'vsmov:menu:generate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate menu';
protected $progressBar;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->call('db:seed', [
'class' => MenusTableSeeder::class,
]);
$this->info('Menu is generated.');
return 0;
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace Vsmov\Core\Console;
use Backpack\Settings\app\Models\Setting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Vsmov\Core\Database\Seeders\CatalogsTableSeeder;
use Vsmov\Core\Database\Seeders\CategoriesTableSeeder;
use Vsmov\Core\Database\Seeders\MenusTableSeeder;
use Vsmov\Core\Database\Seeders\PermissionsSeeder;
use Vsmov\Core\Database\Seeders\RegionsTableSeeder;
use Vsmov\Core\Database\Seeders\SettingsTableSeeder;
use Vsmov\Core\Database\Seeders\ThemesTableSeeder;
class InstallCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'vsmov:install';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Install VsMov';
protected $progressBar;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->progressBar = $this->output->createProgressBar(18);
$this->progressBar->minSecondsBetweenRedraws(0);
$this->progressBar->maxSecondsBetweenRedraws(120);
$this->progressBar->setRedrawFrequency(1);
$this->progressBar->start();
$this->call('vendor:publish', [
'--provider' => 'Backpack\CRUD\BackpackServiceProvider',
'--tag' => 'config',
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('vendor:publish', [
'--provider' => 'Backpack\CRUD\BackpackServiceProvider',
'--tag' => 'config',
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('vendor:publish', [
'--provider' => 'Backpack\CRUD\BackpackServiceProvider',
'--tag' => 'public',
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('vendor:publish', [
'--provider' => 'Backpack\CRUD\BackpackServiceProvider',
'--tag' => 'gravatar',
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('migrate', $this->option('no-interaction') ? ['--no-interaction' => true] : []);
$this->progressBar->advance();
$this->newLine(1);
$this->call('backpack:publish-middleware');
$this->progressBar->advance();
$this->newLine(1);
$this->call('vendor:publish', [
'--tag' => 'cms_menu_content',
'--force' => true
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('vendor:publish', [
'--tag' => 'players',
]);
$this->progressBar->advance();
$this->newLine(1);
$this->installCKfinder();
$this->progressBar->advance();
$this->newLine(1);
$this->call('db:seed', [
'class' => SettingsTableSeeder::class,
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('db:seed', [
'class' => CatalogsTableSeeder::class,
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('db:seed', [
'class' => MenusTableSeeder::class,
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('db:seed', [
'class' => PermissionsSeeder::class,
]);
$this->progressBar->advance();
$this->newLine(1);
$this->progressBar->finish();
$this->newLine(1);
$this->info('VsMov installation finished.');
return 0;
}
protected function installCKfinder()
{
$this->call('ckfinder:download');
$this->call('vendor:publish', [
'--tag' => 'ckfinder-assets',
]);
$this->progressBar->advance();
$this->newLine(1);
$this->call('vendor:publish', [
'--tag' => 'ckfinder-config',
]);
$this->call('storage:link');
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Vsmov\Core\Contracts;
interface HasUrlInterface
{
public function getUrl();
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Vsmov\Core\Contracts;
interface SeoInterface
{
public function generateSeoTags();
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Vsmov\Core\Contracts;
interface TaxonomyInterface extends HasUrlInterface
{
}

View File

@@ -0,0 +1,93 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\ActorRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Actor;
/**
* Class ActorCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class ActorCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Actor::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/actor');
CRUD::setEntityNameStrings('actor', 'actors');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Actor::class);
CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']);
CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']);
CRUD::addColumn(['name' => 'gender', 'label' => 'Giới tính', 'type' => 'text']);
CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Actor::class);
CRUD::setValidation(ActorRequest::class);
CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']);
CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']);
CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']);
CRUD::addField([
'name' => 'gender',
'label' => "Giới tính",
'type' => 'select_from_array',
'options' => ['male' => 'Nam', 'female' => 'Nữ', 'other' => 'Khác'],
'allows_null' => false,
'default' => 'one',
],);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->model);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Illuminate\Routing\Controller;
use Vsmov\Core\Models\Movie;
use Vsmov\Core\Models\Episode;
use Vsmov\Core\Models\Theme;
use Vsmov\Core\Models\User;
class AdminController extends Controller
{
protected $data = []; // the information we send to the view
/**
* Create a new controller instance.
*/
public function __construct()
{
$this->middleware(backpack_middleware());
}
/**
* Show the admin dashboard.
*
* @return \Illuminate\Http\Response
*/
public function dashboard()
{
$this->data['title'] = trans('backpack::base.dashboard'); // set the page title
$this->data['breadcrumbs'] = [
trans('backpack::crud.admin') => backpack_url('dashboard'),
trans('backpack::base.dashboard') => false,
];
$this->data['count_movies'] = Movie::count();
$this->data['count_episodes'] = Episode::count();
$this->data['count_episodes_error'] = Episode::where('has_report', true)->count();
$this->data['count_themes'] = Theme::count();
$this->data['count_users'] = User::count();
$this->data['top_view_day'] = Movie::orderBy('view_day', 'desc')->limit(15)->get();
$this->data['top_view_week'] = Movie::orderBy('view_week', 'desc')->limit(15)->get();
$this->data['top_view_month'] = Movie::orderBy('view_month', 'desc')->limit(15)->get();
return view(backpack_view('dashboard'), $this->data);
}
/**
* Redirect to the dashboard.
*
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
*/
public function redirect()
{
// The '/admin' route is not to be used as a page, because it breaks the menu's active state.
return redirect(backpack_url('dashboard'));
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\CatalogRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Catalog;
/**
* Class CatalogCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class CatalogCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Catalog::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/catalog');
CRUD::setEntityNameStrings('catalog', 'catalogs');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Catalog::class);
CRUD::addButtonFromModelFunction('line', 'open_view', 'openView', 'beginning');
CRUD::column('name')->label('Tên')->type('text');
CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text');
CRUD::column('paginate')->label('Item per page')->type('number');
CRUD::column('value')->label('Value')->type('text');
CRUD::column('seo_title')->label('SEO Title')->type('text');
CRUD::column('seo_des')->label('SEO Description')->type('text');
CRUD::column('seo_key')->label('SEO Keyword')->type('text');
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Catalog::class);
CRUD::setValidation(CatalogRequest::class);
CRUD::field('name')->label('Tên')->type('text');
CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text');
CRUD::field('paginate')->label('Paginate')->hint('Item per page')->type('number');
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');
CRUD::field('seo_title')->label('SEO Title')->type('text');
CRUD::field('seo_des')->label('SEO Description')->type('textarea');
CRUD::field('seo_key')->label('SEO Keyword')->type('text');
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\CategoryRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Category;
/**
* Class CategoryCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class CategoryCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Category::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/category');
CRUD::setEntityNameStrings('category', 'categories');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Category::class);
CRUD::column('name')->label('Tên')->type('text');
CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text');
CRUD::column('seo_title')->label('SEO Title')->type('text');
CRUD::column('seo_des')->label('SEO Description')->type('text');
CRUD::column('seo_key')->label('SEO Keyword')->type('text');
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Category::class);
CRUD::setValidation(CategoryRequest::class);
CRUD::field('name')->label('Tên')->type('text');
CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text');
CRUD::field('seo_title')->label('SEO Title')->type('text');
CRUD::field('seo_des')->label('SEO Description')->type('textarea');
CRUD::field('seo_key')->label('SEO Keyword')->type('text');
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\DirectorRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Director;
/**
* Class DirectorCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class DirectorCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Director::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/director');
CRUD::setEntityNameStrings('director', 'directors');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Director::class);
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']);
CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']);
CRUD::addColumn(['name' => 'gender', 'label' => 'Giới tính', 'type' => 'text']);
CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Director::class);
CRUD::setValidation(DirectorRequest::class);
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']);
CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']);
CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']);
CRUD::addField([
'name' => 'gender',
'label' => "Giới tính",
'type' => 'select_from_array',
'options' => ['male' => 'Nam', 'female' => 'Nữ', 'other' => 'Khác'],
'allows_null' => false,
'default' => 'one',
],);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
}

View File

@@ -0,0 +1,120 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Illuminate\Http\Request;
use Vsmov\Core\Models\Episode;
/**
* Class EpisodeCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class EpisodeCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation {
store as backpackStore;
}
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation {
update as backpackUpdate;
}
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
use \Vsmov\Core\Traits\Operations\BulkDeleteOperation {
bulkDelete as traitBulkDelete;
}
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Episode::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/episode');
CRUD::setEntityNameStrings('Episode', 'episodes');
$this->crud->addButtonFromModelFunction('line', 'open_episode', 'openEpisode', 'beginning');
$this->crud->denyAccess('create');
$this->crud->denyAccess('delete');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Episode::class);
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number','tab'=>'Thông tin phim']);
*/
$this->crud->enableExportButtons();
$this->crud->addClause('where', 'has_report', true);
CRUD::addColumn([
'name' => 'movie', 'label' => 'Phim', 'type' => 'relationship',
'searchLogic' => function ($query, $column, $searchTerm) {
$query->orWhereHas('movie', function ($movie) use ($searchTerm) {
$movie->where('name', 'like', '%' . $searchTerm . '%')
->orWhere('origin_name', 'like', '%' . $searchTerm . '%');
});
}
]);
CRUD::addColumn(['name' => 'name', 'label' => 'Tập', 'type' => 'text']);
CRUD::addColumn(['name' => 'type', 'label' => 'Type', 'type' => 'text']);
CRUD::addColumn(['name' => 'link', 'label' => 'Link', 'type' => 'textarea']);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
abort(404);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
CRUD::addField(['name' => 'type', 'label' => 'Type', 'type' => 'select_from_array', 'options' => config('vsmov.episodes.types')]);
CRUD::addField(['name' => 'link', 'label' => 'Nguồn phát', 'type' => 'url']);
CRUD::addField(['name' => 'has_report', 'label' => 'Đánh dấu đang lỗi', 'type' => 'checkbox']);
CRUD::addField(['name' => 'report_message', 'label' => 'Report message', 'type' => 'textarea']);
}
public function bulkDelete()
{
$this->crud->hasAccessOrFail('bulkDelete');
$entries = request()->input('entries', []);
$deletedEntries = [];
foreach ($entries as $key => $id) {
if ($entry = $this->crud->model->find($id)) {
$deletedEntries[] = $entry->update(['has_report' => 0, 'report_message' => '']);
}
}
return $deletedEntries;
}
}

View File

@@ -0,0 +1,126 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\CoreHttp\Requests\MenuRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Menu;
/**
* Class MenuCrudController
* @package Vsmov\CoreHttp\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class MenuCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ReorderOperation;
use \Vsmov\Core\Traits\Operations\BulkDeleteOperation {
bulkDelete as traitBulkDelete;
}
public function setup()
{
$this->crud->setModel(Menu::class);
$this->crud->setRoute(config('backpack.base.route_prefix') . '/menu');
$this->crud->setEntityNameStrings('menu item', 'menu items');
$this->crud->enableReorder('name', 2);
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Menu::class);
$this->crud->addColumn([
'name' => 'name',
'label' => 'Label',
]);
$this->crud->addColumn([
'label' => 'Parent',
'type' => 'select',
'name' => 'parent_id',
'entity' => 'parent',
'attribute' => 'name',
'model' => Menu::class,
]);
$this->crud->addColumn([
'name' => 'link',
'label' => 'Link',
'type' => 'url',
]);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Menu::class);
$this->crud->addField([
'name' => 'name',
'label' => 'Label',
]);
$this->crud->addField([
'label' => 'Parent',
'type' => 'select',
'name' => 'parent_id',
'entity' => 'parent',
'attribute' => 'name',
Menu::class
]);
$this->crud->addField([
'name' => ['type', 'link', 'internal_link'],
'label' => 'Type',
'type' => 'page_or_link',
]);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
public function bulkDelete()
{
$this->crud->hasAccessOrFail('bulkDelete');
$entries = request()->input('entries', []);
$deletedEntries = [];
foreach ($entries as $key => $id) {
if ($entry = $this->crud->model->find($id)) {
$deletedEntries[] = $entry->delete();
}
}
return $deletedEntries;
}
}

View File

@@ -0,0 +1,409 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\MovieRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Vsmov\Core\Models\Actor;
use Vsmov\Core\Models\Director;
use Vsmov\Core\Models\Movie;
use Vsmov\Core\Models\Region;
use Vsmov\Core\Models\Studio;
use Vsmov\Core\Models\Category;
use Vsmov\Core\Models\Tag;
/**
* Class MovieCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class MovieCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation {
store as backpackStore;
}
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation {
update as backpackUpdate;
}
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation {
destroy as traitDestroy;
}
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
use \Vsmov\Core\Traits\Operations\BulkDeleteOperation {
bulkDelete as traitBulkDelete;
}
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Movie::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/movie');
CRUD::setEntityNameStrings('movie', 'movies');
CRUD::setCreateView('vsmov::movies.create',);
CRUD::setUpdateView('vsmov::movies.edit',);
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Movie::class);
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number','tab'=>'Thông tin phim']);
*/
$this->crud->addFilter([
'name' => 'status',
'type' => 'select2',
'label' => 'Tình trạng'
], function () {
return [
'trailer' => 'Sắp chiếu',
'ongoing' => 'Đang chiếu',
'completed' => 'Hoàn thành'
];
}, function ($val) {
$this->crud->addClause('where', 'status', $val);
});
$this->crud->addFilter([
'name' => 'type',
'type' => 'select2',
'label' => 'Định dạng'
], function () {
return [
'single' => 'Phim lẻ',
'series' => 'Phim bộ'
];
}, function ($val) {
$this->crud->addClause('where', 'type', $val);
});
$this->crud->addFilter([
'name' => 'category_id',
'type' => 'select2',
'label' => 'Thể loại'
], function () {
return Category::all()->pluck('name', 'id')->toArray();
}, function ($value) { // if the filter is active
$this->crud->query = $this->crud->query->whereHas('categories', function ($query) use ($value) {
$query->where('id', $value);
});
});
$this->crud->addFilter([
'name' => 'region_id',
'type' => 'select2',
'label' => 'Quốc gia'
], function () {
return Region::all()->pluck('name', 'id')->toArray();
}, function ($value) { // if the filter is active
$this->crud->query = $this->crud->query->whereHas('regions', function ($query) use ($value) {
$query->where('id', $value);
});
});
$this->crud->addFilter([
'name' => 'other',
'type' => 'select2',
'label' => 'Thông tin'
], function () {
return [
'thumb_url-' => 'Thiếu ảnh thumb',
'poster_url-' => 'Thiếu ảnh poster',
'trailer_url-' => 'Thiếu trailer',
'language-vietsub' => 'Vietsub',
'language-thuyết minh' => 'Thuyết minh',
'language-lồng tiếng' => 'Lồng tiếng',
];
}, function ($values) {
$value = explode("-", $values);
$field = $value[0];
$val = $value[1];
if ($field === 'language') {
$this->crud->query->where($field, 'like', '%' . $val . '%');
} else {
$this->crud->query->where($field, '')->orWhere($field, NULL)->orWhere($field, 'like', '%img.vsmov%')->orWhere($field, 'like', '%img.hiephanhthienha%');
}
});
$this->crud->addFilter(
[
'type' => 'simple',
'name' => 'is_recommended',
'label' => 'Đề cử'
],
false,
function () {
$this->crud->addClause('where', 'is_recommended', true);
}
);
$this->crud->addFilter(
[
'type' => 'simple',
'name' => 'is_shown_in_theater',
'label' => 'Chiếu rạp'
],
false,
function () {
$this->crud->addClause('where', 'is_shown_in_theater', true);
}
);
CRUD::addButtonFromModelFunction('line', 'open_view', 'openView', 'beginning');
CRUD::addColumn([
'name' => 'name',
'origin_name' => 'origin_name',
'publish_year' => 'publish_year',
'status' => 'status',
'movie_type' => 'type',
'episode_current' => 'episode_current',
'label' => 'Thông tin',
'type' => 'view',
'view' => 'vsmov::movies.columns.column_movie_info',
'searchLogic' => function ($query, $column, $searchTerm) {
$query->where('name', 'like', '%' . $searchTerm . '%')->orWhere('origin_name', 'like', '%' . $searchTerm . '%');
// $query->whereRaw("MATCH(name, origin_name) AGAINST(? IN BOOLEAN MODE)", [$searchTerm]);
}
]);
CRUD::addColumn([
'name' => 'thumb_url', 'label' => 'Ảnh thumb', 'type' => 'image',
'height' => '100px',
'width' => '68px',
]);
CRUD::addColumn(['name' => 'categories', 'label' => 'Thể loại', 'type' => 'relationship',]);
CRUD::addColumn(['name' => 'regions', 'label' => 'Khu vực', 'type' => 'relationship',]);
CRUD::addColumn(['name' => 'updated_at', 'label' => 'Cập nhật lúc', 'type' => 'datetime', 'format' => 'DD/MM/YYYY HH:mm:ss']);
// CRUD::addColumn(['name' => 'user_name', 'label' => 'Cập nhật bởi', 'type' => 'text',]);
CRUD::addColumn(['name' => 'view_total', 'label' => 'Lượt xem', 'type' => 'number',]);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Movie::class);
CRUD::setValidation(MovieRequest::class);
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
CRUD::addField(['name' => 'name', 'label' => 'Tên phim', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-6'
], 'attributes' => ['placeholder' => 'Tên'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'origin_name', 'label' => 'Tên gốc', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-6'
], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text', 'tab' => 'Thông tin phim']);
CRUD::addField([
'name' => 'thumb_url', 'label' => 'Ảnh Thumb', 'type' => 'ckfinder', 'preview' => ['width' => 'auto', 'height' => '340px'], 'tab' => 'Thông tin phim'
]);
CRUD::addField(['name' => 'poster_url', 'label' => 'Ảnh Poster', 'type' => 'ckfinder', 'preview' => ['width' => 'auto', 'height' => '340px'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'content', 'label' => 'Nội dung', 'type' => 'summernote', 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'notify', 'label' => 'Thông báo / ghi chú', 'type' => 'text', 'attributes' => ['placeholder' => 'Tuần này hoãn chiếu'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'showtimes', 'label' => 'Lịch chiếu phim', 'type' => 'text', 'attributes' => ['placeholder' => '21h tối hàng ngày'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'trailer_url', 'label' => 'Trailer Youtube URL', 'type' => 'text', 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'episode_time', 'label' => 'Thời lượng tập phim', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-4'
], 'attributes' => ['placeholder' => '45 phút'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'episode_current', 'label' => 'Tập phim hiện tại', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-4'
], 'attributes' => ['placeholder' => '5'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'episode_total', 'label' => 'Tổng số tập phim', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-4'
], 'attributes' => ['placeholder' => '12'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'language', 'label' => 'Ngôn ngữ', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-4'
], 'attributes' => ['placeholder' => 'Tiếng Việt'], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'quality', 'label' => 'Chất lượng', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-4'
], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'publish_year', 'label' => 'Năm xuất bản', 'type' => 'text', 'wrapperAttributes' => [
'class' => 'form-group col-md-4'
], 'tab' => 'Thông tin phim']);
CRUD::addField(['name' => 'type', 'label' => 'Định dạng', 'type' => 'radio', 'options' => ['single' => 'Phim lẻ', 'series' => 'Phim bộ'], 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'status', 'label' => 'Tình trạng', 'type' => 'radio', 'options' => ['trailer' => 'Sắp chiếu', 'ongoing' => 'Đang chiếu', 'completed' => 'Hoàn thành'], 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'categories', 'label' => 'Thể loại', 'type' => 'checklist', 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'regions', 'label' => 'Khu vực', 'type' => 'checklist', 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'directors', 'label' => 'Đạo diễn', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'actors', 'label' => 'Diễn viên', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'tags', 'label' => 'Tags', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']);
CRUD::addField(['name' => 'studios', 'label' => 'Studios', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']);
CRUD::addField([
'name' => 'episodes',
'type' => 'view',
'view' => 'vsmov::movies.inc.episode',
'tab' => 'Danh sách tập phim'
],);
CRUD::addField(['name' => 'update_handler', 'label' => 'Trình cập nhật', 'type' => 'select_from_array', 'options' => collect(config('vsmov.updaters', []))->pluck('name', 'handler')->toArray(), 'tab' => 'Cập nhật']);
CRUD::addField(['name' => 'update_identity', 'label' => 'ID cập nhật', 'type' => 'text', 'tab' => 'Cập nhật']);
CRUD::addField(['name' => 'is_shown_in_theater', 'label' => 'Phim chiếu rạp', 'type' => 'boolean', 'tab' => 'Khác']);
CRUD::addField(['name' => 'is_copyright', 'label' => 'Có bản quyền phim', 'type' => 'boolean', 'tab' => 'Khác']);
CRUD::addField(['name' => 'is_sensitive_content', 'label' => 'Cảnh báo nội dung người lớn', 'type' => 'boolean', 'tab' => 'Khác']);
CRUD::addField(['name' => 'is_recommended', 'label' => 'Đề cử', 'type' => 'boolean', 'tab' => 'Khác']);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
CRUD::addField(['name' => 'timestamps', 'label' => 'Cập nhật thời gian', 'type' => 'checkbox', 'tab' => 'Cập nhật']);
}
public function store(Request $request)
{
$this->getTaxonamies($request);
return $this->backpackStore();
}
public function update(Request $request)
{
$this->getTaxonamies($request);
return $this->backpackUpdate();
}
protected function getTaxonamies(Request $request)
{
$actors = request('actors', []);
$directors = request('directors', []);
$tags = request('tags', []);
$studios = request('studios', []);
$actor_ids = [];
foreach ($actors as $actor) {
$actor_ids[] = Actor::firstOrCreate([
'name_md5' => md5($actor)
], [
'name' => $actor
])->id;
}
$director_ids = [];
foreach ($directors as $director) {
$director_ids[] = Director::firstOrCreate([
'name_md5' => md5($director)
], [
'name' => $director
])->id;
}
$tag_ids = [];
foreach ($tags as $tag) {
$tag_ids[] = Tag::firstOrCreate([
'name_md5' => md5($tag)
], [
'name' => $tag
])->id;
}
$studio_ids = [];
foreach ($studios as $studio) {
$studio_ids[] = Studio::firstOrCreate([
'name_md5' => md5($studio)
], [
'name' => $studio
])->id;
}
$request['actors'] = $actor_ids;
$request['directors'] = $director_ids;
$request['tags'] = $tag_ids;
$request['studios'] = $studio_ids;
}
// protected function setupDeleteOperation()
// {
// $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
// }
public function deleteImage($movie)
{
// Delete images
if ($movie->thumb_url && !filter_var($movie->thumb_url, FILTER_VALIDATE_URL) && file_exists(public_path($movie->thumb_url))) {
unlink(public_path($movie->thumb_url));
}
if ($movie->poster_url && !filter_var($movie->poster_url, FILTER_VALIDATE_URL) && file_exists(public_path($movie->poster_url))) {
unlink(public_path($movie->poster_url));
}
return true;
}
public function destroy($id)
{
$this->crud->hasAccessOrFail('delete');
$movie = Movie::find($id);
$this->deleteImage($movie);
// get entry ID from Request (makes sure its the last ID for nested resources)
$id = $this->crud->getCurrentEntryId() ?? $id;
$res = $this->crud->delete($id);
if ($res) {
}
return $res;
}
public function bulkDelete()
{
$this->crud->hasAccessOrFail('bulkDelete');
$entries = request()->input('entries', []);
$deletedEntries = [];
foreach ($entries as $key => $id) {
if ($entry = $this->crud->model->find($id)) {
$this->deleteImage($entry);
$deletedEntries[] = $entry->delete();
}
}
return $deletedEntries;
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Illuminate\Support\Facades\Route;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Illuminate\Support\Facades\Artisan;
use Vsmov\Core\Models\Plugin;
use Prologue\Alerts\Facades\Alert;
class PluginController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(Plugin::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/plugin');
CRUD::setEntityNameStrings('plugin', 'plugins');
$this->crud->denyAccess('update');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
if (!backpack_user()->hasPermissionTo('Browse plugin')) {
abort(403);
}
CRUD::column('name')->label('Plugin')->type('text');
CRUD::column('version')->label('Version')->type('text');
$this->crud->addButtonFromModelFunction('line', 'editBtn', 'editBtn', 'beginning');
$this->crud->addButtonFromModelFunction('line', 'openBtn', 'openBtn', 'beginning');
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$plugin = $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId());
$fields = $plugin->options;
CRUD::addField(['name' => 'fields', 'type' => 'hidden', 'value' => collect($fields)->implode('name', ',')]);
foreach ($fields as $field) {
CRUD::addField($field);
}
}
public function show($id)
{
/** @var Plugin */
$plugin = Plugin::findOrFail($id);
return $plugin->open();
}
/**
* Show the form for editing the specified resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function edit($id)
{
if (!backpack_user()->hasPermissionTo('Update plugin')) {
abort(403);
}
$id = $this->crud->getCurrentEntryId() ?? $id;
$this->data['entry'] = $this->crud->getEntryWithLocale($id);
$this->crud->setOperationSetting('fields', $this->getUpdateFields());
$this->data['crud'] = $this->crud;
$this->data['saveAction'] = $this->crud->getSaveAction();
$this->data['title'] = $this->crud->getTitle() ?? trans('backpack::crud.edit') . ' ' . $this->crud->entity_name;
$this->data['id'] = $id;
// load the view from /resources/views/vendor/backpack/crud/ if it exists, otherwise load the one in the package
return view($this->crud->getEditView(), $this->data);
}
/**
* Update the specified resource in the database.
*
* @return array|\Illuminate\Http\RedirectResponse
*/
public function update($plugin)
{
if (!backpack_user()->hasPermissionTo('Update plugin')) {
abort(403);
}
// execute the FormRequest authorization and validation, if one is required
$request = $this->crud->validateRequest();
// register any Model Events defined on fields
$this->crud->registerFieldEvents();
// update the row in the db
$item = $this->crud->update(
$request->get($this->crud->model->getKeyName()),
[
'value' => request()->only(explode(',', request('fields')))
]
);
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
Alert::success(trans('backpack::crud.update_success'))->flash();
return redirect(backpack_url('plugin'));
}
/**
* Get all fields needed for the EDIT ENTRY form.
*
* @param int $id The id of the entry that is being edited.
* @return array The fields with attributes, fake attributes and values.
*/
public function getUpdateFields($id = false)
{
$fields = $this->crud->fields();
$entry = ($id != false) ? $this->getEntry($id) : $this->crud->getCurrentEntry();
$options = $entry->value ?? [];
foreach ($options as $k => $v) {
$fields[$k]['value'] = $v;
}
if (!array_key_exists('id', $fields)) {
$fields['id'] = [
'name' => $entry->getKeyName(),
'value' => $entry->getKey(),
'type' => 'hidden',
];
}
return $fields;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Prologue\Alerts\Facades\Alert;
class QuickActionController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function delete_cache()
{
Artisan::call('optimize:clear');
Alert::success("Xóa cache thành công")->flash();
return back();
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\RegionRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Region;
/**
* Class RegionCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class RegionCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Region::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/region');
CRUD::setEntityNameStrings('region', 'regions');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Region::class);
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->label('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
CRUD::column('name')->label('Tên khu vực')->type('text');
CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text');
CRUD::column('seo_title')->label('SEO Title')->type('text');
CRUD::column('seo_des')->label('SEO Description')->type('text');
CRUD::column('seo_key')->label('SEO Keyword')->type('text');
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Region::class);
CRUD::setValidation(RegionRequest::class);
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->label('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
CRUD::field('name')->label('Tên khu vực')->type('text');
CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text');
CRUD::field('seo_title')->label('SEO Title')->type('text');
CRUD::field('seo_des')->label('SEO Description')->type('textarea');
CRUD::field('seo_key')->label('SEO Keyword')->type('text');
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Backpack\Settings\app\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\URL as LARURL;
use Illuminate\Support\Facades\File;
use Carbon\Carbon;
use Vsmov\Core\Models\Actor;
use Vsmov\Core\Models\Catalog;
use Vsmov\Core\Models\Category;
use Vsmov\Core\Models\Director;
use Vsmov\Core\Models\Movie;
use Vsmov\Core\Models\Region;
use Vsmov\Core\Models\Studio;
use Vsmov\Core\Models\Tag;
use Prologue\Alerts\Facades\Alert;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\SitemapIndex;
use Spatie\Sitemap\Tags\Url;
class SiteMapController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setRoute(config('backpack.base.route_prefix') . '/sitemap');
CRUD::setEntityNameStrings('site map', 'site map');
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupCreateOperation()
{
CRUD::addField(['name' => 'sitemap', 'type' => 'custom_html', 'value' => 'Sitemap sẽ được lưu tại đường dẫn: <i>' . url('/sitemap.xml') . '</i>']);
$this->crud->addSaveAction([
'name' => 'save_and_new',
'redirect' => function ($crud, $request, $itemId) {
return $crud->route;
},
'button_text' => 'Tạo sitemap',
]);
$this->crud->setOperationSetting('showSaveActionChange', false);
}
public function render_styles()
{
$xml = view('vsmov::sitemap/styles', [
'title' => Setting::get('site_homepage_title'),
'domain' => LARURL::to('/')
])->render();
file_put_contents(public_path('main-sitemap.xsl'), $xml);
return;
}
public function add_styles($file_name)
{
$path = public_path($file_name);
if(file_exists($path)) {
$content = file_get_contents($path);
$content = str_replace('?'.'>', '?'.'>'.'<'.'?'.'xml-stylesheet type="text/xsl" href="'. LARURL::to('/') .'/main-sitemap.xsl"?'.'>', $content);
file_put_contents($path, $content);
}
}
public function store(Request $request)
{
$this->render_styles();
if (!File::isDirectory('sitemap')) File::makeDirectory('sitemap', 0777, true, true);
$sitemap_index = SitemapIndex::create();
$sitemap_page = Sitemap::create();
$sitemap_page->add(Url::create('/')
->setLastModificationDate(now())
->setChangeFrequency(Url::CHANGE_FREQUENCY_HOURLY)
->setPriority(1));
Catalog::chunkById(100, function ($catalogs) use ($sitemap_page) {
foreach ($catalogs as $catalog) {
$sitemap_page->add(
Url::create($catalog->getUrl())
->setLastModificationDate(now())
->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY)
->setPriority(0.9)
);
}
});
$sitemap_page->writeToFile(public_path('sitemap/page-sitemap.xml'));
$this->add_styles('sitemap/page-sitemap.xml');
$sitemap_index->add('sitemap/page-sitemap.xml');
$sitemap_categories = Sitemap::create();
Category::chunkById(100, function ($categoires) use ($sitemap_categories) {
foreach ($categoires as $category) {
$sitemap_categories->add(
Url::create($category->getUrl())
->setLastModificationDate(now())
->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY)
->setPriority(0.8)
);
}
});
$sitemap_categories->writeToFile(public_path('sitemap/categories-sitemap.xml'));
$this->add_styles('sitemap/categories-sitemap.xml');
$sitemap_index->add('sitemap/categories-sitemap.xml');
$sitemap_regions = Sitemap::create();
Region::chunkById(100, function ($regions) use ($sitemap_regions) {
foreach ($regions as $region) {
$sitemap_regions->add(
Url::create($region->getUrl())
->setLastModificationDate(now())
->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY)
->setPriority(0.8)
);
}
});
$sitemap_regions->writeToFile(public_path('sitemap/regions-sitemap.xml'));
$this->add_styles('sitemap/regions-sitemap.xml');
$sitemap_index->add('sitemap/regions-sitemap.xml');
$chunk = 0;
Movie::chunkById(200, function ($movies) use ($sitemap_index, &$chunk) {
$chunk++;
$sitemap_movies = null;
$sitemap_movies = Sitemap::create();
foreach ($movies as $movie) {
$sitemap_movies->add(
Url::create($movie->getUrl())
->setLastModificationDate($movie->updated_at)
->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY)
->setPriority(0.7)
);
}
$sitemap_movies->writeToFile(public_path("sitemap/movies-sitemap{$chunk}.xml"));
$this->add_styles("sitemap/movies-sitemap{$chunk}.xml");
$sitemap_index->add("sitemap/movies-sitemap{$chunk}.xml");
});
$sitemap_index->writeToFile(public_path('sitemap.xml'));
$this->add_styles("sitemap.xml");
Alert::success("Đã tạo thành công sitemap tại thư mục public")->flash();
return back();
}
}

View File

@@ -0,0 +1,97 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Vsmov\Core\Requests\StudioRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Studio;
/**
* Class StudioCrudController
* @package Vsmov\Core\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class StudioCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Studio::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/studio');
CRUD::setEntityNameStrings('studio', 'studios');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Studio::class);
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']);
CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']);
CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Studio::class);
CRUD::setValidation(StudioRequest::class);
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']);
CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']);
CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Vsmov\Core\Models\Tag;
use Vsmov\Core\Requests\TagRequest;
/**
* Class TagCrudController
* @package App\Http\Controllers\Admin
* @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class TagCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(\Vsmov\Core\Models\Tag::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/tag');
CRUD::setEntityNameStrings('tag', 'tags');
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->authorize('browse', Tag::class);
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
CRUD::addColumn(['name' => 'name', 'type' => 'text']);
CRUD::addColumn(['name' => 'slug', 'type' => 'text']);
}
/**
* Define what happens when the Create operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-create
* @return void
*/
protected function setupCreateOperation()
{
$this->authorize('create', Tag::class);
CRUD::setValidation(TagRequest::class);
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
CRUD::addField(['name' => 'name', 'type' => 'text']);
CRUD::addField(['name' => 'slug', 'type' => 'text']);
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
$this->setupCreateOperation();
}
protected function setupDeleteOperation()
{
$this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()));
}
}

View File

@@ -0,0 +1,252 @@
<?php
namespace Vsmov\Core\Controllers\Admin;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Illuminate\Support\Facades\Route;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
use Illuminate\Http\Request;
use Vsmov\Core\Models\Theme;
use Prologue\Alerts\Facades\Alert;
class ThemeManagementController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
*/
public function setup()
{
CRUD::setModel(Theme::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/theme');
CRUD::setEntityNameStrings('theme', 'themes');
$this->crud->denyAccess('update');
}
/**
* Define which routes are needed for this operation.
*
* @param string $name Name of the current entity (singular). Used as first URL segment.
* @param string $routeName Prefix of the route name.
* @param string $controller Name of the current CrudController.
*/
protected function setupManagementRoutes($segment, $routeName, $controller)
{
Route::post($segment . '/{id}/active', [
'as' => $routeName . '.active',
'uses' => $controller . '@active',
'operation' => 'update',
]);
Route::post($segment . '/{id}/reset', [
'as' => $routeName . '.reset',
'uses' => $controller . '@reset',
'operation' => 'update',
]);
Route::post($segment . '/{id}/delete', [
'as' => $routeName . '.delete',
'uses' => $controller . '@delete',
'operation' => 'update',
]);
}
/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
foreach (config('themes', []) as $key => $theme) {
Theme::updateOrCreate([
'name' => $key,
], [
'display_name' => $theme['display_name'] ?? $theme['name'],
'preview_image' => $theme['preview_image'] ?: '',
'author' => $theme['author'] ?: '',
'package_name' => $theme['package_name'],
]);
}
CRUD::addColumn(['name' => 'display_name', 'type' => 'text']);
CRUD::addColumn(['name' => 'preview_image', 'type' => 'image']);
CRUD::addColumn(['name' => 'version', 'type' => 'text']);
$this->crud->addButtonFromModelFunction('line', 'editBtn', 'editBtn', 'beginning');
$this->crud->addButtonFromModelFunction('line', 'resetBtn', 'resetBtn', 'beginning');
$this->crud->addButtonFromModelFunction('line', 'activeBtn', 'activeBtn', 'beginning');
$this->crud->addButtonFromModelFunction('line', 'deleteBtn', 'deleteBtn', '');
}
/**
* Define what happens when the Update operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-update
* @return void
*/
protected function setupUpdateOperation()
{
$theme = $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId());
$fields = $theme->options;
CRUD::addField(['name' => 'fields', 'type' => 'hidden', 'value' => collect($fields)->implode('name', ',')]);
foreach ($fields as $field) {
CRUD::addField($field);
}
}
public function delete(Request $request, $id)
{
if (!backpack_user()->hasPermissionTo('Customize theme')) {
abort(403);
}
$theme = Theme::fromCache()->find($id);
if (is_null($theme)) {
Alert::warning("Không tìm thấy dữ liệu giao diện")->flash();
return redirect(backpack_url('theme'));
}
// delete row from db
$theme->delete();
Alert::success("Xóa giao diện thành công!")->flash();
return redirect(backpack_url('theme'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Contracts\View\View
*/
public function edit($id)
{
if (!backpack_user()->hasPermissionTo('Customize theme')) {
abort(403);
}
$id = $this->crud->getCurrentEntryId() ?? $id;
$this->data['entry'] = $this->crud->getEntryWithLocale($id);
$this->crud->setOperationSetting('fields', $this->getUpdateFields());
$this->data['crud'] = $this->crud;
$this->data['saveAction'] = $this->crud->getSaveAction();
$this->data['title'] = $this->crud->getTitle() ?? trans('backpack::crud.edit') . ' ' . $this->crud->entity_name;
$this->data['id'] = $id;
// load the view from /resources/views/vendor/backpack/crud/ if it exists, otherwise load the one in the package
return view($this->crud->getEditView(), $this->data);
}
/**
* Update the specified resource in the database.
*
* @return array|\Illuminate\Http\RedirectResponse
*/
public function update()
{
if (!backpack_user()->hasPermissionTo('Customize theme')) {
abort(403);
}
// execute the FormRequest authorization and validation, if one is required
$request = $this->crud->validateRequest();
// register any Model Events defined on fields
$this->crud->registerFieldEvents();
// update the row in the db
$item = $this->crud->update(
$request->get($this->crud->model->getKeyName()),
[
'value' => request()->only(explode(',', request('fields')))
]
);
$this->data['entry'] = $this->crud->entry = $item;
Alert::success(trans('backpack::crud.update_success'))->flash();
return redirect(backpack_url('theme'));
}
/**
* Get all fields needed for the EDIT ENTRY form.
*
* @param int $id The id of the entry that is being edited.
* @return array The fields with attributes, fake attributes and values.
*/
public function getUpdateFields($id = false)
{
$fields = $this->crud->fields();
$entry = ($id != false) ? $this->getEntry($id) : $this->crud->getCurrentEntry();
$options = $entry->value ?? [];
foreach ($options as $k => $v) {
$fields[$k]['value'] = $v;
}
if (!array_key_exists('id', $fields)) {
$fields['id'] = [
'name' => $entry->getKeyName(),
'value' => $entry->getKey(),
'type' => 'hidden',
];
}
return $fields;
}
public function reset(Request $request, $id)
{
$theme = Theme::fromCache()->find($id);
if (is_null($theme)) {
Alert::warning("Không tìm thấy dữ liệu giao diện")->flash();
return redirect(backpack_url('theme'));
}
$fields = collect($theme->options);
$theme->update([
'value' => $fields->pluck('value', 'name')->toArray()
]);
Alert::success(trans('backpack::crud.update_success'))->flash();
return redirect(backpack_url('theme'));
}
public function active($id)
{
$theme = Theme::fromCache()->find($id);
if (is_null($theme)) {
Alert::warning("Không tìm thấy dữ liệu giao diện")->flash();
return redirect(backpack_url('theme'));
}
$res = $theme->active();
if ($res) {
Alert::success(trans('backpack::crud.update_success'))->flash();
} else {
Alert::error(trans('backpack::crud.update_failed'))->flash();
}
return redirect(backpack_url('theme'));
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Vsmov\Core\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

23
src/Helpers/helpers.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
use Backpack\Settings\app\Models\Setting;
use Illuminate\Support\Facades\Cache;
use Vsmov\Core\Models\Theme;
if (!function_exists('get_theme_option')) {
function get_theme_option($key, $fallback = null)
{
$theme = Cache::remember('site.theme.active', setting('site_cache_ttl', 5 * 60), function () {
return Theme::getActivatedTheme();
});
if (is_null($theme)) return $fallback;
$props = collect(array_merge(
array_column($theme->options, 'value', 'name') ?? [],
is_array($theme->value) ? $theme->value : []
));
return $props[$key] ?? $fallback;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Vsmov\Core\Middleware;
use Closure;
use Illuminate\Http\Request;
class CKFinderAuth
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
config(['ckfinder.authentication' => function () {
return true;
}]);
return $next($request);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Vsmov\Core\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array<int, string>
*/
protected $except = [
'ckCsrfToken'
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Vsmov\Core\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
'ckfinder/*',
];
}

191
src/Models/Actor.php Normal file
View File

@@ -0,0 +1,191 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\HasDescription;
use Vsmov\Core\Traits\HasKeywords;
use Vsmov\Core\Traits\HasUniqueName;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Actor extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use Sluggable;
use HasUniqueName;
use HasFactory;
use HasCache;
use HasTitle;
use HasDescription;
use HasKeywords;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'actors';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_actors', '/dien-vien/{actor}');
if (strpos($site_routes, '{actor}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl()
{
$params = [];
$site_routes = setting('site_routes_actors', '/dien-vien/{actor}');
if (strpos($site_routes, '{actor}')) $params['actor'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('actors.movies.index', $params);
}
protected function titlePattern(): string
{
return Setting::get('site_actor_title', '');
}
protected function descriptionPattern(): string
{
return Setting::get('site_actor_des', '');
}
protected function keywordsPattern(): string
{
return Setting::get('site_actor_key', '');
}
public function generateSeoTags()
{
$seo_title = $this->getTitle();
$seo_des = Str::limit($this->getDescription(), 150, '...');
$seo_key = $this->getKeywords();
$movie_thumb_url = '';
$movie_poster_url = '';
$updated_at = '';
if(count($this->movies)) {
$movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url;
$movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url;
$updated_at = $this->movies->last()->updated_at;
}
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setSiteName($site_meta_siteName)
->setType('website')
->setTitle($seo_title, false)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $updated_at)
->addProperty('url', $getUrl)
->setDescription($seo_des)
->addImages([$movie_thumb_url, $movie_poster_url]);
TwitterCard::setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('WebPage')
->addValue('dateCreated', $updated_at)
->addValue('dateModified', $updated_at)
->addValue('datePublished', $updated_at)
->setDescription($seo_des)
->setImages([$movie_thumb_url, $movie_poster_url])
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $this->name,
'item' => $getUrl
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => "Trang " . (request()->get('page') ?: 1),
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movies()
{
return $this->belongsToMany(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

153
src/Models/Catalog.php Normal file
View File

@@ -0,0 +1,153 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Catalog extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use Sluggable;
use HasFactory;
use HasCache;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'catalogs';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_types', '/danh-sach/{type}');
if (strpos($site_routes, '{type}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl()
{
$params = [];
$site_routes = setting('site_routes_types', '/danh-sach/{type}');
if (strpos($site_routes, '{type}')) $params['type'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('types.movies.index', $params);
}
public function generateSeoTags()
{
$seo_title = $this->seo_title;
$seo_des = $this->seo_des;
$seo_key = $this->seo_key;
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setSiteName($site_meta_siteName)
->setType('website')
->setTitle($seo_title, false)
->addProperty('locale', 'vi-VN')
->addProperty('url', $getUrl)
->setDescription($seo_des);
TwitterCard::setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('summary')
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('WebPage')
->setDescription($seo_des)
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $this->name,
'item' => $getUrl
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => "Trang " . (request()->get('page') ?: 1),
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
public function openView($crud = false)
{
return '<a class="btn btn-sm btn-link" target="_blank" href="'.$this->getUrl().'" data-toggle="tooltip" title="View link"><i class="la la-link"></i> View</a>';
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

192
src/Models/Category.php Normal file
View File

@@ -0,0 +1,192 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\ActorLog;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\HasDescription;
use Vsmov\Core\Traits\HasKeywords;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Category extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use ActorLog;
use Sluggable;
use HasFactory;
use HasCache;
use HasTitle;
use HasDescription;
use HasKeywords;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'categories';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_category', '/the-loai/{category}');
if (strpos($site_routes, '{category}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl($withDomain = true)
{
$params = [];
$site_routes = setting('site_routes_category', '/the-loai/{category}');
if (strpos($site_routes, '{category}')) $params['category'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('categories.movies.index', $params, $withDomain);
}
protected function titlePattern(): string
{
return Setting::get('site_category_title', '');
}
protected function descriptionPattern(): string
{
return Setting::get('site_category_des', '');
}
protected function keywordsPattern(): string
{
return Setting::get('site_category_key', '');
}
public function generateSeoTags()
{
$seo_title = $this->seo_title ?: $this->getTitle();
$seo_des = Str::limit($this->seo_des ?: $this->getDescription(), 150, '...');
$seo_key = $this->seo_key ?: $this->getKeywords();
$movie_thumb_url = '';
$movie_poster_url = '';
$updated_at = '';
if(count($this->movies)) {
$movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url;
$movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url;
$updated_at = $this->movies->last()->updated_at;
}
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setSiteName($site_meta_siteName)
->setType('website')
->setTitle($seo_title, false)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $updated_at)
->addProperty('url', $getUrl)
->setDescription($seo_des)
->addImages([$movie_thumb_url,$movie_poster_url]);
TwitterCard::setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('WebPage')
->addValue('dateCreated', $updated_at)
->addValue('dateModified', $updated_at)
->addValue('datePublished', $updated_at)
->setDescription($seo_des)
->setImages([$movie_thumb_url,$movie_poster_url])
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $this->name,
'item' => $getUrl
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => "Trang " . (request()->get('page') ?: 1),
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movies()
{
return $this->belongsToMany(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

192
src/Models/Director.php Normal file
View File

@@ -0,0 +1,192 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\HasDescription;
use Vsmov\Core\Traits\HasKeywords;
use Vsmov\Core\Traits\HasUniqueName;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Director extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use Sluggable;
use HasUniqueName;
use HasFactory;
use HasCache;
use HasTitle;
use HasDescription;
use HasKeywords;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'directors';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_directors', '/dien-vien/{director}');
if (strpos($site_routes, '{director}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl()
{
$params = [];
$site_routes = setting('site_routes_directors', '/dien-vien/{director}');
if (strpos($site_routes, '{director}')) $params['director'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('directors.movies.index', $params);
}
protected function titlePattern(): string
{
return Setting::get('site_director_title', '');
}
protected function descriptionPattern(): string
{
return Setting::get('site_director_des', '');
}
protected function keywordsPattern(): string
{
return Setting::get('site_director_key', '');
}
public function generateSeoTags()
{
$seo_title = $this->getTitle();
$seo_des = Str::limit($this->getDescription(), 150, '...');
$seo_key = $this->getKeywords();
$movie_thumb_url = '';
$movie_poster_url = '';
$updated_at = '';
if(count($this->movies)) {
$movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url;
$movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url;
$updated_at = $this->movies->last()->updated_at;
}
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setSiteName($site_meta_siteName)
->setType('website')
->setTitle($seo_title, false)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $updated_at)
->addProperty('url', $getUrl)
->setDescription($seo_des)
->addImages([$movie_thumb_url, $movie_poster_url]);
TwitterCard::setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('WebPage')
->addValue('dateCreated', $updated_at)
->addValue('dateModified', $updated_at)
->addValue('datePublished', $updated_at)
->setDescription($seo_des)
->setImages([$movie_thumb_url, $movie_poster_url])
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $this->name,
'item' => $getUrl
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => "Trang " . (request()->get('page') ?: 1),
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movies()
{
return $this->belongsToMany(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

212
src/Models/Episode.php Normal file
View File

@@ -0,0 +1,212 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\HasUrlInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Episode extends Model implements Cacheable, HasUrlInterface, SeoInterface
{
use CrudTrait;
use HasFactory;
use HasCache;
use HasTitle;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'episodes';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public function getUrl()
{
$movie = Cache::remember("cache_movie_by_id:" . $this->movie_id, setting('site_cache_ttl', 5 * 60), function () {
return $this->movie;
});
$params = [];
$site_routes_movie = setting('site_routes_episode', '/phim/{movie}/{episode}-{id}');
if (strpos($site_routes_movie, '{movie}')) $params['movie'] = $movie->slug;
if (strpos($site_routes_movie, '{movie_id}')) $params['movie_id'] = $movie->id;
if (strpos($site_routes_movie, '{episode}')) $params['episode'] = $this->slug;
if (strpos($site_routes_movie, '{id}')) $params['id'] = $this->id;
return route('episodes.show', $params);
}
public function openEpisode($crud = false)
{
return '<a class="btn btn-sm btn-link" target="_blank" href="' . $this->getUrl() . '" data-toggle="tooltip" title="Just a demo custom button."><i class="fa fa-search"></i> Open it</a>';
}
protected function titlePattern(): string
{
return Setting::get('site_episode_watch_title', '');
}
public function generateSeoTags()
{
$movie_thumb_url = filter_var($this->movie->thumb_url, FILTER_VALIDATE_URL) ? $this->movie->thumb_url : request()->root() . $this->movie->thumb_url;
$movie_poster_url = filter_var($this->movie->poster_url, FILTER_VALIDATE_URL) ? $this->movie->poster_url : request()->root() . $this->movie->poster_url;
$movie_description = Str::limit(strip_tags($this->movie->content), 150, '...');
$episode_getUrl = $this->getUrl();
$getTitle = $this->getTitle();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($getTitle, false)
->setDescription($movie_description)
->addKeyword($this->movie->tags()->pluck('name')->toArray())
->addMeta('article:published_time', $this->updated_at->toW3CString(), 'property')
->addMeta('article:section', $this->movie->categories->pluck('name')->join(","), 'property')
->addMeta('article:tag', $this->movie->tags->pluck('name')->join(","), 'property')
->setCanonical($episode_getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setType('video.episode')
->setSiteName($site_meta_siteName)
->setTitle($getTitle, false)
->addProperty('locale', 'vi-VN')
->addProperty('url', $episode_getUrl)
->addProperty('updated_time', $this->movie->updated_at)
->setDescription($movie_description)
->addImages([$movie_thumb_url,$movie_poster_url])
->setVideoEpisode([
'actor' => $this->movie->actors->pluck('name')->join(","),
'director' => $this->movie->directors->pluck('name')->join(","),
'duration' => $this->movie->episode_time,
'release_date' => $this->created_at,
'tag' => $this->movie->tags->pluck('name')->join(", "),
'series' => 'video.tv_show'
]);
TwitterCard::setSite($site_meta_siteName)
->setTitle($getTitle, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($movie_description)
->setUrl($episode_getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->addValue('dateCreated', $this->created_at)
->addValue('dateModified', $this->updated_at)
->addValue('datePublished', $this->created_at)
->setTitle($getTitle, false)
->setType('Movie')
->setDescription($movie_description)
->setImages([$movie_thumb_url,$movie_poster_url])
->addValue('aggregateRating', [
'@type' => 'AggregateRating',
'bestRating' => "10",
'worstRating' => "1",
'ratingValue' => $this->movie->getRatingStar(),
'reviewCount' => $this->movie->getRatingCount()
])
->addValue('director', count($this->movie->directors) ? $this->movie->directors->map(function ($director) {
return ['@type'=> 'Person', 'name' => $director->name];
}) : "")
->addValue('actor', count($this->movie->actors) ? $this->movie->actors->map(function ($actor) {
return ['@type'=> 'Person', 'name' => $actor->name];
}) : "")
->setUrl($episode_getUrl);
// ->addValue($key, $value);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
foreach ($this->movie->regions as $item) {
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $item->name,
'item' => $item->getUrl(),
]);
}
foreach ($this->movie->categories as $item) {
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $item->name,
'item' => $item->getUrl(),
]);
}
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => $this->movie->name,
'item' => $this->movie->getUrl()
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 4,
'name' => "Tập " . $this->name,
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movie()
{
return $this->belongsTo(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

76
src/Models/Menu.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Traits\HasFactory;
class Menu extends Model implements Cacheable
{
use CrudTrait;
use HasFactory;
use HasCache;
protected $table = 'menus';
protected $fillable = ['name', 'type', 'link', 'parent_id', 'lft', 'rgt'];
public function parent()
{
return $this->belongsTo(static::class, 'parent_id');
}
public function children()
{
return $this->hasMany(static::class, 'parent_id');
}
/**
* Get all menu items, in a hierarchical collection.
* Only supports 2 levels of indentation.
*/
public static function getTree()
{
$menu = self::fromCache()->all()->sortBy('lft');
if ($menu->count()) {
foreach ($menu as $k => $menu_item) {
$menu_item->children = collect([]);
foreach ($menu as $i => $menu_subitem) {
if ($menu_subitem->parent_id == $menu_item->id) {
$menu_item->children->push($menu_subitem);
// remove the subitem for the first level
$menu = $menu->reject(function ($item) use ($menu_subitem) {
return $item->id == $menu_subitem->id;
});
}
}
}
}
return $menu;
}
public function url()
{
switch ($this->type) {
case 'external_link':
return $this->link;
break;
case 'internal_link':
return is_null($this->link) ? '#' : url($this->link);
break;
default: //page_link
if ($this->page) {
return url($this->page->slug);
}
break;
}
}
}

308
src/Models/Movie.php Normal file
View File

@@ -0,0 +1,308 @@
<?php
namespace Vsmov\Core\Models;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\ActorLog;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\Sluggable;
class Movie extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use ActorLog;
use Sluggable;
use HasFactory;
use HasCache;
use HasTitle;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'movies';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function boot()
{
parent::boot();
static::updating(function ($instance) {
$instance->timestamps = request('timestamps') ?: false;
});
}
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_movie', '/phim/{movie}');
if (strpos($site_routes, '{movie}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl()
{
$params = [];
$site_routes = setting('site_routes_movie', '/phim/{movie}');
if (strpos($site_routes, '{movie}')) $params['movie'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('movies.show', $params);
}
public function getThumbUrl()
{
if (setting('site_image_proxy_enable', false)) {
$image_url = filter_var($this->thumb_url, FILTER_VALIDATE_URL) ? $this->thumb_url : url('/') . $this->thumb_url;
return str_replace('{image_url}', urlencode($image_url), setting('site_image_proxy_url', ''));
}
return $this->thumb_url;
}
public function getPosterUrl()
{
if ($this->poster_url) {
if (setting('site_image_proxy_enable', false)) {
$image_url = filter_var($this->poster_url, FILTER_VALIDATE_URL) ? $this->poster_url : url('/') . $this->poster_url;
return str_replace('{image_url}', urlencode($image_url), setting('site_image_proxy_url', ''));
}
return $this->poster_url;
}
return $this->getThumbUrl();
}
public function getRatingStar()
{
return number_format($this->rating_star > 0 ? $this->rating_star : 8, 1);
}
public function getRatingCount()
{
return $this->rating_count >= 1 ? $this->rating_count : 1;
}
public function generateSeoTags()
{
$movie_thumb_url = filter_var($this->thumb_url, FILTER_VALIDATE_URL) ? $this->thumb_url : request()->root() . $this->thumb_url;
$movie_poster_url = filter_var($this->poster_url, FILTER_VALIDATE_URL) ? $this->poster_url : request()->root() . $this->poster_url;
$seo_des = Str::limit(strip_tags($this->content), 150, '...');
$getTitle = $this->getTitle();
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($getTitle, false)
->setDescription($seo_des)
->addKeyword($this->tags()->pluck('name')->toArray())
->addMeta('article:published_time', $this->updated_at->toW3CString(), 'property')
->addMeta('article:section', $this->categories->pluck('name')->join(","), 'property')
->addMeta('article:tag', $this->tags->pluck('name')->join(","), 'property')
->setCanonical($getUrl)
->setPrev(url('/'))
->setPrev(url('/'));
if ($this->type === 'single') {
OpenGraph::setType('video.movie')
->setTitle($getTitle, false)
->setDescription($seo_des)
->setSiteName($site_meta_siteName)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $this->updated_at)
->addProperty('url', $getUrl)
->addImages([$movie_thumb_url,$movie_poster_url])
->setVideoMovie([
'actor' => $this->actors->pluck('name')->join(","),
'director' => $this->directors->pluck('name')->join(","),
'duration' => $this->episode_time,
'release_date' => $this->created_at,
'tag' => $this->tags->pluck('name')->join(", ")
]);
} else {
OpenGraph::setType('video.tv_show')
->setTitle($getTitle, false)
->setDescription($seo_des)
->setSiteName($site_meta_siteName)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $this->updated_at)
->addProperty('url', $getUrl)
->addImages([$movie_thumb_url,$movie_poster_url])
->setVideoTVShow([
'actor' => $this->actors->pluck('name')->join(","),
'director' => $this->directors->pluck('name')->join(","),
'duration' => $this->episode_time,
'release_date' => $this->created_at,
'tag' => $this->tags->pluck('name')->join(", ")
]);
}
TwitterCard::setSite($site_meta_siteName)
->setTitle($getTitle, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->addValue('dateCreated', $this->created_at)
->addValue('dateModified', $this->updated_at)
->addValue('datePublished', $this->created_at)
->setTitle($getTitle, false)
->setType('Movie')
->setDescription($seo_des)
->setImages([$movie_thumb_url, $movie_poster_url])
->addValue('aggregateRating', [
'@type' => 'AggregateRating',
'bestRating' => "10",
'worstRating' => "1",
'ratingValue' => $this->getRatingStar(),
'reviewCount' => $this->getRatingCount()
])
->addValue('director', count($this->directors) ? $this->directors->map(function ($director) {
return ['@type' => 'Person', 'name' => $director->name];
}) : "")
->addValue('actor', count($this->actors) ? $this->actors->map(function ($actor) {
return ['@type' => 'Person', 'name' => $actor->name];
}) : "")
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
foreach ($this->regions as $item) {
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $item->name,
'item' => $item->getUrl(),
]);
}
foreach ($this->categories as $item) {
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $item->name,
'item' => $item->getUrl(),
]);
}
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => $this->name
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
public function openView($crud = false)
{
return '<a class="btn btn-sm btn-link" target="_blank" href="' . $this->getUrl() . '" data-toggle="tooltip" title="View link"><i class="la la-link"></i> View</a>';
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function categories()
{
return $this->belongsToMany(Category::class);
}
public function regions()
{
return $this->belongsToMany(Region::class);
}
public function directors()
{
return $this->belongsToMany(Director::class);
}
public function actors()
{
return $this->belongsToMany(Actor::class);
}
public function tags()
{
return $this->belongsToMany(Tag::class);
}
public function episodes()
{
return $this->hasMany(Episode::class);
}
public function studios()
{
return $this->belongsToMany(Studio::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
public function getStatus()
{
$statuses = [
'trailer' => __('Sắp chiếu'),
'ongoing' => __('Đang chiếu'),
'completed' => __('Hoàn thành')
];
return $statuses[$this->status];
}
protected function titlePattern(): string
{
return Setting::get('site_movie_title', '');
}
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

192
src/Models/Region.php Normal file
View File

@@ -0,0 +1,192 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\ActorLog;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\HasDescription;
use Vsmov\Core\Traits\HasKeywords;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Region extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use ActorLog;
use Sluggable;
use HasFactory;
use HasCache;
use HasTitle;
use HasDescription;
use HasKeywords;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'regions';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_region', '/quoc-gia/{region}');
if (strpos($site_routes, '{region}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl($withDomain = true)
{
$params = [];
$site_routes = setting('site_routes_region', '/quoc-gia/{region}');
if (strpos($site_routes, '{region}')) $params['region'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('regions.movies.index', $params, $withDomain);
}
protected function titlePattern(): string
{
return Setting::get('site_region_title', '');
}
protected function descriptionPattern(): string
{
return Setting::get('site_region_des', '');
}
protected function keywordsPattern(): string
{
return Setting::get('site_region_key', '');
}
public function generateSeoTags()
{
$seo_title = $this->seo_title ?: $this->getTitle();
$seo_des = Str::limit($this->seo_des ?: $this->getDescription(), 150, '...');
$seo_key = $this->seo_key ?: $this->getKeywords();
$movie_thumb_url = '';
$movie_poster_url = '';
$updated_at = '';
if(count($this->movies)) {
$movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url;
$movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url;
$updated_at = $this->movies->last()->updated_at;
}
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setSiteName($site_meta_siteName)
->setType('website')
->setTitle($seo_title, false)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $updated_at)
->addProperty('url', $getUrl)
->setDescription($seo_des)
->addImages([$movie_thumb_url, $movie_poster_url]);
TwitterCard::setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('WebPage')
->addValue('dateCreated', $updated_at)
->addValue('dateModified', $updated_at)
->addValue('datePublished', $updated_at)
->setDescription($seo_des)
->setImages([$movie_thumb_url, $movie_poster_url])
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $this->name,
'item' => $getUrl
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => "Trang " . (request()->get('page') ?: 1),
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movies()
{
return $this->belongsToMany(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

149
src/Models/Studio.php Normal file
View File

@@ -0,0 +1,149 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\HasDescription;
use Vsmov\Core\Traits\HasKeywords;
use Vsmov\Core\Traits\HasUniqueName;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Studio extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use Sluggable;
use HasUniqueName;
use HasFactory;
use HasCache;
use HasTitle;
use HasDescription;
use HasKeywords;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'studios';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
return 'slug';
}
public function getUrl()
{
return route('studios.movies.index', $this->slug);
}
protected function titlePattern(): string
{
return Setting::get('site_studio_title', '');
}
protected function descriptionPattern(): string
{
return Setting::get('site_region_des', '');
}
protected function keywordsPattern(): string
{
return Setting::get('site_region_key', '');
}
public function generateSeoTags()
{
$seo_title = $this->getTitle();
$seo_des = Str::limit($this->getDescription(), 150, '...');
$seo_key = $this->getKeywords();
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($this->getUrl())
->setPrev(request()->root())
->setPrev(request()->root());
// ->addMeta($meta, $value, 'property');
OpenGraph::setSiteName(setting('site_meta_siteName'))
->setTitle($seo_title, false)
->addProperty('type', 'movie')
->addProperty('locale', 'vi-VN')
->addProperty('url', $this->getUrl())
->setDescription($seo_des)
->addImages([$this->thumb_url, $this->poster_url]);
TwitterCard::setSite(setting('site_meta_siteName'))
->setTitle($seo_title, false)
->setType('movie')
->setImage($this->thumb_url)
->setDescription($seo_des)
->setUrl($this->getUrl());
// ->addValue($key, $value);
JsonLdMulti::newJsonLd()
->setSite(setting('site_meta_siteName'))
->setTitle($seo_title, false)
->setType('movie')
->setDescription($seo_des)
->setUrl($this->getUrl());
// ->addValue($key, $value);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movies()
{
return $this->belongsToMany(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

191
src/Models/Tag.php Normal file
View File

@@ -0,0 +1,191 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Backpack\Settings\app\Models\Setting;
use Vsmov\Core\Contracts\TaxonomyInterface;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Vsmov\Core\Contracts\SeoInterface;
use Vsmov\Core\Traits\HasFactory;
use Vsmov\Core\Traits\HasTitle;
use Vsmov\Core\Traits\HasDescription;
use Vsmov\Core\Traits\HasKeywords;
use Vsmov\Core\Traits\HasUniqueName;
use Vsmov\Core\Traits\Sluggable;
use Illuminate\Support\Str;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\TwitterCard;
class Tag extends Model implements TaxonomyInterface, Cacheable, SeoInterface
{
use CrudTrait;
use Sluggable;
use HasUniqueName;
use HasFactory;
use HasCache;
use HasTitle;
use HasDescription;
use HasKeywords;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'tags';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
public static function primaryCacheKey(): string
{
$site_routes = setting('site_routes_tag', '/tu-khoa/{tag}');
if (strpos($site_routes, '{tag}')) return 'slug';
if (strpos($site_routes, '{id}')) return 'id';
return 'slug';
}
public function getUrl()
{
$params = [];
$site_routes = setting('site_routes_tag', '/tu-khoa/{tag}');
if (strpos($site_routes, '{tag}')) $params['tag'] = $this->slug;
if (strpos($site_routes, '{id}')) $params['id'] = $this->id;
return route('tags.movies.index', $params);
}
protected function titlePattern(): string
{
return Setting::get('site_tag_title', '');
}
protected function descriptionPattern(): string
{
return Setting::get('site_tag_des', '');
}
protected function keywordsPattern(): string
{
return Setting::get('site_tag_key', '');
}
public function generateSeoTags()
{
$seo_title = $this->getTitle();
$seo_des = Str::limit($this->getDescription(), 150, '...');
$seo_key = $this->getKeywords();
$movie_thumb_url = '';
$movie_poster_url = '';
$updated_at = '';
if(count($this->movies)) {
$movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url;
$movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url;
$updated_at = $this->movies->last()->updated_at;
}
$getUrl = $this->getUrl();
$site_meta_siteName = setting('site_meta_siteName');
SEOMeta::setTitle($seo_title, false)
->setDescription($seo_des)
->addKeyword([$seo_key])
->setCanonical($getUrl)
->setPrev(request()->root())
->setPrev(request()->root());
OpenGraph::setSiteName($site_meta_siteName)
->setType('website')
->setTitle($seo_title, false)
->addProperty('locale', 'vi-VN')
->addProperty('updated_time', $updated_at)
->addProperty('url', $getUrl)
->setDescription($seo_des)
->addImages([$this->thumb_url, $this->poster_url]);
TwitterCard::setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('summary')
->setImage($movie_thumb_url)
->setDescription($seo_des)
->setUrl($getUrl);
JsonLdMulti::newJsonLd()
->setSite($site_meta_siteName)
->setTitle($seo_title, false)
->setType('WebPage')
->addValue('dateCreated', $updated_at)
->addValue('dateModified', $updated_at)
->addValue('datePublished', $updated_at)
->setDescription($seo_des)
->setImages([$movie_thumb_url, $movie_poster_url])
->setUrl($getUrl);
$breadcrumb = [];
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => url('/')
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 2,
'name' => $this->name,
'item' => $getUrl
]);
array_push($breadcrumb, [
'@type' => 'ListItem',
'position' => 3,
'name' => "Trang " . (request()->get('page') ?: 1),
]);
JsonLdMulti::newJsonLd()
->setType('BreadcrumbList')
->addValue('name', '')
->addValue('description', '')
->addValue('itemListElement', $breadcrumb);
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function movies()
{
return $this->belongsToMany(Movie::class);
}
/*
|--------------------------------------------------------------------------
| SCOPES
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| ACCESSORS
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| MUTATORS
|--------------------------------------------------------------------------
*/
}

140
src/Models/Theme.php Normal file
View File

@@ -0,0 +1,140 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Vsmov\CachingModel\Contracts\Cacheable;
use Vsmov\CachingModel\HasCache;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Artisan;
use Vsmov\Core\Traits\HasFactory;
class Theme extends Model implements Cacheable
{
use CrudTrait;
use HasFactory;
use HasCache;
/*
|--------------------------------------------------------------------------
| GLOBAL VARIABLES
|--------------------------------------------------------------------------
*/
protected $table = 'themes';
// protected $primaryKey = 'id';
// public $timestamps = false;
protected $guarded = ['id'];
// protected $fillable = [];
// protected $hidden = [];
// protected $dates = [];
protected $casts = [
'value' => 'array',
];
public static function getActivatedTheme(): ?self
{
return Theme::where('active', true)->first() ?: Theme::first();
}
public function getVersionAttribute()
{
if (!\Composer\InstalledVersions::isInstalled($this->package_name)) {
return 'Unknown';
}
return \PackageVersions\Versions::getVersion($this->package_name);
}
public function getOptionsAttribute()
{
$allThemes = config('themes', []);
if (!isset($allThemes[strtolower($this->name)]['options'])) {
return [];
}
return $allThemes[strtolower($this->name)]['options'];
}
public function editBtn($crud = false)
{
return '<a href="' . backpack_url("theme/{$this->id}/edit") . '" class="btn btn-primary">Edit</a>';
}
public function deleteBtn($crud = false)
{
if ($this->getVersionAttribute() === 'Unknown') {
$template = <<<EOT
<form action="{actionRoute}" method="post" onsubmit="return confirm('Chắc chắn muốn xóa giao diện {display_name}?. ');" style="display: inline">
{csrfField}
<button class="btn btn-danger" type="submit">Delete</button>
</form>
EOT;
$html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/delete"), $template);
$html = str_replace("{csrfField}", csrf_field(), $html);
$html = str_replace("{display_name}", $this->display_name, $html);
return $html;
}
return '';
}
public function activeBtn($crud = false)
{
$template = <<<EOT
<form action="{actionRoute}" method="post" onsubmit="return confirm('Chắc chắn muốn kích hoạt giao diện {display_name}?');" style="display: inline">
{csrfField}
<button class="btn {btnType}" type="submit">{name}</button>
</form>
EOT;
$html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/active"), $template);
$html = str_replace("{csrfField}", csrf_field(), $html);
$html = str_replace("{display_name}", $this->display_name, $html);
if ($this->active) {
$html = str_replace("{name}", 'Re-Activate', $html);
$html = str_replace("{btnType}", 'btn-secondary', $html);
} else {
$html = str_replace("{name}", 'Activate', $html);
$html = str_replace("{btnType}", 'btn-primary', $html);
}
return $html;
}
public function resetBtn($crud = false)
{
$template = <<<EOT
<form action="{actionRoute}" method="post" onsubmit="return confirm('Chắc chắn muốn đặt về mặc định?');" style="display: inline">
{csrfField}
<button class="btn {btnType}" type="submit">{name}</button>
</form>
EOT;
$html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/reset"), $template);
$html = str_replace("{csrfField}", csrf_field(), $html);
$html = str_replace("{btnType}", 'btn-warning', $html);
$html = str_replace("{name}", 'Reset', $html);
return $html;
}
public function active()
{
static::where('active', true)->update(['active' => false]);
$publishTags = config('themes', [])[$this->name]['publishes'] ?? [];
foreach ($publishTags as $tag) {
Artisan::call('vendor:publish', [
'--tag' => $tag,
'--force' => true
]);
}
return $this->update(['active' => true]);
}
}

13
src/Models/User.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
namespace Vsmov\Core\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use CrudTrait;
use HasRoles;
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class ActorPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse user');
}
public function create($user)
{
return $user->hasPermissionTo('Create user');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update user');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete user');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class CatalogPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse catalog');
}
public function create($user)
{
return $user->hasPermissionTo('Create catalog');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update catalog');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete catalog');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class CategoryPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse category');
}
public function create($user)
{
return $user->hasPermissionTo('Create category');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update category');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete category');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class CrawlSchedulePolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse crawl schedule');
}
public function create($user)
{
return $user->hasPermissionTo('Create crawl schedule');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update crawl schedule');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete crawl schedule');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class DirectorPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse director');
}
public function create($user)
{
return $user->hasPermissionTo('Create director');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update director');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete director');
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class EpisodePolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse episode');
}
public function create($user)
{
return $user->hasPermissionTo('Create episode');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update episode');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete episode');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class MenuPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse menu');
}
public function create($user)
{
return $user->hasPermissionTo('Create menu');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update menu');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete menu');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class MoviePolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse movie');
}
public function create($user)
{
return $user->hasPermissionTo('Create movie');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update movie');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete movie');
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
use Backpack\PermissionManager\app\Models\Permission;
class PermissionPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse permission');
}
public function create($user)
{
return $user->hasPermissionTo('Create permission');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update permission');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete permission');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class RegionPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse region');
}
public function create($user)
{
return $user->hasPermissionTo('Create region');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update region');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete region');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class RolePolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse role');
}
public function create($user)
{
return $user->hasPermissionTo('Create role');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update role');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete role');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class StudioPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse studio');
}
public function create($user)
{
return $user->hasPermissionTo('Create studio');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update studio');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete studio');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class TagPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse tag');
}
public function create($user)
{
return $user->hasPermissionTo('Create tag');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update tag');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete tag');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Vsmov\Core\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function before($user)
{
if ($user->hasRole('Admin')) {
return true;
}
}
public function browse($user)
{
return $user->hasPermissionTo('Browse user');
}
public function create($user)
{
return $user->hasPermissionTo('Create user');
}
public function update($user, $entry)
{
return $user->hasPermissionTo('Update user');
}
public function delete($user, $entry)
{
return $user->hasPermissionTo('Delete user');
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Vsmov\Core\Rules\UniqueName;
class ActorRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$this->name_md5 = md5($this->name);
return [
'name' => ['required', 'max:255', new UniqueName('actors', 'name', 'name_md5', 'id', $this->id)],
'slug' => 'max:255|unique:actors,slug,' . $this->id . ',id',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CatalogRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|min:5|max:255',
'slug' => 'max:255|unique:catalogs,slug,' . $this->id . ',id',
'value' => 'string',
'seo_title' => 'string|max:255',
'seo_des' => 'string|max:255',
'seo_key' => 'string|max:255',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CategoryRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|min:5|max:255',
'slug' => 'max:255|unique:categories,slug,' . $this->id . ',id',
'seo_title' => 'string|max:255',
'seo_des' => 'string|max:255',
'seo_key' => 'string|max:255',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CrawlScheduleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'type' => 'required',
'fields' => 'required'
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Vsmov\Core\Rules\UniqueName;
class DirectorRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$this->name_md5 = md5($this->name);
return [
'name' => ['required', 'max:255', new UniqueName('directors', 'name', 'name_md5', 'id', $this->id)],
'slug' => 'max:255|unique:directors,slug,' . $this->id . ',id',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Vsmov\CoreHttp\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MenuRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:255',
'type' => 'required',
'link' => 'required|max:2048'
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MovieRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:512',
'origin_name' => 'required|max:512',
'slug' => 'max:255|unique:movies,slug,' . $this->id . ',id',
'type' => 'required|in:single,series',
'status' => 'required|in:trailer,ongoing,completed',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegionRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|min:5|max:255',
'slug' => 'max:255|unique:regions,slug,' . $this->id . ',id',
'seo_title' => 'string|max:255',
'seo_des' => 'string|max:255',
'seo_key' => 'string|max:255',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StudioRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|max:512',
'slug' => 'max:255|unique:studios,slug,' . $this->id . ',id',
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Vsmov\Core\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Vsmov\Core\Rules\UniqueName;
class TagRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => ['required', 'max:255', new UniqueName('tags', 'name', 'name_md5', 'id', $this->id)],
];
}
/**
* Get the validation attributes that apply to the request.
*
* @return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* @return array
*/
public function messages()
{
return [
//
];
}
}

51
src/Rules/UniqueName.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
namespace Vsmov\Core\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\DB;
class UniqueName implements Rule
{
protected $table;
protected $excludeField;
protected $excludeVal;
protected $md5Field;
protected $nameField;
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct(string $table, $nameField = 'name', $md5Field = 'name_md5', $excludeField, $excludeVal)
{
$this->table = $table;
$this->md5Field = $md5Field;
$this->excludeField = $excludeField;
$this->excludeVal = $excludeVal;
$this->nameField = $nameField;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return DB::table($this->table)->where($this->excludeField, '!=', $this->excludeVal)->where($this->md5Field, md5($value))->doesntExist();
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return ":attribute must be unique";
}
}

43
src/Theme.php Normal file
View File

@@ -0,0 +1,43 @@
<?php
namespace VsMov\Core;
use Exception;
use VsMov\Core\Models\Theme as ThemeModel;
class Theme
{
protected $name;
protected $namespace = 'themes';
protected $publicPath;
protected $themePath;
protected $payload;
public function __construct(array $payload = [])
{
$this->payload = $payload;
$this->name = ThemeModel::getActivatedTheme()->name;
if (is_null($this->name)) {
throw new \Exception("Not found any theme. Please install and active one.");;
}
$this->themePath = $this->namespace . '::' . $this->name;
}
public function render($template, array $data = [])
{
$viewPath = sprintf("%s.%s", $this->themePath, $template);
if (!view()->exists($viewPath)) {
throw new Exception("Theme {$this->name}'s {$template} view is not installed. Please check your installation");
}
return view($viewPath, array_merge($this->payload, $data));
}
public function addPayload(array $data)
{
$this->payload = array_merge($this->payload, $data);
}
}

19
src/Traits/ActorLog.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace VsMov\Core\Traits;
trait ActorLog
{
public static function bootActorLog()
{
static::creating(function ($instance) {
$instance->user_id = auth('backpack')->id() ?: $instance->user_id;
$instance->user_name = auth('backpack')->user() ? auth('backpack')->user()->name : $instance->username;
});
static::updating(function ($instance) {
$instance->user_id = auth('backpack')->id() ?: $instance->user_id;
$instance->user_name = auth('backpack')->user() ? auth('backpack')->user()->name : $instance->username;
});
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace VsMov\Core\Traits;
use Backpack\Settings\app\Models\Setting;
use Illuminate\Support\Str;
trait HasDescription
{
protected function descriptionPattern(): string
{
return Setting::get('site.title');
}
public function getDescription(): string
{
$pattern = $this->descriptionPattern();
preg_match_all('/{.*?}/', $pattern, $vars);
foreach ($vars[0] as $var) {
try {
$x = str_replace('{', '', $var);
$x = str_replace('}', '', $x);
$keys = explode('.', (string) $x);
$data = $this;
foreach ($keys as $key) {
$data = $data->{$key};
}
$pattern = str_replace($var, $data, $pattern);
} catch (\Exception $e) {
}
}
return $pattern;
}
}

20
src/Traits/HasFactory.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
namespace VsMov\Core\Traits;
use Illuminate\Database\Eloquent\Factories\HasFactory as BaseFactory;
use Illuminate\Support\Str;
trait HasFactory
{
use BaseFactory;
protected static function newFactory()
{
$package = Str::before(get_called_class(), 'Models\\');
$modelName = Str::after(get_called_class(), 'Models\\');
$path = $package.'Database\\Factories\\'.$modelName.'Factory';
return $path::new();
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace VsMov\Core\Traits;
use Backpack\Settings\app\Models\Setting;
use Illuminate\Support\Str;
trait HasKeywords
{
protected function keywordsPattern(): string
{
return Setting::get('site.title');
}
public function getKeywords(): string
{
$pattern = $this->keywordsPattern();
preg_match_all('/{.*?}/', $pattern, $vars);
foreach ($vars[0] as $var) {
try {
$x = str_replace('{', '', $var);
$x = str_replace('}', '', $x);
$keys = explode('.', (string) $x);
$data = $this;
foreach ($keys as $key) {
$data = $data->{$key};
}
$pattern = str_replace($var, $data, $pattern);
} catch (\Exception $e) {
}
}
return $pattern;
}
}

37
src/Traits/HasTitle.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
namespace VsMov\Core\Traits;
use Backpack\Settings\app\Models\Setting;
use Illuminate\Support\Str;
trait HasTitle
{
protected function titlePattern(): string
{
return Setting::get('site.title');
}
public function getTitle(): string
{
$pattern = $this->titlePattern();
preg_match_all('/{.*?}/', $pattern, $vars);
foreach ($vars[0] as $var) {
try {
$x = str_replace('{', '', $var);
$x = str_replace('}', '', $x);
$keys = explode('.', (string) $x);
$data = $this;
foreach ($keys as $key) {
$data = $data->{$key};
}
$pattern = str_replace($var, $data, $pattern);
} catch (\Exception $e) {
}
}
return $pattern;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace VsMov\Core\Traits;
use Illuminate\Support\Str;
trait HasUniqueName
{
/**
* Require "name" and "name_md5" filed
*
* @return void
*/
public static function bootHasUniqueName()
{
static::creating(function ($instance) {
$instance->name_md5 = md5($instance->name);
});
static::updating(function ($instance) {
$instance->name_md5 = md5($instance->name);
});
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace VsMov\Core\Traits\Operations;
use Illuminate\Support\Facades\Route;
trait BulkDeleteOperation
{
protected function setupBulkDeleteRoutes($segment, $routeName, $controller)
{
Route::post($segment.'/bulk-delete', [
'as' => $routeName.'.bulkDelete',
'uses' => $controller.'@bulkDelete',
'operation' => 'bulkDelete',
]);
}
protected function setupBulkDeleteDefaults()
{
$this->crud->allowAccess('bulkDelete');
$this->crud->operation('bulkDelete', function () {
$this->crud->loadDefaultOperationSettingsFromConfig();
});
$this->crud->operation('list', function () {
$this->crud->enableBulkActions();
$this->crud->addButton('bottom', 'bulk_delete', 'view', 'crud::buttons.bulk_delete');
});
}
public function bulkDelete()
{
$this->crud->hasAccessOrFail('bulkDelete');
$entries = request()->input('entries', []);
$deletedEntries = [];
foreach ($entries as $key => $id) {
if ($entry = $this->crud->model->find($id)) {
$deletedEntries[] = $entry->delete();
}
}
return $deletedEntries;
}
}

34
src/Traits/Sluggable.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
namespace VsMov\Core\Traits;
use Illuminate\Support\Str;
trait Sluggable
{
/**
* Require "name" and "slug" field
*
* @return void
*/
public static function bootSluggable()
{
static::creating(function ($instance) {
if (empty($instance->slug)) {
$slug = Str::slug($instance->name) ?: $instance->name;
$instance->slug = static::where('slug', $slug)->exists()
? sprintf("%s-%s%s", $slug, floor(microtime(true) * 1000), rand(1, 100))
: $slug;
}
});
static::updating(function ($instance) {
if (empty($instance->slug)) {
$slug = Str::slug($instance->name) ?: $instance->name;
$instance->slug = static::where('slug', $slug)->exists()
? sprintf("%s-%s%s", $slug, floor(microtime(true) * 1000), rand(1, 100))
: $slug;
}
});
}
}

View File

@@ -0,0 +1,229 @@
<?php
namespace VsMov\Core;
use Illuminate\Console\Scheduling\Schedule;
use VsMov\Core\Policies\PermissionPolicy;
use VsMov\Core\Policies\RolePolicy;
use VsMov\Core\Policies\UserPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\DB;
use VsMov\Core\Console\CreateUser;
use VsMov\Core\Console\InstallCommand;
use VsMov\Core\Console\GenerateMenuCommand;
use VsMov\Core\Console\ChangeDomainEpisodeCommand;
use VsMov\Core\Middleware\CKFinderAuth;
use VsMov\Core\Models\Actor;
use VsMov\Core\Models\Catalog;
use VsMov\Core\Models\Category;
use VsMov\Core\Models\Director;
use VsMov\Core\Models\Episode;
use VsMov\Core\Models\Menu;
use VsMov\Core\Models\Movie;
use VsMov\Core\Models\Region;
use VsMov\Core\Models\Studio;
use VsMov\Core\Models\Tag;
use VsMov\Core\Models\Theme;
use VsMov\Core\Policies\ActorPolicy;
use VsMov\Core\Policies\CatalogPolicy;
use VsMov\Core\Policies\CategoryPolicy;
use VsMov\Core\Policies\CrawlSchedulePolicy;
use VsMov\Core\Policies\DirectorPolicy;
use VsMov\Core\Policies\EpisodePolicy;
use VsMov\Core\Policies\MenuPolicy;
use VsMov\Core\Policies\MoviePolicy;
use VsMov\Core\Policies\RegionPolicy;
use VsMov\Core\Policies\StudioPolicy;
use VsMov\Core\Policies\TagPolicy;
class VsMovServiceProvider extends ServiceProvider
{
/**
* Get the policies defined on the provider.
*
* @return array
*/
public function policies()
{
return [
Actor::class => ActorPolicy::class,
Catalog::class => CatalogPolicy::class,
Category::class => CategoryPolicy::class,
Region::class => RegionPolicy::class,
Director::class => DirectorPolicy::class,
Tag::class => TagPolicy::class,
Studio::class => StudioPolicy::class,
Movie::class => MoviePolicy::class,
Episode::class => EpisodePolicy::class,
Menu::class => MenuPolicy::class,
CrawlSchedule::class => CrawlSchedulePolicy::class
];
}
public function register()
{
$this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'vsmov');
$this->mergeBackpackConfigs();
$this->mergeCkfinderConfigs();
$this->mergePolicies();
}
public function boot()
{
$this->registerPolicies();
try {
foreach (glob(__DIR__ . '/Helpers/*.php') as $filename) {
require_once $filename;
}
} catch (\Exception $e) {
//throw $e;
}
$this->loadRoutesFrom(__DIR__ . '/../routes/admin.php');
$this->app->booted(function () {
$this->loadThemeRoutes();
$this->loadScheduler();
});
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
$this->loadViewsFrom(__DIR__ . '/../resources/views/core/', 'vsmov');
$this->loadViewsFrom(__DIR__ . '/../resources/views/themes', 'themes');
$this->publishFiles();
$this->commands([
InstallCommand::class,
CreateUser::class,
GenerateMenuCommand::class,
ChangeDomainEpisodeCommand::class,
]);
$this->bootSeoDefaults();
}
protected function publishFiles()
{
$backpack_menu_contents_view = [
__DIR__ . '/../resources/views/core/base/' => resource_path('views/vendor/vsmov/base/'),
__DIR__ . '/../resources/views/core/crud/' => resource_path('views/vendor/vsmov/crud/'),
];
$players = [
__DIR__ . '/../resources/assets/js/hls.min.js' => public_path('js/hls.min.js'),
__DIR__ . '/../resources/assets/js/jwplayer-8.9.3.js' => public_path('js/jwplayer-8.9.3.js'),
__DIR__ . '/../resources/assets/js/jwplayer.hlsjs.min.js' => public_path('js/jwplayer.hlsjs.min.js'),
];
$this->publishes($backpack_menu_contents_view, 'cms_menu_content');
$this->publishes($players, 'players');
$this->publishes([
__DIR__ . '/../config/config.php' => config_path('vsmov.php')
], 'config');
}
protected function mergeBackpackConfigs()
{
config(['backpack.base.styles' => array_merge(config('backpack.base.styles', []), [
'packages/select2/dist/css/select2.css',
'packages/select2-bootstrap-theme/dist/select2-bootstrap.min.css'
])]);
config(['backpack.base.scripts' => array_merge(config('backpack.base.scripts', []), [
'packages/select2/dist/js/select2.full.min.js'
])]);
config(['backpack.base.middleware_class' => array_merge(config('backpack.base.middleware_class', []), [
\Backpack\CRUD\app\Http\Middleware\UseBackpackAuthGuardInsteadOfDefaultAuthGuard::class,
])]);
config(['cachebusting_string' => \PackageVersions\Versions::getVersion('vsmov/crud')]);
config(['backpack.base.project_logo' => '<b>VsMov</b>CMS']);
config(['backpack.base.developer_name' => 'vsmov']);
config(['backpack.base.developer_link' => 'mailto:vsmov@gmail.com']);
config(['backpack.base.show_powered_by' => false]);
}
protected function mergeCkfinderConfigs()
{
config(['ckfinder.authentication' => CKFinderAuth::class]);
config(['ckfinder.backends.default' => config('vsmov.ckfinder.backends')]);
}
protected function mergePolicies()
{
config(['backpack.permissionmanager.policies.permission' => PermissionPolicy::class]);
config(['backpack.permissionmanager.policies.role' => RolePolicy::class]);
config(['backpack.permissionmanager.policies.user' => UserPolicy::class]);
}
protected function bootSeoDefaults()
{
config([
'seotools.meta.defaults.title' => setting('site_homepage_title'),
'seotools.meta.defaults.description' => setting('site_meta_description'),
'seotools.meta.defaults.keywords' => [setting('site_meta_keywords')],
'seotools.meta.defaults.canonical' => url("/")
]);
config([
'seotools.opengraph.defaults.title' => setting('site_homepage_title'),
'seotools.opengraph.defaults.description' => setting('site_meta_description'),
'seotools.opengraph.defaults.type' => 'website',
'seotools.opengraph.defaults.url' => url("/"),
'seotools.opengraph.defaults.site_name' => setting('site_meta_siteName'),
'seotools.opengraph.defaults.images' => [setting('site_meta_image')],
]);
config([
'seotools.twitter.defaults.card' => 'website',
'seotools.twitter.defaults.title' => setting('site_homepage_title'),
'seotools.twitter.defaults.description' => setting('site_meta_description'),
'seotools.twitter.defaults.url' => url("/"),
'seotools.twitter.defaults.site' => setting('site_meta_siteName'),
'seotools.twitter.defaults.image' => setting('site_meta_image'),
]);
config([
'seotools.json-ld.defaults.title' => setting('site_homepage_title'),
'seotools.json-ld.defaults.type' => 'WebPage',
'seotools.json-ld.defaults.description' => setting('site_meta_description'),
'seotools.json-ld.defaults.images' => setting('site_meta_image'),
]);
}
protected function loadThemeRoutes()
{
try {
$activatedTheme = Theme::getActivatedTheme();
if ($activatedTheme && file_exists($routeFile = base_path('vendor/' . $activatedTheme->package_name . '/routes/web.php'))) {
$this->loadRoutesFrom($routeFile);
}
} catch (\Exception $e) {
// Log
}
}
protected function loadScheduler()
{
$schedule = $this->app->make(Schedule::class);
$schedule->call(function () {
DB::table('movies')->update(['view_day' => 0]);
})->daily();
$schedule->call(function () {
DB::table('movies')->update(['view_week' => 0]);
})->weekly();
$schedule->call(function () {
DB::table('movies')->update(['view_month' => 0]);
})->monthly();
}
}