some progress
This commit is contained in:
@@ -8,7 +8,7 @@ php artisan tmdb:fetch-export tv_series
|
|||||||
|
|
||||||
### Populate the list of movies/tv_series to fetch
|
### Populate the list of movies/tv_series to fetch
|
||||||
```
|
```
|
||||||
php artisan tmdb:fetch-export-items movie}
|
php artisan tmdb:fetch-export-items movie
|
||||||
php artisan tmdb:fetch-export-items show
|
php artisan tmdb:fetch-export-items show
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,12 @@ class FetchItemDataCommand extends Command
|
|||||||
{
|
{
|
||||||
switch ($type){
|
switch ($type){
|
||||||
case ItemToFetch::TYPE_MOVIE:
|
case ItemToFetch::TYPE_MOVIE:
|
||||||
return MovieProcessingService::getBatch($batch, $job);
|
$items = MovieProcessingService::getBatch($batch, $job);
|
||||||
|
|
||||||
|
if ($items->count() == 0){
|
||||||
|
$items = MovieProcessingService::getMissingMoviesBatch($batch, $job);
|
||||||
|
}
|
||||||
|
return $items;
|
||||||
case ItemToFetch::TYPE_TV_SERIES:
|
case ItemToFetch::TYPE_TV_SERIES:
|
||||||
return ShowProcessingService::getBatch($batch, $job, $tmdbId);
|
return ShowProcessingService::getBatch($batch, $job, $tmdbId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class FetchExportItemsCommand extends Command
|
|||||||
if (null === $decodedLine) {
|
if (null === $decodedLine) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
echo '.';
|
||||||
$this->processItem($decodedLine, $type);
|
$this->processItem($decodedLine, $type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class CheckPermission
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
* @param string ...$permissions
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next, ...$permissions): Response
|
||||||
|
{
|
||||||
|
if (!$request->user()) {
|
||||||
|
abort(403, 'Unauthorized action.');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
if ($request->user()->hasPermission($permission)) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403, 'Unauthorized action.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class CheckRole
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
* @param string ...$roles
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next, ...$roles): Response
|
||||||
|
{
|
||||||
|
if (!$request->user()) {
|
||||||
|
abort(403, 'Unauthorized action.');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($roles as $role) {
|
||||||
|
if ($request->user()->hasRole($role)) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403, 'Unauthorized action.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,9 +71,9 @@ class Movie extends Model
|
|||||||
|
|
||||||
public function director()
|
public function director()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Person::class, 'movie_cast', 'movie_id', 'person_id')
|
return $this->belongsToMany(Person::class, 'movie_crew', 'movie_id', 'person_id')
|
||||||
->where('movie_cast.job', 'Director')
|
->where('movie_crew.job', 'Director')
|
||||||
->orWhere('movie_cast.known_for_department', 'Directing')
|
->orWhere('movie_crew.known_for_department', 'Directing')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Permission extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'slug',
|
||||||
|
'description',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function roles()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Role::class, 'permission_role');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class, 'permission_user');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Role extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'slug',
|
||||||
|
'description',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class, 'role_user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function permissions()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Permission::class, 'permission_role');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPermission($permission)
|
||||||
|
{
|
||||||
|
if (is_string($permission)) {
|
||||||
|
return $this->permissions->contains('slug', $permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->permissions->contains('id', $permission->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function givePermissionTo($permission)
|
||||||
|
{
|
||||||
|
return $this->permissions()->save($permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,4 +52,69 @@ class User extends Authenticatable
|
|||||||
{
|
{
|
||||||
return $this->belongsToMany(MediaList::class, 'user_media_lists', 'user_id', 'media_list_id');
|
return $this->belongsToMany(MediaList::class, 'user_media_lists', 'user_id', 'media_list_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function roles()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Role::class, 'role_user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function permissions()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Permission::class, 'permission_user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRole($role)
|
||||||
|
{
|
||||||
|
if (is_string($role)) {
|
||||||
|
return $this->roles->contains('slug', $role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->roles->contains('id', $role->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPermission($permission)
|
||||||
|
{
|
||||||
|
if (is_string($permission)) {
|
||||||
|
// Check direct permissions
|
||||||
|
if ($this->permissions->contains('slug', $permission)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check role permissions
|
||||||
|
foreach ($this->roles as $role) {
|
||||||
|
if ($role->hasPermission($permission)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->permissions->contains('id', $permission->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAnyRole($roles)
|
||||||
|
{
|
||||||
|
if (is_string($roles)) {
|
||||||
|
return $this->roles->contains('slug', $roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($roles as $role) {
|
||||||
|
if ($this->hasRole($role)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function assignRole($role)
|
||||||
|
{
|
||||||
|
return $this->roles()->save($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function givePermissionTo($permission)
|
||||||
|
{
|
||||||
|
return $this->permissions()->save($permission);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,20 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getMissingMoviesBatch(int $batch, string $job)
|
||||||
|
{
|
||||||
|
return ItemToFetchJobs::select('item_to_fetch_jobs.*')
|
||||||
|
->leftJoin('movies', function ($join) {
|
||||||
|
$join->on('movies.tmdb_id', '=', 'item_to_fetch_jobs.tmdb_id');
|
||||||
|
})
|
||||||
|
->whereRaw("FIND_IN_SET('".$job."', item_to_fetch_jobs.jobs)")
|
||||||
|
->where('item_to_fetch_jobs.type', 'movie')
|
||||||
|
->whereNull('movies.id')
|
||||||
|
->whereNotNull('item_to_fetch_jobs.tmdb_id')
|
||||||
|
->take($batch)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
public function process($item, $job)
|
public function process($item, $job)
|
||||||
{
|
{
|
||||||
$methodName = "get".ucfirst($job);
|
$methodName = "get".ucfirst($job);
|
||||||
@@ -66,7 +80,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
// @todo maybe raise an exception here
|
// @todo maybe raise an exception here
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
echo "Processing {$methodName} ".$item->tmdb_id." (".$item->id.") \n";
|
echo "Processing {$methodName} ".$item->tmdb_id." (".$item->tmdb_id.") \n";
|
||||||
$this->$methodName($item);
|
$this->$methodName($item);
|
||||||
|
|
||||||
// maybe we should sleep for a while so we do not spam the tmdb api
|
// maybe we should sleep for a while so we do not spam the tmdb api
|
||||||
@@ -78,7 +92,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
$tmdbMovie = $this->moviesApi->getMovie($item->tmdb_id);
|
$tmdbMovie = $this->moviesApi->getMovie($item->tmdb_id);
|
||||||
|
|
||||||
if (isset($tmdbMovie['status_code']) && $tmdbMovie['status_code'] == 34) {
|
if (isset($tmdbMovie['status_code']) && $tmdbMovie['status_code'] == 34) {
|
||||||
echo "[ApiError-Could not be found]\n]";
|
echo "[ApiError-Could not be found]\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,12 +218,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
$imageExists = Image::create($image);
|
$imageExists = Image::create($image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($movie->whereHas('images', function ($query) use ($imageExists) {
|
if (!$movie->images()->where('image_id', $imageExists->id)->exists()) {
|
||||||
$query->where('type', $imageExists->type)
|
|
||||||
->where('file_path', $imageExists->file_path);
|
|
||||||
})->exists()) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$movie->images()->attach($imageExists);
|
$movie->images()->attach($imageExists);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,11 +247,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($movie->whereHas('keywords', function ($query) use ($existingKeyword) {
|
if (!$movie->keywords()->where('keyword_id', $existingKeyword->id)->exists()) {
|
||||||
$query->where('tmdb_id', $existingKeyword->tmdb_id);
|
|
||||||
})->exists()) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$movie->keywords()->attach($existingKeyword);
|
$movie->keywords()->attach($existingKeyword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,11 +281,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($movie->whereHas('releaseDates', function ($query) use ($movie) {
|
if (!$movie->releaseDates()->where('release_date_id', $existingReleaseDate->id)->exists()) {
|
||||||
$query->where('movie_id', $movie->id);
|
|
||||||
})->exists()) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$movie->releaseDates()->attach($existingReleaseDate);
|
$movie->releaseDates()->attach($existingReleaseDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,9 +453,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$movie->whereHas('watchProviders', function ($query) use ($movie) {
|
if (!$movie->watchProviders()->where('watch_provider_id', $existingWatchProvider->id)->where('locale', $locale)->exists()) {
|
||||||
$query->where('movie_id', $movie->id);
|
|
||||||
})->exists()) {
|
|
||||||
$movie->watchProviders()->attach($existingWatchProvider, [
|
$movie->watchProviders()->attach($existingWatchProvider, [
|
||||||
'locale' => $locale,
|
'locale' => $locale,
|
||||||
'tmdb_url' => $tmdbWatchProvider['link'],
|
'tmdb_url' => $tmdbWatchProvider['link'],
|
||||||
@@ -494,11 +493,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($movie->whereHas('videos', function ($query) use ($movie) {
|
if (!$movie->videos()->where('video_id', $videoExists->id)->exists()) {
|
||||||
$query->where('movie_id', $movie->id);
|
|
||||||
})->exists()) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$movie->videos()->attach($videoExists);
|
$movie->videos()->attach($videoExists);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -718,8 +713,6 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
|
|
||||||
private function processMovieCollection(int $movieId, $belongsToCollection)
|
private function processMovieCollection(int $movieId, $belongsToCollection)
|
||||||
{
|
{
|
||||||
dd($belongsToCollection);
|
|
||||||
|
|
||||||
$movieCollection = MovieCollection::where('tmdb_id', $belongsToCollection['id'])->first();
|
$movieCollection = MovieCollection::where('tmdb_id', $belongsToCollection['id'])->first();
|
||||||
|
|
||||||
if (!$movieCollection) {
|
if (!$movieCollection) {
|
||||||
@@ -795,6 +788,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
|
|
||||||
if (empty($remainingJobs)) {
|
if (empty($remainingJobs)) {
|
||||||
$itemToFetchJobs->delete();
|
$itemToFetchJobs->delete();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// $itemToFetchJobs->remaining_jobs = $remainingJobs;
|
// $itemToFetchJobs->remaining_jobs = $remainingJobs;
|
||||||
@@ -833,7 +827,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
|
|
||||||
$personData = array_merge($personData, [
|
$personData = array_merge($personData, [
|
||||||
'biography' => $tmdbPerson['biography'],
|
'biography' => $tmdbPerson['biography'],
|
||||||
'birtday' => $tmdbPerson['birthday'],
|
'birthday' => $tmdbPerson['birthday'],
|
||||||
'deathday' => $tmdbPerson['deathday'],
|
'deathday' => $tmdbPerson['deathday'],
|
||||||
'homepage' => $tmdbPerson['homepage'],
|
'homepage' => $tmdbPerson['homepage'],
|
||||||
'imdb_id' => $tmdbPerson['imdb_id'],
|
'imdb_id' => $tmdbPerson['imdb_id'],
|
||||||
@@ -883,7 +877,7 @@ class MovieProcessingService implements ProcessingInterface
|
|||||||
if (!empty($tmdbPerson)) {
|
if (!empty($tmdbPerson)) {
|
||||||
$personData = array_merge($personData, [
|
$personData = array_merge($personData, [
|
||||||
'biography' => $tmdbPerson['biography'],
|
'biography' => $tmdbPerson['biography'],
|
||||||
'birtday' => $tmdbPerson['birthday'],
|
'birthday' => $tmdbPerson['birthday'],
|
||||||
'deathday' => $tmdbPerson['deathday'],
|
'deathday' => $tmdbPerson['deathday'],
|
||||||
'homepage' => $tmdbPerson['homepage'],
|
'homepage' => $tmdbPerson['homepage'],
|
||||||
'imdb_id' => $tmdbPerson['imdb_id'],
|
'imdb_id' => $tmdbPerson['imdb_id'],
|
||||||
|
|||||||
+4
-1
@@ -11,7 +11,10 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware) {
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
//
|
$middleware->alias([
|
||||||
|
'role' => \App\Http\Middleware\CheckRole::class,
|
||||||
|
'permission' => \App\Http\Middleware\CheckPermission::class,
|
||||||
|
]);
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions) {
|
->withExceptions(function (Exceptions $exceptions) {
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// Create roles table
|
||||||
|
Schema::create('roles', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name')->unique();
|
||||||
|
$table->string('slug')->unique();
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create permissions table
|
||||||
|
Schema::create('permissions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name')->unique();
|
||||||
|
$table->string('slug')->unique();
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create role_user pivot table
|
||||||
|
Schema::create('role_user', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('role_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['user_id', 'role_id']);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create permission_role pivot table
|
||||||
|
Schema::create('permission_role', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('role_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('permission_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['role_id', 'permission_id']);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create permission_user pivot table (for direct user permissions)
|
||||||
|
Schema::create('permission_user', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('permission_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['user_id', 'permission_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('permission_user');
|
||||||
|
Schema::dropIfExists('permission_role');
|
||||||
|
Schema::dropIfExists('role_user');
|
||||||
|
Schema::dropIfExists('permissions');
|
||||||
|
Schema::dropIfExists('roles');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\MediaList;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class DatabaseSeeder extends Seeder
|
class DatabaseSeeder extends Seeder
|
||||||
{
|
{
|
||||||
@@ -17,7 +19,26 @@ class DatabaseSeeder extends Seeder
|
|||||||
|
|
||||||
User::factory()->create([
|
User::factory()->create([
|
||||||
'name' => 'Test User',
|
'name' => 'Test User',
|
||||||
|
'slug' => 'test-user',
|
||||||
'email' => 'test@example.com',
|
'email' => 'test@example.com',
|
||||||
|
'password' => bcrypt('password'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = User::find(1);
|
||||||
|
|
||||||
|
$this->createMediaList('Watchlist', $user);
|
||||||
|
$this->createMediaList('Collection', $user);
|
||||||
|
$this->createMediaList('Watched', $user);
|
||||||
|
$this->createMediaList('Liked', $user);
|
||||||
|
$this->createMediaList('Favourite', $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMediaList(string $name, $user)
|
||||||
|
{
|
||||||
|
return MediaList::create([
|
||||||
|
'name' => $name,
|
||||||
|
'slug' => Str::slug($name),
|
||||||
|
'user_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Permission;
|
||||||
|
use App\Models\Role;
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class RolesAndPermissionsSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// Create permissions
|
||||||
|
$permissions = [
|
||||||
|
['name' => 'View Movies', 'slug' => 'view-movies', 'description' => 'Can view movies'],
|
||||||
|
['name' => 'Create Movies', 'slug' => 'create-movies', 'description' => 'Can create new movies'],
|
||||||
|
['name' => 'Edit Movies', 'slug' => 'edit-movies', 'description' => 'Can edit existing movies'],
|
||||||
|
['name' => 'Delete Movies', 'slug' => 'delete-movies', 'description' => 'Can delete movies'],
|
||||||
|
['name' => 'Manage Users', 'slug' => 'manage-users', 'description' => 'Can manage users'],
|
||||||
|
['name' => 'Manage Roles', 'slug' => 'manage-roles', 'description' => 'Can manage roles and permissions'],
|
||||||
|
['name' => 'Moderate Content', 'slug' => 'moderate-content', 'description' => 'Can moderate user content'],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
Permission::firstOrCreate(['slug' => $permission['slug']], $permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create roles
|
||||||
|
$adminRole = Role::firstOrCreate(
|
||||||
|
['slug' => 'admin'],
|
||||||
|
['name' => 'Administrator', 'description' => 'Full access to all features']
|
||||||
|
);
|
||||||
|
|
||||||
|
$moderatorRole = Role::firstOrCreate(
|
||||||
|
['slug' => 'moderator'],
|
||||||
|
['name' => 'Moderator', 'description' => 'Can moderate content and manage movies']
|
||||||
|
);
|
||||||
|
|
||||||
|
$userRole = Role::firstOrCreate(
|
||||||
|
['slug' => 'user'],
|
||||||
|
['name' => 'User', 'description' => 'Regular user with basic access']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assign permissions to admin (all permissions)
|
||||||
|
$allPermissions = Permission::all();
|
||||||
|
foreach ($allPermissions as $permission) {
|
||||||
|
if (!$adminRole->hasPermission($permission)) {
|
||||||
|
$adminRole->permissions()->attach($permission->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign permissions to moderator
|
||||||
|
$moderatorPermissions = Permission::whereIn('slug', [
|
||||||
|
'view-movies',
|
||||||
|
'create-movies',
|
||||||
|
'edit-movies',
|
||||||
|
'delete-movies',
|
||||||
|
'moderate-content',
|
||||||
|
])->get();
|
||||||
|
|
||||||
|
foreach ($moderatorPermissions as $permission) {
|
||||||
|
if (!$moderatorRole->hasPermission($permission)) {
|
||||||
|
$moderatorRole->permissions()->attach($permission->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign permissions to user
|
||||||
|
$userPermissions = Permission::whereIn('slug', [
|
||||||
|
'view-movies',
|
||||||
|
])->get();
|
||||||
|
|
||||||
|
foreach ($userPermissions as $permission) {
|
||||||
|
if (!$userRole->hasPermission($permission)) {
|
||||||
|
$userRole->permissions()->attach($permission->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->command->info('Roles and permissions seeded successfully!');
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
-5
@@ -764,6 +764,52 @@ $fa-font-path: "/fonts";
|
|||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28224, 224, 224, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28224, 224, 224, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Star rating
|
||||||
|
.jq-star{
|
||||||
|
display: inline-block;
|
||||||
|
svg{
|
||||||
|
max-width: 20px;
|
||||||
|
max-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Movie page
|
||||||
|
.movie-page{
|
||||||
|
.card{
|
||||||
|
.card-header{
|
||||||
|
h1{
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1.7em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tagline{
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.cast-list{
|
||||||
|
.department{
|
||||||
|
.persons{
|
||||||
|
.person{
|
||||||
|
img{
|
||||||
|
max-width: 45px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right sidebar - add missing padding
|
||||||
|
.right-sidebar {
|
||||||
|
.trending-movies {
|
||||||
|
.movie-item {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.light-mode{
|
body.light-mode{
|
||||||
@@ -1343,6 +1389,7 @@ body.light-mode{
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
|
background: white;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -1352,6 +1399,7 @@ body.light-mode{
|
|||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
|
color: #495057;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border-bottom: 1px solid #e0e0e0;
|
border-bottom: 1px solid #e0e0e0;
|
||||||
@@ -1359,6 +1407,7 @@ body.light-mode{
|
|||||||
h5 {
|
h5 {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: #495057;
|
||||||
|
|
||||||
.iconify {
|
.iconify {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
@@ -1369,13 +1418,15 @@ body.light-mode{
|
|||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
color: #495057;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-info-list {
|
.movie-info-list {
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
padding: 12px 15px;
|
background-color: white;
|
||||||
border-color: #e0e0e0;
|
border-color: #e0e0e0;
|
||||||
|
padding: 12px 15px;
|
||||||
|
|
||||||
.info-label {
|
.info-label {
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
@@ -1421,8 +1472,6 @@ body.light-mode{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.movie-info {
|
.movie-info {
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
h6 {
|
h6 {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
@@ -1434,7 +1483,6 @@ body.light-mode{
|
|||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
.iconify {
|
.iconify {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
@@ -1471,7 +1519,6 @@ body.light-mode{
|
|||||||
|
|
||||||
a {
|
a {
|
||||||
color: #495057;
|
color: #495057;
|
||||||
text-decoration: none;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px 15px;
|
padding: 12px 15px;
|
||||||
@@ -1486,6 +1533,7 @@ body.light-mode{
|
|||||||
&:hover {
|
&:hover {
|
||||||
color: #0d6efd;
|
color: #0d6efd;
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user