mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
fix(cs): broken static analysis
This commit is contained in:
parent
e4ca67bc69
commit
a3c1f7aec4
39 changed files with 186 additions and 217 deletions
3
.github/workflows/e2e.yml
vendored
3
.github/workflows/e2e.yml
vendored
|
@ -3,7 +3,8 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
# @fixme Tmp.disable until ready
|
||||
# - next
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: [ 7.4, 8.0, 8.1 ]
|
||||
php-version: [ 8.0, 8.1 ]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
|
@ -6,7 +6,6 @@ use App\Console\Commands\Traits\AskForPassword;
|
|||
use App\Exceptions\InstallationFailedException;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Repositories\SettingRepository;
|
||||
use App\Services\MediaCacheService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel as Artisan;
|
||||
|
@ -27,30 +26,16 @@ class InitCommand extends Command
|
|||
protected $signature = 'koel:init {--no-assets}';
|
||||
protected $description = 'Install or upgrade Koel';
|
||||
|
||||
private MediaCacheService $mediaCacheService;
|
||||
private Artisan $artisan;
|
||||
private DotenvEditor $dotenvEditor;
|
||||
private Hash $hash;
|
||||
private DB $db;
|
||||
private SettingRepository $settingRepository;
|
||||
private bool $adminSeeded = false;
|
||||
|
||||
public function __construct(
|
||||
MediaCacheService $mediaCacheService,
|
||||
SettingRepository $settingRepository,
|
||||
Artisan $artisan,
|
||||
Hash $hash,
|
||||
DotenvEditor $dotenvEditor,
|
||||
DB $db
|
||||
private MediaCacheService $mediaCacheService,
|
||||
private Artisan $artisan,
|
||||
private Hash $hash,
|
||||
private DotenvEditor $dotenvEditor,
|
||||
private DB $db
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->mediaCacheService = $mediaCacheService;
|
||||
$this->artisan = $artisan;
|
||||
$this->dotenvEditor = $dotenvEditor;
|
||||
$this->hash = $hash;
|
||||
$this->db = $db;
|
||||
$this->settingRepository = $settingRepository;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
|
|
|
@ -7,17 +7,13 @@ use App\Http\Resources\ArtistResource;
|
|||
use App\Models\Artist;
|
||||
use App\Models\User;
|
||||
use App\Repositories\ArtistRepository;
|
||||
use App\Services\MediaInformationService;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
|
||||
class ArtistController extends Controller
|
||||
{
|
||||
/** @param User $user */
|
||||
public function __construct(
|
||||
private ArtistRepository $artistRepository,
|
||||
private MediaInformationService $informationService,
|
||||
private ?Authenticatable $user
|
||||
) {
|
||||
public function __construct(private ArtistRepository $artistRepository, private ?Authenticatable $user)
|
||||
{
|
||||
}
|
||||
|
||||
public function index()
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Http\Controllers\V6\Requests;
|
|||
use App\Http\Requests\API\Request;
|
||||
|
||||
/**
|
||||
* @property-read array<string> songs
|
||||
* @property-read array<string> $songs
|
||||
*/
|
||||
class AddSongsToPlaylistRequest extends Request
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Http\Controllers\V6\Requests;
|
|||
use App\Http\Requests\API\Request;
|
||||
|
||||
/**
|
||||
* @property-read array<string> songs
|
||||
* @property-read array<string> $songs
|
||||
*/
|
||||
class RemoveSongsFromPlaylistRequest extends Request
|
||||
{
|
||||
|
|
|
@ -31,6 +31,9 @@ use Laravel\Scout\Searchable;
|
|||
* Notice that this doesn't guarantee the thumbnail exists.
|
||||
* @property string|null $thumbnail The public URL to the album's thumbnail
|
||||
* @property Carbon $created_at
|
||||
* @property float|string $length Total length of the album in seconds (dynamically calculated)
|
||||
* @property int|string $play_count Total number of times the album's songs have been played (dynamically calculated)
|
||||
* @property int|string $song_count Total number of songs on the album (dynamically calculated)
|
||||
*
|
||||
* @method static self firstOrCreate(array $where, array $params = [])
|
||||
* @method static self|null find(int $id)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Facades\Util;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Database\Query\Builder as BuilderContract;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
@ -24,6 +25,11 @@ use Laravel\Scout\Searchable;
|
|||
* @property Collection $songs
|
||||
* @property bool $has_image If the artist has a (non-default) image
|
||||
* @property string|null $image_path Absolute path to the artist's image
|
||||
* @property float|string $length Total length of the artist's songs in seconds (dynamically calculated)
|
||||
* @property string|int $play_count Total number of times the artist has been played (dynamically calculated)
|
||||
* @property string|int $song_count Total number of songs by the artist (dynamically calculated)
|
||||
* @property string|int $album_count Total number of albums by the artist (dynamically calculated)
|
||||
* @property Carbon $created_at
|
||||
*
|
||||
* @method static self find(int $id)
|
||||
* @method static self firstOrCreate(array $where, array $params = [])
|
||||
|
|
|
@ -54,7 +54,6 @@ class Playlist extends Model
|
|||
return Attribute::get(fn (): bool => $this->rule_groups->isNotEmpty());
|
||||
}
|
||||
|
||||
/** @return Collection|array<array-key, SmartPlaylistRuleGroup> */
|
||||
protected function ruleGroups(): Attribute
|
||||
{
|
||||
// aliasing the attribute to avoid confusion
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
@ -27,6 +28,9 @@ use Laravel\Scout\Searchable;
|
|||
* @property int $artist_id
|
||||
* @property int $mtime
|
||||
* @property int $contributing_artist_id
|
||||
* @property ?bool $liked Whether the song is liked by the current user (dynamically calculated)
|
||||
* @property ?int $play_count The number of times the song has been played by the current user (dynamically calculated)
|
||||
* @property Carbon $created_at
|
||||
*
|
||||
* @method static self updateOrCreate(array $where, array $params)
|
||||
* @method static Builder select(string $string)
|
||||
|
|
|
@ -6,17 +6,12 @@ use Illuminate\Database\Eloquent\Builder;
|
|||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
/**
|
||||
* @property array<string>|null $s3_params
|
||||
* @property array<string>|null $s3_params The bucket and key name of an S3 object.
|
||||
*
|
||||
* @method static Builder hostedOnS3()
|
||||
*/
|
||||
trait SupportsS3
|
||||
{
|
||||
/**
|
||||
* Get the bucket and key name of an S3 object.
|
||||
*
|
||||
* @return array<string>|null
|
||||
*/
|
||||
protected function s3Params(): Attribute
|
||||
{
|
||||
return Attribute::get(function (): ?array {
|
||||
|
|
|
@ -16,7 +16,7 @@ use Laravel\Sanctum\HasApiTokens;
|
|||
* @property UserPreferences $preferences
|
||||
* @property int $id
|
||||
* @property bool $is_admin
|
||||
* @property string $lastfm_session_key
|
||||
* @property ?string $lastfm_session_key
|
||||
* @property string $name
|
||||
* @property string $email
|
||||
* @property string $password
|
||||
|
@ -25,6 +25,7 @@ use Laravel\Sanctum\HasApiTokens;
|
|||
* @method static self create(array $params)
|
||||
* @method static int count()
|
||||
* @method static Builder where(...$params)
|
||||
* @method static self|null firstWhere(...$params)
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
|
@ -60,8 +61,6 @@ class User extends Authenticatable
|
|||
|
||||
/**
|
||||
* Get the user's Last.fm session key.
|
||||
*
|
||||
* @return string|null The key if found, or null if user isn't connected to Last.fm
|
||||
*/
|
||||
protected function lastfmSessionKey(): Attribute
|
||||
{
|
||||
|
|
|
@ -14,11 +14,6 @@ use Illuminate\Validation\Rules\Password;
|
|||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The policy mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $policies = [
|
||||
Playlist::class => PlaylistPolicy::class,
|
||||
User::class => UserPolicy::class,
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
namespace App\Repositories;
|
||||
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Throwable;
|
||||
|
||||
abstract class AbstractRepository implements RepositoryInterface
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Repositories;
|
|||
use App\Models\Album;
|
||||
use App\Models\User;
|
||||
use App\Repositories\Traits\Searchable;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class AlbumRepository extends AbstractRepository
|
||||
{
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace App\Repositories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface RepositoryInterface
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ use App\Repositories\Traits\Searchable;
|
|||
use App\Services\Helper;
|
||||
use Illuminate\Contracts\Database\Query\Builder;
|
||||
use Illuminate\Contracts\Pagination\Paginator;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Collection;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
class SongRepository extends AbstractRepository
|
||||
|
|
|
@ -157,7 +157,7 @@ class FileSynchronizer
|
|||
|
||||
$cover = $matches ? $matches[0] : null;
|
||||
|
||||
return $cover && static::isImage($cover) ? $cover : null;
|
||||
return $cover && self::isImage($cover) ? $cover : null;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,6 @@ class SearchService
|
|||
return $this->songRepository
|
||||
->search($keywords)
|
||||
->get()
|
||||
->map(static fn (Song $song): string => $song->id);
|
||||
->map(static fn (Song $song): string => $song->id); // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use SpotifyWebAPI\SpotifyWebAPI;
|
|||
use Throwable;
|
||||
|
||||
/**
|
||||
* @method array search(string $keywords, string|array $type, string|object $options = [])
|
||||
* @method array search(string $keywords, string|array $type, array|object $options = [])
|
||||
*/
|
||||
class SpotifyClient
|
||||
{
|
||||
|
|
|
@ -20,18 +20,12 @@ class TokenManager
|
|||
|
||||
public function deleteTokenByPlainTextToken(string $plainTextToken): void
|
||||
{
|
||||
$token = PersonalAccessToken::findToken($plainTextToken);
|
||||
|
||||
if ($token) {
|
||||
$token->delete();
|
||||
}
|
||||
PersonalAccessToken::findToken($plainTextToken)?->delete();
|
||||
}
|
||||
|
||||
public function getUserFromPlainTextToken(string $plainTextToken): ?User
|
||||
{
|
||||
$token = PersonalAccessToken::findToken($plainTextToken);
|
||||
|
||||
return $token ? $token->tokenable : null;
|
||||
return PersonalAccessToken::findToken($plainTextToken)?->tokenable;
|
||||
}
|
||||
|
||||
public function refreshToken(User $user): NewAccessToken
|
||||
|
|
|
@ -18,7 +18,7 @@ final class SongScanInformation implements Arrayable
|
|||
public ?int $track,
|
||||
public ?int $disc,
|
||||
public ?string $lyrics,
|
||||
public ?int $length,
|
||||
public ?float $length,
|
||||
public ?array $cover,
|
||||
public ?string $path,
|
||||
public ?int $mTime,
|
||||
|
|
|
@ -22,6 +22,8 @@ parameters:
|
|||
- '#Call to an undefined method Illuminate\\Filesystem\\FilesystemAdapter::getAdapter\(\)#'
|
||||
- '#Call to an undefined method Mockery\\ExpectationInterface|Mockery\\HigherOrderMessage::with\(\)#'
|
||||
- '#Call to an undefined method Laravel\\Scout\\Builder::with\(\)#'
|
||||
- '#Call to an undefined method Illuminate\\Contracts\\Database\\Query\\Builder::isStandard\(\)#'
|
||||
- '#Call to an undefined method Illuminate\\Contracts\\Database\\Query\\Builder::withMeta\(\)#'
|
||||
- '#should return App\\Models\\.*(\|null)? but returns Illuminate\\Database\\Eloquent\\Model(\|null)?#'
|
||||
# Laravel factories allow declaration of dynamic methods as "states"
|
||||
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Factories\\Factory::#'
|
||||
|
|
|
@ -7,10 +7,11 @@ use App\Models\Album;
|
|||
use App\Models\User;
|
||||
use App\Services\MediaMetadataService;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
|
||||
class AlbumCoverTest extends TestCase
|
||||
{
|
||||
private $mediaMetadataService;
|
||||
private MediaMetadataService|MockInterface $mediaMetadataService;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -23,21 +24,19 @@ class AlbumCoverTest extends TestCase
|
|||
{
|
||||
$this->expectsEvents(LibraryChanged::class);
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create();
|
||||
|
||||
/** @var Album $album */
|
||||
$album = Album::factory()->create(['id' => 9999]);
|
||||
|
||||
$this->mediaMetadataService
|
||||
->shouldReceive('writeAlbumCover')
|
||||
->once()
|
||||
->with(Mockery::on(static function (Album $album): bool {
|
||||
return $album->id === 9999;
|
||||
}), 'Foo', 'jpeg');
|
||||
->with(Mockery::on(static fn (Album $album) => $album->id === 9999), 'Foo', 'jpeg');
|
||||
|
||||
$response = $this->putAs('api/album/' . $album->id . '/cover', [
|
||||
'cover' => 'data:image/jpeg;base64,Rm9v',
|
||||
], User::factory()->admin()->create());
|
||||
|
||||
$response->assertStatus(200);
|
||||
$this->putAs('api/album/' . $album->id . '/cover', ['cover' => 'data:image/jpeg;base64,Rm9v'], $user)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function testUpdateNotAllowedForNormalUsers(): void
|
||||
|
@ -49,9 +48,10 @@ class AlbumCoverTest extends TestCase
|
|||
->shouldReceive('writeAlbumCover')
|
||||
->never();
|
||||
|
||||
$this->putAs('api/album/' . $album->id . '/cover', [
|
||||
'cover' => 'data:image/jpeg;base64,Rm9v',
|
||||
], User::factory()->create())
|
||||
->assertStatus(403);
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->putAs('api/album/' . $album->id . '/cover', ['cover' => 'data:image/jpeg;base64,Rm9v'], $user)
|
||||
->assertForbidden();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,7 @@ use Mockery\MockInterface;
|
|||
|
||||
class ArtistImageTest extends TestCase
|
||||
{
|
||||
/** @var MockInterface|MediaMetadataService */
|
||||
private $mediaMetadataService;
|
||||
private MediaMetadataService|MockInterface $mediaMetadataService;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -24,19 +23,19 @@ class ArtistImageTest extends TestCase
|
|||
public function testUpdate(): void
|
||||
{
|
||||
$this->expectsEvents(LibraryChanged::class);
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
Artist::factory()->create(['id' => 9999]);
|
||||
|
||||
$this->mediaMetadataService
|
||||
->shouldReceive('writeArtistImage')
|
||||
->once()
|
||||
->with(Mockery::on(static function (Artist $artist): bool {
|
||||
return $artist->id === 9999;
|
||||
}), 'Foo', 'jpeg');
|
||||
->with(Mockery::on(static fn (Artist $artist) => $artist->id === 9999), 'Foo', 'jpeg');
|
||||
|
||||
$this->putAs('api/artist/9999/image', [
|
||||
'image' => 'data:image/jpeg;base64,Rm9v',
|
||||
], User::factory()->admin()->create())
|
||||
->assertStatus(200);
|
||||
$this->putAs('api/artist/9999/image', ['image' => 'data:image/jpeg;base64,Rm9v'], $admin)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function testUpdateNotAllowedForNormalUsers(): void
|
||||
|
@ -47,9 +46,7 @@ class ArtistImageTest extends TestCase
|
|||
->shouldReceive('writeArtistImage')
|
||||
->never();
|
||||
|
||||
$this->putAs('api/artist/9999/image', [
|
||||
'image' => 'data:image/jpeg;base64,Rm9v',
|
||||
], User::factory()->create())
|
||||
->assertStatus(403);
|
||||
$this->putAs('api/artist/9999/image', ['image' => 'data:image/jpeg;base64,Rm9v'])
|
||||
->assertForbidden();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ use App\Models\Song;
|
|||
use App\Models\User;
|
||||
use App\Repositories\InteractionRepository;
|
||||
use App\Services\DownloadService;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Collection;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
|
@ -152,7 +151,7 @@ class DownloadTest extends TestCase
|
|||
$user = User::factory()->create();
|
||||
|
||||
$this->get("download/playlist/{$playlist->id}?api_token=" . $user->createToken('Koel')->plainTextToken)
|
||||
->assertStatus(Response::HTTP_FORBIDDEN);
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testDownloadFavorites(): void
|
||||
|
|
|
@ -32,7 +32,7 @@ class LastfmTest extends TestCase
|
|||
/** @var User $user */
|
||||
$user = User::factory()->create();
|
||||
$this->postAs('api/lastfm/session-key', ['key' => 'foo'], $user)
|
||||
->assertStatus(204);
|
||||
->assertNoContent();
|
||||
|
||||
self::assertEquals('foo', $user->refresh()->lastfm_session_key);
|
||||
}
|
||||
|
|
|
@ -100,27 +100,20 @@ class PlaylistTest extends TestCase
|
|||
|
||||
public function testCreatingPlaylistWithNonExistentSongsFails(): void
|
||||
{
|
||||
$response = $this->postAs('api/playlist', [
|
||||
$this->postAs('api/playlist', [
|
||||
'name' => 'Foo Bar',
|
||||
'rules' => [],
|
||||
'songs' => ['foo'],
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable();
|
||||
])
|
||||
->assertUnprocessable();
|
||||
}
|
||||
|
||||
public function testUpdatePlaylistName(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create();
|
||||
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Playlist::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Foo',
|
||||
]);
|
||||
$playlist = Playlist::factory()->create(['name' => 'Foo']);
|
||||
|
||||
$this->putAs("api/playlist/$playlist->id", ['name' => 'Bar'], $user);
|
||||
$this->putAs("api/playlist/$playlist->id", ['name' => 'Bar'], $playlist->user);
|
||||
|
||||
self::assertSame('Bar', $playlist->refresh()->name);
|
||||
}
|
||||
|
@ -128,26 +121,19 @@ class PlaylistTest extends TestCase
|
|||
public function testNonOwnerCannotUpdatePlaylist(): void
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Playlist::factory()->create([
|
||||
'name' => 'Foo',
|
||||
]);
|
||||
$playlist = Playlist::factory()->create(['name' => 'Foo']);
|
||||
|
||||
$response = $this->putAs("api/playlist/$playlist->id", ['name' => 'Qux']);
|
||||
$response->assertStatus(403);
|
||||
$this->putAs("api/playlist/$playlist->id", ['name' => 'Qux'])->assertForbidden();
|
||||
}
|
||||
|
||||
public function testDeletePlaylist(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create();
|
||||
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Playlist::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
$playlist = Playlist::factory()->create();
|
||||
|
||||
$this->deleteAs("api/playlist/$playlist->id", [], $user);
|
||||
self::assertDatabaseMissing('playlists', ['id' => $playlist->id]);
|
||||
$this->deleteAs("api/playlist/$playlist->id", [], $playlist->user);
|
||||
|
||||
self::assertModelMissing($playlist);
|
||||
}
|
||||
|
||||
public function testNonOwnerCannotDeletePlaylist(): void
|
||||
|
@ -155,7 +141,8 @@ class PlaylistTest extends TestCase
|
|||
/** @var Playlist $playlist */
|
||||
$playlist = Playlist::factory()->create();
|
||||
|
||||
$this->deleteAs("api/playlist/$playlist->id")
|
||||
->assertStatus(403);
|
||||
$this->deleteAs("api/playlist/$playlist->id")->assertForbidden();
|
||||
|
||||
self::assertModelExists($playlist);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,56 +3,56 @@
|
|||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class ProfileTest extends TestCase
|
||||
{
|
||||
private User $user;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = User::factory()->create(['password' => Hash::make('secret')]);
|
||||
}
|
||||
|
||||
public function testUpdateProfileRequiresCurrentPassword(): void
|
||||
{
|
||||
$this->putAs('api/me', [
|
||||
'name' => 'Foo',
|
||||
'email' => 'bar@baz.com',
|
||||
], $this->user)
|
||||
->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
])
|
||||
->assertUnprocessable();
|
||||
}
|
||||
|
||||
public function testUpdateProfileWithoutNewPassword(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create(['password' => Hash::make('secret')]);
|
||||
|
||||
$this->putAs('api/me', [
|
||||
'name' => 'Foo',
|
||||
'email' => 'bar@baz.com',
|
||||
'current_password' => 'secret',
|
||||
], $this->user);
|
||||
], $user);
|
||||
|
||||
$this->user->refresh();
|
||||
$user->refresh();
|
||||
|
||||
self::assertSame('Foo', $this->user->name);
|
||||
self::assertSame('bar@baz.com', $this->user->email);
|
||||
self::assertTrue(Hash::check('secret', $this->user->password));
|
||||
self::assertSame('Foo', $user->name);
|
||||
self::assertSame('bar@baz.com', $user->email);
|
||||
self::assertTrue(Hash::check('secret', $user->password));
|
||||
}
|
||||
|
||||
public function testUpdateProfileWithNewPassword(): void
|
||||
{
|
||||
$this->putAs('api/me', [
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create(['password' => Hash::make('secret')]);
|
||||
|
||||
$token = $this->putAs('api/me', [
|
||||
'name' => 'Foo',
|
||||
'email' => 'bar@baz.com',
|
||||
'new_password' => 'new-secret',
|
||||
'current_password' => 'secret',
|
||||
], $this->user)
|
||||
->assertHeader('Authorization', $this->user->refresh()->api_token);
|
||||
], $user)
|
||||
->headers
|
||||
->get('Authorization');
|
||||
|
||||
self::assertSame('Foo', $this->user->name);
|
||||
self::assertSame('bar@baz.com', $this->user->email);
|
||||
self::assertTrue(Hash::check('new-secret', $this->user->password));
|
||||
$user->refresh();
|
||||
|
||||
self::assertNotNull($token);
|
||||
self::assertSame('Foo', $user->name);
|
||||
self::assertSame('bar@baz.com', $user->email);
|
||||
self::assertTrue(Hash::check('new-secret', $user->password));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@ namespace Tests\Feature;
|
|||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Services\MediaSyncService;
|
||||
use Mockery\LegacyMockInterface;
|
||||
use Mockery\MockInterface;
|
||||
|
||||
class SettingTest extends TestCase
|
||||
{
|
||||
private MediaSyncService|MockInterface|LegacyMockInterface $mediaSyncService;
|
||||
private MediaSyncService|MockInterface $mediaSyncService;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -21,9 +20,12 @@ class SettingTest extends TestCase
|
|||
|
||||
public function testSaveSettings(): void
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
$this->mediaSyncService->shouldReceive('sync')->once();
|
||||
|
||||
$this->putAs('/api/settings', ['media_path' => __DIR__], User::factory()->admin()->create())
|
||||
$this->putAs('/api/settings', ['media_path' => __DIR__], $admin)
|
||||
->assertSuccessful();
|
||||
|
||||
self::assertEquals(__DIR__, Setting::get('media_path'));
|
||||
|
@ -31,7 +33,7 @@ class SettingTest extends TestCase
|
|||
|
||||
public function testNonAdminCannotSaveSettings(): void
|
||||
{
|
||||
$this->putAs('/api/settings', ['media_path' => __DIR__], User::factory()->create())
|
||||
$this->putAs('/api/settings', ['media_path' => __DIR__])
|
||||
->assertForbidden();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ class SongTest extends TestCase
|
|||
|
||||
public function testSingleUpdateAllInfoNoCompilation(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create();
|
||||
$song = Song::first();
|
||||
|
||||
$this->putAs('/api/songs', [
|
||||
|
@ -31,8 +33,8 @@ class SongTest extends TestCase
|
|||
'track' => 1,
|
||||
'disc' => 2,
|
||||
],
|
||||
], User::factory()->admin()->create())
|
||||
->assertStatus(200);
|
||||
], $user)
|
||||
->assertOk();
|
||||
|
||||
/** @var Artist $artist */
|
||||
$artist = Artist::where('name', 'John Cena')->first();
|
||||
|
@ -53,6 +55,8 @@ class SongTest extends TestCase
|
|||
|
||||
public function testSingleUpdateSomeInfoNoCompilation(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create();
|
||||
$song = Song::first();
|
||||
$originalArtistId = $song->artist->id;
|
||||
|
||||
|
@ -65,8 +69,8 @@ class SongTest extends TestCase
|
|||
'lyrics' => 'Lorem ipsum dolor sic amet.',
|
||||
'track' => 1,
|
||||
],
|
||||
], User::factory()->admin()->create())
|
||||
->assertStatus(200);
|
||||
], $user)
|
||||
->assertOk();
|
||||
|
||||
// We don't expect the song's artist to change
|
||||
self::assertEquals($originalArtistId, Song::find($song->id)->artist->id);
|
||||
|
@ -77,6 +81,8 @@ class SongTest extends TestCase
|
|||
|
||||
public function testMultipleUpdateNoCompilation(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create();
|
||||
$songIds = Song::latest()->take(3)->pluck('id')->toArray();
|
||||
|
||||
$this->putAs('/api/songs', [
|
||||
|
@ -88,8 +94,8 @@ class SongTest extends TestCase
|
|||
'lyrics' => 'bar',
|
||||
'track' => 9999,
|
||||
],
|
||||
], User::factory()->admin()->create())
|
||||
->assertStatus(200);
|
||||
], $user)
|
||||
->assertOk();
|
||||
|
||||
$songs = Song::whereIn('id', $songIds)->get();
|
||||
|
||||
|
@ -105,6 +111,9 @@ class SongTest extends TestCase
|
|||
|
||||
public function testMultipleUpdateCreatingNewAlbumsAndArtists(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create();
|
||||
|
||||
/** @var array<array-key, Song>|Collection $originalSongs */
|
||||
$originalSongs = Song::latest()->take(3)->get();
|
||||
$songIds = $originalSongs->pluck('id')->toArray();
|
||||
|
@ -118,8 +127,8 @@ class SongTest extends TestCase
|
|||
'lyrics' => 'Lorem ipsum dolor sic amet.',
|
||||
'track' => 1,
|
||||
],
|
||||
], User::factory()->admin()->create())
|
||||
->assertStatus(200);
|
||||
], $user)
|
||||
->assertOk();
|
||||
|
||||
/** @var array<Song>|Collection $songs */
|
||||
$songs = Song::latest()->take(3)->get();
|
||||
|
@ -141,6 +150,8 @@ class SongTest extends TestCase
|
|||
|
||||
public function testSingleUpdateAllInfoWithCompilation(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create();
|
||||
$song = Song::first();
|
||||
|
||||
$this->putAs('/api/songs', [
|
||||
|
@ -154,8 +165,8 @@ class SongTest extends TestCase
|
|||
'track' => 1,
|
||||
'disc' => 2,
|
||||
],
|
||||
], User::factory()->admin()->create())
|
||||
->assertStatus(200);
|
||||
], $user)
|
||||
->assertOk();
|
||||
|
||||
/** @var Album $album */
|
||||
$album = Album::where('name', 'One by One')->first();
|
||||
|
@ -182,7 +193,9 @@ class SongTest extends TestCase
|
|||
{
|
||||
self::assertNotEquals(0, Song::count());
|
||||
$ids = Song::select('id')->get()->pluck('id')->all();
|
||||
|
||||
Song::deleteByChunk($ids, 'id', 1);
|
||||
|
||||
self::assertEquals(0, Song::count());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,11 @@ use App\Models\Song;
|
|||
use App\Models\User;
|
||||
use App\Services\UploadService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Mockery\LegacyMockInterface;
|
||||
use Mockery\MockInterface;
|
||||
|
||||
class UploadTest extends TestCase
|
||||
{
|
||||
private UploadService|MockInterface|LegacyMockInterface $uploadService;
|
||||
private UploadService|MockInterface $uploadService;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -32,7 +31,7 @@ class UploadTest extends TestCase
|
|||
->shouldReceive('handleUploadedFile')
|
||||
->never();
|
||||
|
||||
$this->postAs('/api/upload', ['file' => $file], User::factory()->create())->assertStatus(403);
|
||||
$this->postAs('/api/upload', ['file' => $file])->assertForbidden();
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
|
@ -49,32 +48,35 @@ class UploadTest extends TestCase
|
|||
{
|
||||
$file = UploadedFile::fake()->create('foo.mp3', 2048);
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
$this->uploadService
|
||||
->shouldReceive('handleUploadedFile')
|
||||
->once()
|
||||
->with($file)
|
||||
->andThrow($exceptionClass);
|
||||
|
||||
$this->postAs('/api/upload', ['file' => $file], User::factory()->admin()->create())
|
||||
->assertStatus($statusCode);
|
||||
$this->postAs('/api/upload', ['file' => $file], $admin)->assertStatus($statusCode);
|
||||
}
|
||||
|
||||
public function testPost(): void
|
||||
{
|
||||
Setting::set('media_path', '/media/koel');
|
||||
$file = UploadedFile::fake()->create('foo.mp3', 2048);
|
||||
|
||||
/** @var Song $song */
|
||||
$song = Song::factory()->create();
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
$this->uploadService
|
||||
->shouldReceive('handleUploadedFile')
|
||||
->once()
|
||||
->with($file)
|
||||
->andReturn($song);
|
||||
|
||||
$this->postAs('/api/upload', ['file' => $file], User::factory()->admin()->create())
|
||||
->assertJsonStructure([
|
||||
'song',
|
||||
'album',
|
||||
]);
|
||||
$this->postAs('/api/upload', ['file' => $file], $admin)->assertJsonStructure(['song', 'album']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,6 @@ use Illuminate\Support\Facades\Hash;
|
|||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testNonAdminCannotCreateUser(): void
|
||||
{
|
||||
$this->postAs('api/user', [
|
||||
|
@ -24,15 +19,17 @@ class UserTest extends TestCase
|
|||
|
||||
public function testAdminCreatesUser(): void
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
$this->postAs('api/user', [
|
||||
'name' => 'Foo',
|
||||
'email' => 'bar@baz.com',
|
||||
'password' => 'secret',
|
||||
'is_admin' => true,
|
||||
], User::factory()->admin()->create())
|
||||
], $admin)
|
||||
->assertSuccessful();
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::firstWhere('email', 'bar@baz.com');
|
||||
|
||||
self::assertTrue(Hash::check('secret', $user->password));
|
||||
|
@ -43,6 +40,9 @@ class UserTest extends TestCase
|
|||
|
||||
public function testAdminUpdatesUser(): void
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::factory()->admin()->create(['password' => 'secret']);
|
||||
|
||||
|
@ -51,7 +51,8 @@ class UserTest extends TestCase
|
|||
'email' => 'bar@baz.com',
|
||||
'password' => 'new-secret',
|
||||
'is_admin' => false,
|
||||
], User::factory()->admin()->create());
|
||||
], $admin)
|
||||
->assertSuccessful();
|
||||
|
||||
$user->refresh();
|
||||
|
||||
|
@ -65,10 +66,12 @@ class UserTest extends TestCase
|
|||
{
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create();
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
$this->deleteAs("api/user/$user->id", [], $admin);
|
||||
self::assertDatabaseMissing('users', ['id' => $user->id]);
|
||||
self::assertModelMissing($user);
|
||||
}
|
||||
|
||||
public function testSeppukuNotAllowed(): void
|
||||
|
@ -77,9 +80,7 @@ class UserTest extends TestCase
|
|||
$admin = User::factory()->admin()->create();
|
||||
|
||||
// A user can't delete himself
|
||||
$this->deleteAs("api/user/$admin->id", [], $admin)
|
||||
->assertStatus(403);
|
||||
|
||||
self::assertDatabaseHas('users', ['id' => $admin->id]);
|
||||
$this->deleteAs("api/user/$admin->id", [], $admin)->assertForbidden();
|
||||
self::assertModelExists($admin);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Tests\Feature\V6;
|
|||
use App\Models\Playlist;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class PlaylistSongTest extends TestCase
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ class PlaylistSongTest extends TestCase
|
|||
$playlist->songs()->attach(Song::factory(5)->create());
|
||||
|
||||
$this->getAs('api/playlists/' . $playlist->id . '/songs')
|
||||
->assertStatus(Response::HTTP_FORBIDDEN);
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testAddSongsToPlaylist(): void
|
||||
|
@ -61,6 +61,7 @@ class PlaylistSongTest extends TestCase
|
|||
/** @var Playlist $playlist */
|
||||
$playlist = Playlist::factory()->create();
|
||||
|
||||
/** @var Collection|array<array-key, Song> $songs */
|
||||
$songs = Song::factory(2)->create();
|
||||
|
||||
$this->postAs('api/playlists/' . $playlist->id . '/songs', [
|
||||
|
@ -77,7 +78,10 @@ class PlaylistSongTest extends TestCase
|
|||
$playlist = Playlist::factory()->create();
|
||||
|
||||
$toRemainSongs = Song::factory(5)->create();
|
||||
|
||||
/** @var Collection|array<array-key, Song> $toBeRemovedSongs */
|
||||
$toBeRemovedSongs = Song::factory(2)->create();
|
||||
|
||||
$playlist->songs()->attach($toRemainSongs->merge($toBeRemovedSongs));
|
||||
|
||||
self::assertCount(7, $playlist->songs);
|
||||
|
@ -103,10 +107,10 @@ class PlaylistSongTest extends TestCase
|
|||
$song = Song::factory()->create();
|
||||
|
||||
$this->postAs('api/playlists/' . $playlist->id . '/songs', ['songs' => [$song->id]])
|
||||
->assertStatus(Response::HTTP_FORBIDDEN);
|
||||
->assertForbidden();
|
||||
|
||||
$this->deleteAs('api/playlists/' . $playlist->id . '/songs', ['songs' => [$song->id]])
|
||||
->assertStatus(Response::HTTP_FORBIDDEN);
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testSmartPlaylistContentCannotBeModified(): void
|
||||
|
@ -128,12 +132,14 @@ class PlaylistSongTest extends TestCase
|
|||
],
|
||||
]);
|
||||
|
||||
$songs = Song::factory(2)->create()->map(static fn (Song $song) => $song->id)->all();
|
||||
/** @var Collection|array<array-key, Song> $songs */
|
||||
$songs = Song::factory(2)->create();
|
||||
$songIds = $songs->map(static fn (Song $song) => $song->id)->all();
|
||||
|
||||
$this->postAs('api/playlists/' . $playlist->id . '/songs', ['songs' => $songs], $playlist->user)
|
||||
->assertStatus(Response::HTTP_FORBIDDEN);
|
||||
$this->postAs('api/playlists/' . $playlist->id . '/songs', ['songs' => $songIds], $playlist->user)
|
||||
->assertForbidden();
|
||||
|
||||
$this->deleteAs('api/playlists/' . $playlist->id . '/songs', ['songs' => $songs], $playlist->user)
|
||||
->assertStatus(Response::HTTP_FORBIDDEN);
|
||||
$this->deleteAs('api/playlists/' . $playlist->id . '/songs', ['songs' => $songIds], $playlist->user)
|
||||
->assertForbidden();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ class FileSynchronizerTest extends TestCase
|
|||
];
|
||||
|
||||
self::assertArraySubset($expectedData, $info->toArray());
|
||||
self::assertEqualsWithDelta(10, $info->length, 0.001);
|
||||
self::assertEqualsWithDelta(10, $info->length, 0.1);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
|
|
|
@ -2,19 +2,9 @@
|
|||
|
||||
namespace Tests\Integration\Services;
|
||||
|
||||
use App\Services\SmartPlaylistService;
|
||||
use Carbon\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SmartPlaylistServiceTest extends TestCase
|
||||
{
|
||||
private SmartPlaylistService $service;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->service = app(SmartPlaylistService::class);
|
||||
Carbon::setTestNow(new Carbon('2018-07-15'));
|
||||
}
|
||||
// @todo write tests
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace Tests\Unit\Services;
|
|||
|
||||
use App\Models\Song;
|
||||
use App\Repositories\SongRepository;
|
||||
use App\Services\Helper;
|
||||
use App\Services\MediaMetadataService;
|
||||
use App\Services\S3Service;
|
||||
use Aws\CommandInterface;
|
||||
|
@ -12,15 +11,14 @@ use Aws\S3\S3ClientInterface;
|
|||
use GuzzleHttp\Psr7\Request;
|
||||
use Illuminate\Cache\Repository as Cache;
|
||||
use Mockery;
|
||||
use Mockery\LegacyMockInterface;
|
||||
use Mockery\MockInterface;
|
||||
use Tests\TestCase;
|
||||
|
||||
class S3ServiceTest extends TestCase
|
||||
{
|
||||
private $s3Client;
|
||||
private $cache;
|
||||
private $metadataService;
|
||||
private $songRepository;
|
||||
private $helper;
|
||||
private LegacyMockInterface|MockInterface|S3ClientInterface $s3Client;
|
||||
private LegacyMockInterface|Cache|MockInterface $cache;
|
||||
private S3Service $s3Service;
|
||||
|
||||
public function setUp(): void
|
||||
|
@ -29,17 +27,11 @@ class S3ServiceTest extends TestCase
|
|||
|
||||
$this->s3Client = Mockery::mock(S3ClientInterface::class);
|
||||
$this->cache = Mockery::mock(Cache::class);
|
||||
$this->metadataService = Mockery::mock(MediaMetadataService::class);
|
||||
$this->songRepository = Mockery::mock(SongRepository::class);
|
||||
$this->helper = Mockery::mock(Helper::class);
|
||||
|
||||
$this->s3Service = new S3Service(
|
||||
$this->s3Client,
|
||||
$this->cache,
|
||||
$this->metadataService,
|
||||
$this->songRepository,
|
||||
$this->helper
|
||||
);
|
||||
$metadataService = Mockery::mock(MediaMetadataService::class);
|
||||
$songRepository = Mockery::mock(SongRepository::class);
|
||||
|
||||
$this->s3Service = new S3Service($this->s3Client, $this->cache, $metadataService, $songRepository);
|
||||
}
|
||||
|
||||
public function testGetSongPublicUrl(): void
|
||||
|
@ -48,6 +40,7 @@ class S3ServiceTest extends TestCase
|
|||
$song = Song::factory()->create(['path' => 's3://foo/bar']);
|
||||
|
||||
$cmd = Mockery::mock(CommandInterface::class);
|
||||
|
||||
$this->s3Client->shouldReceive('getCommand')
|
||||
->with('GetObject', [
|
||||
'Bucket' => 'foo',
|
||||
|
|
|
@ -14,7 +14,7 @@ use Tests\TestCase;
|
|||
class SpotifyServiceTest extends TestCase
|
||||
{
|
||||
private SpotifyService $service;
|
||||
private SpotifyClient|LegacyMockInterface|MockInterface $client;
|
||||
private SpotifyClient|MockInterface|LegacyMockInterface $client;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ class SpotifyServiceTest extends TestCase
|
|||
|
||||
$this->client->shouldNotReceive('search');
|
||||
|
||||
self::assertNull($this->service->tryGetArtistImage(Artist::factory()->create()));
|
||||
self::assertNull($this->service->tryGetArtistImage(Mockery::mock(Artist::class)));
|
||||
}
|
||||
|
||||
public function testTryGetAlbumImage(): void
|
||||
|
@ -73,7 +73,7 @@ class SpotifyServiceTest extends TestCase
|
|||
|
||||
$this->client->shouldNotReceive('search');
|
||||
|
||||
self::assertNull($this->service->tryGetAlbumCover(Album::factory()->create()));
|
||||
self::assertNull($this->service->tryGetAlbumCover(Mockery::mock(Album::class)));
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
|
|
Loading…
Reference in a new issue