From 473f1c11a12ac0b123f2f673a6817f0cb2a404c8 Mon Sep 17 00:00:00 2001 From: Phan An Date: Sun, 7 Jan 2024 13:43:10 +0100 Subject: [PATCH] feat: adapt downloading to Plus --- app/Casts/LicenseInstanceCast.php | 2 +- app/Casts/LicenseMetaCast.php | 2 +- .../Commands/ActivateLicenseCommand.php | 2 +- .../Commands/CheckLicenseStatusCommand.php | 2 +- app/Console/Commands/ScanCommand.php | 37 ++++---- app/Facades/Download.php | 1 + app/Facades/License.php | 1 + .../Download/DownloadAlbumController.php | 8 +- .../Download/DownloadArtistController.php | 14 ++- .../Download/DownloadFavoritesController.php | 6 +- .../Download/DownloadPlaylistController.php | 24 ++++- .../Download/DownloadSongsController.php | 3 + app/Models/SongZipArchive.php | 2 +- app/Policies/PlaylistPolicy.php | 5 ++ app/Policies/SongPolicy.php | 9 ++ app/Providers/MacroProvider.php | 16 ++++ app/Repositories/AlbumRepository.php | 1 - app/Repositories/ArtistRepository.php | 2 +- app/Repositories/SongRepository.php | 30 +++---- app/Services/DownloadService.php | 90 ++++--------------- app/Services/LicenseService.php | 2 +- routes/web.base.php | 16 ++-- tests/Feature/UploadTest.php | 2 +- .../Integration/Services/MediaScannerTest.php | 54 ++++++----- .../Services/UploadServiceTest.php | 2 +- tests/TestCase.php | 15 ---- 26 files changed, 175 insertions(+), 173 deletions(-) diff --git a/app/Casts/LicenseInstanceCast.php b/app/Casts/LicenseInstanceCast.php index 493ba84e..fcecb073 100644 --- a/app/Casts/LicenseInstanceCast.php +++ b/app/Casts/LicenseInstanceCast.php @@ -25,7 +25,7 @@ class LicenseInstanceCast implements CastsAttributes } } - /** @param LicenseInstance $value */ + /** @param ?LicenseInstance $value */ public function set($model, string $key, $value, array $attributes): ?string { try { diff --git a/app/Casts/LicenseMetaCast.php b/app/Casts/LicenseMetaCast.php index 669902ca..e473c95e 100644 --- a/app/Casts/LicenseMetaCast.php +++ b/app/Casts/LicenseMetaCast.php @@ -25,7 +25,7 @@ class LicenseMetaCast implements CastsAttributes } } - /** @param LicenseMeta $value */ + /** @param ?LicenseMeta $value */ public function set($model, string $key, $value, array $attributes): ?string { try { diff --git a/app/Console/Commands/ActivateLicenseCommand.php b/app/Console/Commands/ActivateLicenseCommand.php index 73aa2ab6..03ca88f6 100644 --- a/app/Console/Commands/ActivateLicenseCommand.php +++ b/app/Console/Commands/ActivateLicenseCommand.php @@ -39,7 +39,7 @@ class ActivateLicenseCommand extends Command $this->components->twoColumnDetail('Expires On', 'Never ever'); - $this->line(''); + $this->newLine(); return self::SUCCESS; } diff --git a/app/Console/Commands/CheckLicenseStatusCommand.php b/app/Console/Commands/CheckLicenseStatusCommand.php index e9b2f235..252dc137 100644 --- a/app/Console/Commands/CheckLicenseStatusCommand.php +++ b/app/Console/Commands/CheckLicenseStatusCommand.php @@ -35,7 +35,7 @@ class CheckLicenseStatusCommand extends Command ); $this->components->twoColumnDetail('Expires On', 'Never ever'); - $this->line(''); + $this->newLine(); break; case LicenseStatus::STATUS_NO_LICENSE: diff --git a/app/Console/Commands/ScanCommand.php b/app/Console/Commands/ScanCommand.php index 4cfb371a..f1ac9dbb 100644 --- a/app/Console/Commands/ScanCommand.php +++ b/app/Console/Commands/ScanCommand.php @@ -27,7 +27,6 @@ class ScanCommand extends Command protected $description = 'Scan for songs in the configured directory.'; private ?string $mediaPath; - private ?User $owner; private ProgressBar $progressBar; public function __construct(private MediaScanner $mediaScanner) @@ -50,15 +49,22 @@ class ScanCommand extends Command public function handle(): int { - $this->owner = $this->getOwner(); $this->mediaPath = $this->getMediaPath(); + $config = ScanConfiguration::make( + owner: $this->getOwner(), + // When scanning via CLI, the songs should be public by default, unless explicitly specified otherwise. + makePublic: !$this->option('private'), + ignores: collect($this->option('ignore'))->sort()->values()->all(), + force: $this->option('force') + ); + $record = $this->argument('record'); if ($record) { - $this->scanSingleRecord($record); + $this->scanSingleRecord($record, $config); } else { - $this->scanMediaPath(); + $this->scanMediaPath($config); } return self::SUCCESS; @@ -67,27 +73,14 @@ class ScanCommand extends Command /** * Scan all files in the configured media path. */ - private function scanMediaPath(): void + private function scanMediaPath(ScanConfiguration $config): void { $this->components->info('Scanning ' . $this->mediaPath); - // The tags to ignore from scanning. - // Notice that this is only meaningful for existing records. - // New records will have every applicable field scanned. - $ignores = collect($this->option('ignore'))->sort()->values()->all(); - - if ($ignores) { - $this->components->info('Ignoring tag(s): ' . implode(', ', $ignores)); + if ($config->ignores) { + $this->components->info('Ignoring tag(s): ' . implode(', ', $config->ignores)); } - $config = ScanConfiguration::make( - owner: $this->owner, - // When scanning via CLI, the songs should be public by default, unless explicitly specified otherwise. - makePublic: !$this->option('private'), - ignores: $ignores, - force: $this->option('force') - ); - $results = $this->mediaScanner->scan($config); $this->newLine(2); @@ -110,9 +103,9 @@ class ScanCommand extends Command * * @see http://man7.org/linux/man-pages/man1/inotifywait.1.html */ - private function scanSingleRecord(string $record): void + private function scanSingleRecord(string $record, ScanConfiguration $config): void { - $this->mediaScanner->scanWatchRecord(new InotifyWatchRecord($record)); + $this->mediaScanner->scanWatchRecord(new InotifyWatchRecord($record), $config); } public function onScanProgress(ScanResult $result): void diff --git a/app/Facades/Download.php b/app/Facades/Download.php index fc7e9a21..9c98d8ac 100644 --- a/app/Facades/Download.php +++ b/app/Facades/Download.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Facade; /** * @method static string fromSong(Song $song) + * @see \App\Services\DownloadService */ class Download extends Facade { diff --git a/app/Facades/License.php b/app/Facades/License.php index 93c6a2de..a06888a4 100644 --- a/app/Facades/License.php +++ b/app/Facades/License.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Facade; /** * @method static bool isPlus() * @method static bool isCommunity() + * @see \App\Services\LicenseService */ class License extends Facade { diff --git a/app/Http/Controllers/Download/DownloadAlbumController.php b/app/Http/Controllers/Download/DownloadAlbumController.php index 73a4d5fa..af39d751 100644 --- a/app/Http/Controllers/Download/DownloadAlbumController.php +++ b/app/Http/Controllers/Download/DownloadAlbumController.php @@ -4,12 +4,16 @@ namespace App\Http\Controllers\Download; use App\Http\Controllers\Controller; use App\Models\Album; +use App\Models\User; +use App\Repositories\SongRepository; use App\Services\DownloadService; +use Illuminate\Contracts\Auth\Authenticatable; class DownloadAlbumController extends Controller { - public function __invoke(Album $album, DownloadService $download) + /** @param User $user */ + public function __invoke(Album $album, SongRepository $repository, DownloadService $download, Authenticatable $user) { - return response()->download($download->from($album)); + return response()->download($download->from($repository->getByAlbum($album, $user))); } } diff --git a/app/Http/Controllers/Download/DownloadArtistController.php b/app/Http/Controllers/Download/DownloadArtistController.php index 7e6cee25..bbd7a02a 100644 --- a/app/Http/Controllers/Download/DownloadArtistController.php +++ b/app/Http/Controllers/Download/DownloadArtistController.php @@ -4,12 +4,20 @@ namespace App\Http\Controllers\Download; use App\Http\Controllers\Controller; use App\Models\Artist; +use App\Models\User; +use App\Repositories\SongRepository; use App\Services\DownloadService; +use Illuminate\Contracts\Auth\Authenticatable; class DownloadArtistController extends Controller { - public function __invoke(Artist $artist, DownloadService $download) - { - return response()->download($download->from($artist)); + /** @param User $user */ + public function __invoke( + Artist $artist, + SongRepository $repository, + DownloadService $download, + Authenticatable $user + ) { + return response()->download($download->from($repository->getByArtist($artist, $user))); } } diff --git a/app/Http/Controllers/Download/DownloadFavoritesController.php b/app/Http/Controllers/Download/DownloadFavoritesController.php index c05876d5..7423eef1 100644 --- a/app/Http/Controllers/Download/DownloadFavoritesController.php +++ b/app/Http/Controllers/Download/DownloadFavoritesController.php @@ -4,15 +4,15 @@ namespace App\Http\Controllers\Download; use App\Http\Controllers\Controller; use App\Models\User; -use App\Repositories\InteractionRepository; +use App\Repositories\SongRepository; use App\Services\DownloadService; use Illuminate\Contracts\Auth\Authenticatable; class DownloadFavoritesController extends Controller { /** @param User $user */ - public function __invoke(DownloadService $download, InteractionRepository $repository, Authenticatable $user) + public function __invoke(DownloadService $download, SongRepository $repository, Authenticatable $user) { - return response()->download($download->from($repository->getUserFavorites($user))); + return response()->download($download->from($repository->getFavorites($user))); } } diff --git a/app/Http/Controllers/Download/DownloadPlaylistController.php b/app/Http/Controllers/Download/DownloadPlaylistController.php index 202ef4d1..d1e95f38 100644 --- a/app/Http/Controllers/Download/DownloadPlaylistController.php +++ b/app/Http/Controllers/Download/DownloadPlaylistController.php @@ -4,14 +4,30 @@ namespace App\Http\Controllers\Download; use App\Http\Controllers\Controller; use App\Models\Playlist; +use App\Models\User; +use App\Repositories\SongRepository; use App\Services\DownloadService; +use App\Services\SmartPlaylistService; +use Illuminate\Contracts\Auth\Authenticatable; class DownloadPlaylistController extends Controller { - public function __invoke(Playlist $playlist, DownloadService $download) - { - $this->authorize('own', $playlist); + /** @param User $user */ + public function __invoke( + Playlist $playlist, + SongRepository $repository, + SmartPlaylistService $smartPlaylistService, + DownloadService $download, + Authenticatable $user + ) { + $this->authorize('download', $playlist); - return response()->download($download->from($playlist)); + return response()->download( + $download->from( + $playlist->is_smart + ? $smartPlaylistService->getSongs($playlist, $user) + : $repository->getByStandardPlaylist($playlist, $user) + ) + ); } } diff --git a/app/Http/Controllers/Download/DownloadSongsController.php b/app/Http/Controllers/Download/DownloadSongsController.php index e86f7965..729e3fbe 100644 --- a/app/Http/Controllers/Download/DownloadSongsController.php +++ b/app/Http/Controllers/Download/DownloadSongsController.php @@ -11,6 +11,9 @@ class DownloadSongsController extends Controller { public function __invoke(DownloadSongsRequest $request, DownloadService $download, SongRepository $repository) { + $songs = $repository->getMany($request->songs); + $songs->each(fn ($song) => $this->authorize('download', $song)); + return response()->download($download->from($repository->getMany($request->songs))); } } diff --git a/app/Models/SongZipArchive.php b/app/Models/SongZipArchive.php index c8dc23c0..e6636647 100644 --- a/app/Models/SongZipArchive.php +++ b/app/Models/SongZipArchive.php @@ -18,7 +18,7 @@ class SongZipArchive */ private array $fileNames = []; - public function __construct(string $path = '') + public function __construct(?string $path = null) { $this->path = $path ?: self::generateRandomArchivePath(); diff --git a/app/Policies/PlaylistPolicy.php b/app/Policies/PlaylistPolicy.php index e43462e9..39cc9460 100644 --- a/app/Policies/PlaylistPolicy.php +++ b/app/Policies/PlaylistPolicy.php @@ -11,4 +11,9 @@ class PlaylistPolicy { return $playlist->user->is($user); } + + public function download(User $user, Playlist $playlist): bool + { + return $this->own($user, $playlist); + } } diff --git a/app/Policies/SongPolicy.php b/app/Policies/SongPolicy.php index ac441f1c..9c1a717e 100644 --- a/app/Policies/SongPolicy.php +++ b/app/Policies/SongPolicy.php @@ -27,4 +27,13 @@ class SongPolicy { return (License::isCommunity() && $user->is_admin) || $song->owner_id === $user->id; } + + public function download(User $user, Song $song): bool + { + if (!config('koel.download.allow')) { + return false; + } + + return License::isCommunity() || $song->is_public || $song->owner_id === $user->id; + } } diff --git a/app/Providers/MacroProvider.php b/app/Providers/MacroProvider.php index 3e0a5dfb..e370baf6 100644 --- a/app/Providers/MacroProvider.php +++ b/app/Providers/MacroProvider.php @@ -3,9 +3,12 @@ namespace App\Providers; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\UploadedFile; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; +use Illuminate\Testing\TestResponse; class MacroProvider extends ServiceProvider { @@ -22,5 +25,18 @@ class MacroProvider extends ServiceProvider return $this; }); + + if (app()->runningUnitTests()) { + UploadedFile::macro('fromFile', static function (string $path, ?string $name = null): UploadedFile { + return UploadedFile::fake()->createWithContent($name ?? basename($path), File::get($path)); + }); + + TestResponse::macro('log', function (string $file = 'test-response.json'): TestResponse { + /** @var TestResponse $this */ + File::put(storage_path('logs/' . $file), $this->getContent()); + + return $this; + }); + } } } diff --git a/app/Repositories/AlbumRepository.php b/app/Repositories/AlbumRepository.php index b2643a7a..d40a733b 100644 --- a/app/Repositories/AlbumRepository.php +++ b/app/Repositories/AlbumRepository.php @@ -28,7 +28,6 @@ class AlbumRepository extends Repository /** @return Collection|array */ public function getMostPlayed(int $count = 6, ?User $user = null): Collection { - /** @var User $user */ $user ??= $this->auth->user(); $query = Album::query() diff --git a/app/Repositories/ArtistRepository.php b/app/Repositories/ArtistRepository.php index 91383e08..6df89d10 100644 --- a/app/Repositories/ArtistRepository.php +++ b/app/Repositories/ArtistRepository.php @@ -14,7 +14,7 @@ class ArtistRepository extends Repository /** @return Collection|array */ public function getMostPlayed(int $count = 6, ?User $user = null): Collection { - /** @var User $user */ + /** @var ?User $user */ $user ??= auth()->user(); $query = Artist::query() diff --git a/app/Repositories/SongRepository.php b/app/Repositories/SongRepository.php index e8df3f26..deb3ba89 100644 --- a/app/Repositories/SongRepository.php +++ b/app/Repositories/SongRepository.php @@ -29,7 +29,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getRecentlyAdded(int $count = 10, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -43,7 +43,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getMostPlayed(int $count = 7, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -58,7 +58,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getRecentlyPlayed(int $count = 7, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -75,7 +75,7 @@ class SongRepository extends Repository ?User $scopedUser = null, int $perPage = 50 ): Paginator { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -92,7 +92,7 @@ class SongRepository extends Repository ?User $scopedUser = null, int $perPage = 50 ): Paginator { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -110,7 +110,7 @@ class SongRepository extends Repository int $limit = self::DEFAULT_QUEUE_LIMIT, ?User $scopedUser = null, ): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -124,7 +124,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getFavorites(?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -137,7 +137,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getByAlbum(Album $album, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -153,7 +153,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getByArtist(Artist $artist, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -171,7 +171,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getByStandardPlaylist(Playlist $playlist, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -187,7 +187,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getRandom(int $limit, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -201,7 +201,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getMany(array $ids, bool $inThatOrder = false, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); $songs = Song::query() @@ -215,7 +215,7 @@ class SongRepository extends Repository public function getOne($id, ?User $scopedUser = null): Song { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -226,7 +226,7 @@ class SongRepository extends Repository public function findOne($id, ?User $scopedUser = null): ?Song { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() @@ -248,7 +248,7 @@ class SongRepository extends Repository /** @return Collection|array */ public function getRandomByGenre(string $genre, int $limit, ?User $scopedUser = null): Collection { - /** @var User $scopedUser */ + /** @var ?User $scopedUser */ $scopedUser ??= $this->auth->user(); return Song::query() diff --git a/app/Services/DownloadService.php b/app/Services/DownloadService.php index 854a2a40..cb8346ce 100644 --- a/app/Services/DownloadService.php +++ b/app/Services/DownloadService.php @@ -2,14 +2,11 @@ namespace App\Services; -use App\Models\Album; -use App\Models\Artist; -use App\Models\Playlist; use App\Models\Song; use App\Models\SongZipArchive; -use Illuminate\Database\Eloquent\Collection as EloquentCollection; +use Illuminate\Http\Response; use Illuminate\Support\Collection; -use InvalidArgumentException; +use Illuminate\Support\Facades\File; class DownloadService { @@ -17,57 +14,7 @@ class DownloadService { } - /** - * Generic method to generate a download archive from various source types. - * - * @return string Full path to the generated archive - */ - public function from(Playlist|Song|Album|Artist|Collection $downloadable): string - { - switch (get_class($downloadable)) { - case Song::class: - return $this->fromSong($downloadable); - - case Collection::class: - case EloquentCollection::class: - return $this->fromMultipleSongs($downloadable); - - case Album::class: - return $this->fromAlbum($downloadable); - - case Artist::class: - return $this->fromArtist($downloadable); - - case Playlist::class: - return $this->fromPlaylist($downloadable); - } - - throw new InvalidArgumentException('Unsupported download type.'); - } - - public function fromSong(Song $song): string - { - if ($song->s3_params) { - // The song is hosted on Amazon S3. - // We download it back to our local server first. - $url = $this->s3Service->getSongPublicUrl($song); - abort_unless((bool) $url, 404); - - $localPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . basename($song->s3_params['key']); - - // The following function requires allow_url_fopen to be ON. - // We're just assuming that to be the case here. - copy($url, $localPath); - } else { - // The song is hosted locally. Make sure the file exists. - $localPath = $song->path; - abort_unless(file_exists($localPath), 404); - } - - return $localPath; - } - - private function fromMultipleSongs(Collection $songs): string + public function from(Collection $songs): string { if ($songs->count() === 1) { return $this->fromSong($songs->first()); @@ -79,24 +26,25 @@ class DownloadService ->getPath(); } - private function fromPlaylist(Playlist $playlist): string + public function fromSong(Song $song): string { - return $this->fromMultipleSongs($playlist->songs); - } + if ($song->s3_params) { + // The song is hosted on Amazon S3. + // We download it back to our local server first. + $url = $this->s3Service->getSongPublicUrl($song); + abort_unless((bool) $url, Response::HTTP_NOT_FOUND); - private function fromAlbum(Album $album): string - { - return $this->fromMultipleSongs($album->songs); - } + $localPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . basename($song->s3_params['key']); - public function fromArtist(Artist $artist): string - { - // We cater to the case where the artist is an "album artist," which means she has songs through albums as well. - $songs = $artist->albums->reduce( - static fn (Collection $songs, Album $album) => $songs->merge($album->songs), - $artist->songs - )->unique('id'); + // The following function requires allow_url_fopen to be ON. + // We're just assuming that to be the case here. + copy($url, $localPath); + } else { + // The song is hosted locally. Make sure the file exists. + $localPath = $song->path; + abort_unless(File::exists($localPath), Response::HTTP_NOT_FOUND); + } - return $this->fromMultipleSongs($songs); + return $localPath; } } diff --git a/app/Services/LicenseService.php b/app/Services/LicenseService.php index 0ad1408f..a3797fb4 100644 --- a/app/Services/LicenseService.php +++ b/app/Services/LicenseService.php @@ -42,7 +42,7 @@ class LicenseService return Cache::get('license_status'); } - /** @var License $license */ + /** @var ?License $license */ $license = License::query()->latest()->first(); if (!$license) { diff --git a/routes/web.base.php b/routes/web.base.php index 41504c00..a4f7995c 100644 --- a/routes/web.base.php +++ b/routes/web.base.php @@ -30,12 +30,14 @@ Route::middleware('web')->group(static function (): void { Route::middleware('audio.auth')->group(static function (): void { Route::get('play/{song}/{transcode?}/{bitrate?}', PlayController::class)->name('song.play'); - Route::prefix('download')->group(static function (): void { - Route::get('songs', DownloadSongsController::class); - Route::get('album/{album}', DownloadAlbumController::class); - Route::get('artist/{artist}', DownloadArtistController::class); - Route::get('playlist/{playlist}', DownloadPlaylistController::class); - Route::get('favorites', DownloadFavoritesController::class); - }); + if (config('koel.download.allow')) { + Route::prefix('download')->group(static function (): void { + Route::get('songs', DownloadSongsController::class); + Route::get('album/{album}', DownloadAlbumController::class); + Route::get('artist/{artist}', DownloadArtistController::class); + Route::get('playlist/{playlist}', DownloadPlaylistController::class); + Route::get('favorites', DownloadFavoritesController::class); + }); + } }); }); diff --git a/tests/Feature/UploadTest.php b/tests/Feature/UploadTest.php index 8b88ef28..42136c19 100644 --- a/tests/Feature/UploadTest.php +++ b/tests/Feature/UploadTest.php @@ -19,7 +19,7 @@ class UploadTest extends TestCase { parent::setUp(); - $this->file = UploadedFile::fromFile(test_path('songs/full.mp3'), 'song.mp3'); + $this->file = UploadedFile::fromFile(test_path('songs/full.mp3'), 'song.mp3'); //@phpstan-ignore-line } public function testUnauthorizedPost(): void diff --git a/tests/Integration/Services/MediaScannerTest.php b/tests/Integration/Services/MediaScannerTest.php index 18e234ac..61465dfb 100644 --- a/tests/Integration/Services/MediaScannerTest.php +++ b/tests/Integration/Services/MediaScannerTest.php @@ -37,11 +37,10 @@ class MediaScannerTest extends TestCase public function testScan(): void { - /** @var User $owner */ - $owner = User::factory()->admin()->create(); - $this->expectsEvents(MediaScanCompleted::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); $this->scanner->scan(ScanConfiguration::make(owner: $owner)); // Standard mp3 files under root path should be recognized @@ -94,10 +93,11 @@ class MediaScannerTest extends TestCase public function testModifiedFileIsRescanned(): void { - $config = ScanConfiguration::make(owner: User::factory()->admin()->create()); - $this->expectsEvents(MediaScanCompleted::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); + $config = ScanConfiguration::make(owner: $owner); $this->scanner->scan($config); /** @var Song $song */ @@ -111,10 +111,12 @@ class MediaScannerTest extends TestCase public function testRescanWithoutForceDoesNotResetData(): void { - $config = ScanConfiguration::make(owner: User::factory()->admin()->create()); - $this->expectsEvents(MediaScanCompleted::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); + $config = ScanConfiguration::make(owner: $owner); + $this->scanner->scan($config); /** @var Song $song */ @@ -134,11 +136,10 @@ class MediaScannerTest extends TestCase public function testForceScanResetsData(): void { - /** @var User $owner */ - $owner = User::factory()->admin()->create(); - $this->expectsEvents(MediaScanCompleted::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); $this->scanner->scan(ScanConfiguration::make(owner: $owner)); /** @var Song $song */ @@ -149,7 +150,9 @@ class MediaScannerTest extends TestCase 'lyrics' => 'Booom Wroooom', ]); - $this->scanner->scan(ScanConfiguration::make(owner: User::factory()->admin()->create(), force: true)); + /** @var User $anotherOwner */ + $anotherOwner = User::factory()->admin()->create(); + $this->scanner->scan(ScanConfiguration::make(owner: $anotherOwner, force: true)); $song->refresh(); @@ -161,11 +164,10 @@ class MediaScannerTest extends TestCase public function testScanWithIgnoredTags(): void { - /** @var User $owner */ - $owner = User::factory()->admin()->create(); - $this->expectsEvents(MediaScanCompleted::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); $this->scanner->scan(ScanConfiguration::make(owner: $owner)); /** @var Song $song */ @@ -186,10 +188,10 @@ class MediaScannerTest extends TestCase public function testScanAllTagsForNewFilesRegardlessOfIgnoredOption(): void { + $this->expectsEvents(MediaScanCompleted::class); + /** @var User $owner */ $owner = User::factory()->admin()->create(); - - $this->expectsEvents(MediaScanCompleted::class); $this->scanner->scan(ScanConfiguration::make(owner: $owner)); /** @var Song $song */ @@ -214,11 +216,14 @@ class MediaScannerTest extends TestCase { $this->expectsEvents(LibraryChanged::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); + $path = $this->path('/blank.mp3'); $this->scanner->scanWatchRecord( new InotifyWatchRecord("CLOSE_WRITE,CLOSE $path"), - ScanConfiguration::make(owner: User::factory()->admin()->create()) + ScanConfiguration::make(owner: $owner) ); self::assertDatabaseHas(Song::class, ['path' => $path]); @@ -228,6 +233,9 @@ class MediaScannerTest extends TestCase { $this->expectsEvents(LibraryChanged::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); + static::createSampleMediaSet(); /** @var Song $song */ @@ -235,7 +243,7 @@ class MediaScannerTest extends TestCase $this->scanner->scanWatchRecord( new InotifyWatchRecord("DELETE $song->path"), - ScanConfiguration::make(owner: User::factory()->admin()->create()) + ScanConfiguration::make(owner: $owner) ); self::assertModelMissing($song); @@ -243,10 +251,12 @@ class MediaScannerTest extends TestCase public function testScanDeletedDirectoryViaWatch(): void { - $config = ScanConfiguration::make(owner: User::factory()->admin()->create()); - $this->expectsEvents(LibraryChanged::class, MediaScanCompleted::class); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); + $config = ScanConfiguration::make(owner: $owner); + $this->scanner->scan($config); $this->scanner->scanWatchRecord(new InotifyWatchRecord("MOVED_FROM,ISDIR $this->mediaPath/subdir"), $config); @@ -290,7 +300,9 @@ class MediaScannerTest extends TestCase public function testOptionallyIgnoreHiddenFiles(): void { - $config = ScanConfiguration::make(owner: User::factory()->admin()->create()); + /** @var User $owner */ + $owner = User::factory()->admin()->create(); + $config = ScanConfiguration::make(owner: $owner); config(['koel.ignore_dot_files' => false]); $this->scanner->scan($config); diff --git a/tests/Integration/Services/UploadServiceTest.php b/tests/Integration/Services/UploadServiceTest.php index 4d913d07..58f301ff 100644 --- a/tests/Integration/Services/UploadServiceTest.php +++ b/tests/Integration/Services/UploadServiceTest.php @@ -51,7 +51,7 @@ class UploadServiceTest extends TestCase /** @var User $user */ $user = User::factory()->create(); - $song = $this->service->handleUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); + $song = $this->service->handleUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line self::assertSame($song->owner_id, $user->id); self::assertSame(public_path("sandbox/media/__KOEL_UPLOADS_\${$user->id}__/full.mp3"), $song->path); diff --git a/tests/TestCase.php b/tests/TestCase.php index 5874636a..fa85eba4 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -10,9 +10,6 @@ use App\Services\CommunityLicenseService; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; -use Illuminate\Http\UploadedFile; -use Illuminate\Support\Facades\File; -use Illuminate\Testing\TestResponse; use ReflectionClass; use Tests\Traits\CreatesApplication; use Tests\Traits\SandboxesTests; @@ -29,18 +26,6 @@ abstract class TestCase extends BaseTestCase parent::setUp(); License::swap($this->app->make(CommunityLicenseService::class)); - - TestResponse::macro('log', function (string $file = 'test-response.json'): TestResponse { - /** @var TestResponse $this */ - File::put(storage_path('logs/' . $file), $this->getContent()); - - return $this; - }); - - UploadedFile::macro('fromFile', static function (string $path, ?string $name = null): UploadedFile { - return UploadedFile::fake()->createWithContent($name ?? basename($path), File::get($path)); - }); - self::createSandbox(); }