mirror of
https://github.com/koel/koel
synced 2024-11-14 00:17:13 +00:00
refactor: avoid leadking database keys (#1874)
This commit is contained in:
parent
bcfbf31b35
commit
aa7ddd9d94
76 changed files with 286 additions and 293 deletions
|
@ -34,7 +34,7 @@ class ChangePasswordCommand extends Command
|
||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->comment("Changing the user's password (ID: $user->id, email: $user->email)");
|
$this->comment("Changing the user's password (ID: {$user->id}, email: $user->email)");
|
||||||
|
|
||||||
$user->password = $this->hash->make($this->askForPassword());
|
$user->password = $this->hash->make($this->askForPassword());
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
|
@ -173,7 +173,7 @@ class ScanCommand extends Command
|
||||||
exit(self::INVALID);
|
exit(self::INVALID);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->components->info("Setting owner to $user->name (ID $user->id).");
|
$this->components->info("Setting owner to $user->name (ID {$user->id}).");
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ class ScanCommand extends Command
|
||||||
$user = $this->userRepository->getDefaultAdminUser();
|
$user = $this->userRepository->getDefaultAdminUser();
|
||||||
|
|
||||||
$this->components->warn(
|
$this->components->warn(
|
||||||
"No song owner specified. Setting the first admin ($user->name, ID $user->id) as owner."
|
"No song owner specified. Setting the first admin ($user->name, ID {$user->id}) as owner."
|
||||||
);
|
);
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
|
|
|
@ -10,6 +10,6 @@ final class UserAlreadySubscribedToPodcast extends Exception
|
||||||
{
|
{
|
||||||
public static function make(User $user, Podcast $podcast): self
|
public static function make(User $user, Podcast $podcast): self
|
||||||
{
|
{
|
||||||
return new self("User $user->id has already subscribed to podcast $podcast->id");
|
return new self("User {$user->id} has already subscribed to podcast {$podcast->id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\API;
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Facades\License;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\API\ChangeSongsVisibilityRequest;
|
use App\Http\Requests\API\ChangeSongsVisibilityRequest;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
|
@ -14,6 +15,8 @@ class PrivatizeSongsController extends Controller
|
||||||
/** @param User $user */
|
/** @param User $user */
|
||||||
public function __invoke(ChangeSongsVisibilityRequest $request, SongService $songService, Authenticatable $user)
|
public function __invoke(ChangeSongsVisibilityRequest $request, SongService $songService, Authenticatable $user)
|
||||||
{
|
{
|
||||||
|
License::requirePlus();
|
||||||
|
|
||||||
$songs = Song::query()->findMany($request->songs);
|
$songs = Song::query()->findMany($request->songs);
|
||||||
$songs->each(fn ($song) => $this->authorize('own', $song));
|
$songs->each(fn ($song) => $this->authorize('own', $song));
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\API;
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Facades\License;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\API\ChangeSongsVisibilityRequest;
|
use App\Http\Requests\API\ChangeSongsVisibilityRequest;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
|
@ -14,6 +15,8 @@ class PublicizeSongsController extends Controller
|
||||||
/** @param User $user */
|
/** @param User $user */
|
||||||
public function __invoke(ChangeSongsVisibilityRequest $request, SongService $songService, Authenticatable $user)
|
public function __invoke(ChangeSongsVisibilityRequest $request, SongService $songService, Authenticatable $user)
|
||||||
{
|
{
|
||||||
|
License::requirePlus();
|
||||||
|
|
||||||
$songs = Song::query()->findMany($request->songs);
|
$songs = Song::query()->findMany($request->songs);
|
||||||
$songs->each(fn ($song) => $this->authorize('own', $song));
|
$songs->each(fn ($song) => $this->authorize('own', $song));
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class UploadAlbumCoverController extends Controller
|
||||||
$this->authorize('update', $album);
|
$this->authorize('update', $album);
|
||||||
$metadataService->writeAlbumCover($album, $request->getFileContent());
|
$metadataService->writeAlbumCover($album, $request->getFileContent());
|
||||||
|
|
||||||
Cache::delete("album.info.$album->id");
|
Cache::delete("album.info.{$album->id}");
|
||||||
|
|
||||||
return response()->json(['cover_url' => $album->cover]);
|
return response()->json(['cover_url' => $album->cover]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class UploadArtistImageController extends Controller
|
||||||
$this->authorize('update', $artist);
|
$this->authorize('update', $artist);
|
||||||
$metadataService->writeArtistImage($artist, $request->getFileContent());
|
$metadataService->writeArtistImage($artist, $request->getFileContent());
|
||||||
|
|
||||||
Cache::delete("artist.info.$artist->id");
|
Cache::delete("artist.info.{$artist->id}");
|
||||||
|
|
||||||
return response()->json(['image_url' => $artist->image]);
|
return response()->json(['image_url' => $artist->image]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class ProfileUpdateRequest extends Request
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'required',
|
'name' => 'required',
|
||||||
'email' => 'required|email|unique:users,email,' . auth()->user()->id,
|
'email' => 'required|email|unique:users,email,' . auth()->user()->getAuthIdentifier(),
|
||||||
'current_password' => 'sometimes|required_with:new_password',
|
'current_password' => 'sometimes|required_with:new_password',
|
||||||
'new_password' => ['sometimes', Password::defaults()],
|
'new_password' => ['sometimes', Password::defaults()],
|
||||||
];
|
];
|
||||||
|
|
|
@ -19,7 +19,6 @@ use Laravel\Scout\Searchable;
|
||||||
* @property string $cover The album cover's URL
|
* @property string $cover The album cover's URL
|
||||||
* @property string|null $cover_path The absolute path to the cover file
|
* @property string|null $cover_path The absolute path to the cover file
|
||||||
* @property bool $has_cover If the album has a non-default cover image
|
* @property bool $has_cover If the album has a non-default cover image
|
||||||
* @property int $id
|
|
||||||
* @property string $name Name of the album
|
* @property string $name Name of the album
|
||||||
* @property Artist $artist The album's artist
|
* @property Artist $artist The album's artist
|
||||||
* @property int $artist_id
|
* @property int $artist_id
|
||||||
|
|
|
@ -8,6 +8,7 @@ use App\Models\Song as Playable;
|
||||||
use App\Values\SmartPlaylistRuleGroupCollection;
|
use App\Values\SmartPlaylistRuleGroupCollection;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
@ -24,16 +25,16 @@ use Laravel\Scout\Searchable;
|
||||||
* @property bool $is_smart
|
* @property bool $is_smart
|
||||||
* @property int $user_id
|
* @property int $user_id
|
||||||
* @property User $user
|
* @property User $user
|
||||||
* @property Collection<array-key, Playable> $playables
|
|
||||||
* @property ?SmartPlaylistRuleGroupCollection $rule_groups
|
* @property ?SmartPlaylistRuleGroupCollection $rule_groups
|
||||||
* @property ?SmartPlaylistRuleGroupCollection $rules
|
* @property ?SmartPlaylistRuleGroupCollection $rules
|
||||||
* @property Carbon $created_at
|
* @property Carbon $created_at
|
||||||
|
* @property EloquentCollection<array-key, Playable> $playables
|
||||||
|
* @property EloquentCollection<array-key, User> $collaborators
|
||||||
* @property bool $own_songs_only
|
* @property bool $own_songs_only
|
||||||
* @property Collection<array-key, User> $collaborators
|
|
||||||
* @property-read bool $is_collaborative
|
|
||||||
* @property-read ?string $cover The playlist cover's URL
|
* @property-read ?string $cover The playlist cover's URL
|
||||||
* @property-read ?string $cover_path
|
* @property-read ?string $cover_path
|
||||||
* @property-read Collection<array-key, PlaylistFolder> $folders
|
* @property-read EloquentCollection<array-key, PlaylistFolder> $folders
|
||||||
|
* @property-read bool $is_collaborative
|
||||||
*/
|
*/
|
||||||
class Playlist extends Model
|
class Playlist extends Model
|
||||||
{
|
{
|
||||||
|
@ -107,7 +108,7 @@ class Playlist extends Model
|
||||||
|
|
||||||
public function ownedBy(User $user): bool
|
public function ownedBy(User $user): bool
|
||||||
{
|
{
|
||||||
return $this->user_id === $user->id;
|
return $this->user->is($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function inFolder(PlaylistFolder $folder): bool
|
public function inFolder(PlaylistFolder $folder): bool
|
||||||
|
|
|
@ -11,7 +11,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property string $id
|
|
||||||
* @property string $name
|
* @property string $name
|
||||||
* @property User $user
|
* @property User $user
|
||||||
* @property Collection<array-key, Playlist> $playlists
|
* @property Collection<array-key, Playlist> $playlists
|
||||||
|
@ -38,6 +37,6 @@ class PlaylistFolder extends Model
|
||||||
|
|
||||||
public function ownedBy(User $user): bool
|
public function ownedBy(User $user): bool
|
||||||
{
|
{
|
||||||
return $this->user_id === $user->id;
|
return $this->user->is($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,7 @@ class Song extends Model
|
||||||
|
|
||||||
public function ownedBy(User $user): bool
|
public function ownedBy(User $user): bool
|
||||||
{
|
{
|
||||||
|
// Do not use $song->owner->is($user) here, as it may trigger an extra query.
|
||||||
return $this->owner_id === $user->id;
|
return $this->owner_id === $user->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ class User extends Authenticatable
|
||||||
|
|
||||||
public function subscribedToPodcast(Podcast $podcast): bool
|
public function subscribedToPodcast(Podcast $podcast): bool
|
||||||
{
|
{
|
||||||
return $this->podcasts()->where('podcast_id', $podcast->id)->exists();
|
return $this->podcasts()->whereKey($podcast)->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function subscribeToPodcast(Podcast $podcast): void
|
public function subscribeToPodcast(Podcast $podcast): void
|
||||||
|
|
|
@ -10,6 +10,7 @@ class SongPolicy
|
||||||
{
|
{
|
||||||
public function own(User $user, Song $song): bool
|
public function own(User $user, Song $song): bool
|
||||||
{
|
{
|
||||||
|
// Do not use $song->owner->is($user) here, as it may trigger an extra query.
|
||||||
return $song->owner_id === $user->id;
|
return $song->owner_id === $user->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class MacroProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
Collection::macro('orderByArray', function (array $orderBy, string $key = 'id'): Collection {
|
Collection::macro('orderByArray', function (array $orderBy, string $key = 'id') {
|
||||||
/** @var Collection $this */
|
/** @var Collection $this */
|
||||||
return $this->sortBy(static fn ($item) => array_search($item->$key, $orderBy, true))->values();
|
return $this->sortBy(static fn ($item) => array_search($item->$key, $orderBy, true))->values();
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,8 +8,8 @@ use App\Models\Album;
|
||||||
use App\Models\Artist;
|
use App\Models\Artist;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Contracts\Pagination\Paginator;
|
use Illuminate\Contracts\Pagination\Paginator;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Album>
|
* @extends Repository<Album>
|
||||||
|
|
|
@ -9,7 +9,6 @@ use App\Models\User;
|
||||||
use Illuminate\Contracts\Pagination\Paginator;
|
use Illuminate\Contracts\Pagination\Paginator;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection as BaseCollection;
|
|
||||||
|
|
||||||
/** @extends Repository<Artist> */
|
/** @extends Repository<Artist> */
|
||||||
class ArtistRepository extends Repository
|
class ArtistRepository extends Repository
|
||||||
|
@ -44,7 +43,7 @@ class ArtistRepository extends Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Collection|array<array-key, Artist> */
|
/** @return Collection|array<array-key, Artist> */
|
||||||
public function getMany(array $ids, bool $preserveOrder = false, ?User $user = null): Collection|BaseCollection
|
public function getMany(array $ids, bool $preserveOrder = false, ?User $user = null): Collection
|
||||||
{
|
{
|
||||||
$artists = Artist::query()
|
$artists = Artist::query()
|
||||||
->isStandard()
|
->isStandard()
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
|
|
||||||
namespace App\Repositories\Contracts;
|
namespace App\Repositories\Contracts;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/** @template T of Model */
|
/** @template T of Model */
|
||||||
interface RepositoryInterface
|
interface RepositoryInterface
|
||||||
|
@ -25,7 +24,7 @@ interface RepositoryInterface
|
||||||
public function getMany(array $ids, bool $preserveOrder = false): Collection;
|
public function getMany(array $ids, bool $preserveOrder = false): Collection;
|
||||||
|
|
||||||
/** @return Collection<int, T> */
|
/** @return Collection<int, T> */
|
||||||
public function getAll(): EloquentCollection;
|
public function getAll(): Collection;
|
||||||
|
|
||||||
/** @return T|null */
|
/** @return T|null */
|
||||||
public function findFirstWhere(...$params): ?Model;
|
public function findFirstWhere(...$params): ?Model;
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace App\Repositories;
|
||||||
|
|
||||||
use App\Models\Podcast;
|
use App\Models\Podcast;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
/** @extends Repository<Podcast> */
|
/** @extends Repository<Podcast> */
|
||||||
class PodcastRepository extends Repository
|
class PodcastRepository extends Repository
|
||||||
|
|
|
@ -4,9 +4,8 @@ namespace App\Repositories;
|
||||||
|
|
||||||
use App\Repositories\Contracts\RepositoryInterface;
|
use App\Repositories\Contracts\RepositoryInterface;
|
||||||
use Illuminate\Contracts\Auth\Guard;
|
use Illuminate\Contracts\Auth\Guard;
|
||||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template T of Model
|
* @template T of Model
|
||||||
|
@ -68,9 +67,9 @@ abstract class Repository implements RepositoryInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */ // @phpcs:ignore
|
/** @inheritDoc */ // @phpcs:ignore
|
||||||
public function getAll(): EloquentCollection
|
public function getAll(): Collection
|
||||||
{
|
{
|
||||||
return $this->modelClass::all();
|
return $this->modelClass::all(); // @phpstan-ignore-line
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
|
@ -13,7 +13,7 @@ use App\Models\Song;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Values\Genre;
|
use App\Values\Genre;
|
||||||
use Illuminate\Contracts\Pagination\Paginator;
|
use Illuminate\Contracts\Pagination\Paginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
/** @extends Repository<Song> */
|
/** @extends Repository<Song> */
|
||||||
class SongRepository extends Repository
|
class SongRepository extends Repository
|
||||||
|
@ -78,7 +78,10 @@ class SongRepository extends Repository
|
||||||
return Song::query(type: PlayableType::SONG, user: $scopedUser)
|
return Song::query(type: PlayableType::SONG, user: $scopedUser)
|
||||||
->accessible()
|
->accessible()
|
||||||
->withMeta()
|
->withMeta()
|
||||||
->when($ownSongsOnly, static fn (SongBuilder $query) => $query->where('songs.owner_id', $scopedUser->id))
|
->when(
|
||||||
|
$ownSongsOnly,
|
||||||
|
static fn (SongBuilder $query) => $query->where('songs.owner_id', $scopedUser->id)
|
||||||
|
)
|
||||||
->sort($sortColumns, $sortDirection)
|
->sort($sortColumns, $sortDirection)
|
||||||
->simplePaginate($perPage);
|
->simplePaginate($perPage);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +132,7 @@ class SongRepository extends Repository
|
||||||
return Song::query(user: $scopedUser ?? $this->auth->user())
|
return Song::query(user: $scopedUser ?? $this->auth->user())
|
||||||
->accessible()
|
->accessible()
|
||||||
->withMeta()
|
->withMeta()
|
||||||
->where('album_id', $album->id)
|
->whereBelongsTo($album)
|
||||||
->orderBy('songs.disc')
|
->orderBy('songs.disc')
|
||||||
->orderBy('songs.track')
|
->orderBy('songs.track')
|
||||||
->orderBy('songs.title')
|
->orderBy('songs.title')
|
||||||
|
@ -195,7 +198,7 @@ class SongRepository extends Repository
|
||||||
->whereIn('songs.id', $ids)
|
->whereIn('songs.id', $ids)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
return $preserveOrder ? $songs->orderByArray($ids) : $songs;
|
return $preserveOrder ? $songs->orderByArray($ids) : $songs; // @phpstan-ignore-line
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,7 @@ final class AllPlaylistsAreAccessibleBy implements ValidationRule
|
||||||
$accessiblePlaylists = $accessiblePlaylists->merge($this->user->collaboratedPlaylists);
|
$accessiblePlaylists = $accessiblePlaylists->merge($this->user->collaboratedPlaylists);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_diff(Arr::wrap($value), $accessiblePlaylists->pluck('id')->toArray())) {
|
if (array_diff(Arr::wrap($value), $accessiblePlaylists->modelKeys())) {
|
||||||
$fail(
|
$fail(
|
||||||
License::isPlus()
|
License::isPlus()
|
||||||
? 'Not all playlists are accessible by the user'
|
? 'Not all playlists are accessible by the user'
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Services\SongStorages\DropboxStorage;
|
||||||
use App\Services\SongStorages\S3CompatibleStorage;
|
use App\Services\SongStorages\S3CompatibleStorage;
|
||||||
use App\Services\SongStorages\SftpStorage;
|
use App\Services\SongStorages\SftpStorage;
|
||||||
use App\Values\Podcast\EpisodePlayable;
|
use App\Values\Podcast\EpisodePlayable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
class DownloadService
|
class DownloadService
|
||||||
|
@ -17,7 +17,7 @@ class DownloadService
|
||||||
public function getDownloadablePath(Collection $songs): ?string
|
public function getDownloadablePath(Collection $songs): ?string
|
||||||
{
|
{
|
||||||
if ($songs->count() === 1) {
|
if ($songs->count() === 1) {
|
||||||
return $this->getLocalPath($songs->first());
|
return $this->getLocalPath($songs->first()); // @phpstan-ignore-line
|
||||||
}
|
}
|
||||||
|
|
||||||
return (new SongZipArchive())
|
return (new SongZipArchive())
|
||||||
|
|
|
@ -8,7 +8,7 @@ use App\Events\SongLikeToggled;
|
||||||
use App\Models\Interaction;
|
use App\Models\Interaction;
|
||||||
use App\Models\Song as Playable;
|
use App\Models\Song as Playable;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class InteractionService
|
class InteractionService
|
||||||
{
|
{
|
||||||
|
@ -57,14 +57,20 @@ class InteractionService
|
||||||
public function likeMany(Collection $playables, User $user): Collection
|
public function likeMany(Collection $playables, User $user): Collection
|
||||||
{
|
{
|
||||||
$interactions = $playables->map(static function (Playable $playable) use ($user): Interaction {
|
$interactions = $playables->map(static function (Playable $playable) use ($user): Interaction {
|
||||||
return tap(Interaction::query()->firstOrCreate([
|
$interaction = Interaction::query()->whereBelongsTo($playable)->whereBelongsTo($user)->first();
|
||||||
'song_id' => $playable->id,
|
|
||||||
'user_id' => $user->id,
|
if ($interaction) {
|
||||||
]), static function (Interaction $interaction): void {
|
$interaction->update(['liked' => true]);
|
||||||
$interaction->play_count ??= 0;
|
} else {
|
||||||
$interaction->liked = true;
|
$interaction = Interaction::query()->create([
|
||||||
$interaction->save();
|
'song_id' => $playable->id,
|
||||||
});
|
'user_id' => $user->id,
|
||||||
|
'play_count' => 0,
|
||||||
|
'liked' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $interaction;
|
||||||
});
|
});
|
||||||
|
|
||||||
event(new MultipleSongsLiked($playables, $user));
|
event(new MultipleSongsLiked($playables, $user));
|
||||||
|
@ -80,8 +86,8 @@ class InteractionService
|
||||||
public function unlikeMany(Collection $playables, User $user): void
|
public function unlikeMany(Collection $playables, User $user): void
|
||||||
{
|
{
|
||||||
Interaction::query()
|
Interaction::query()
|
||||||
->whereIn('song_id', $playables->pluck('id')->all())
|
->whereBelongsTo($playables)
|
||||||
->where('user_id', $user->id)
|
->whereBelongsTo($user)
|
||||||
->update(['liked' => false]);
|
->update(['liked' => false]);
|
||||||
|
|
||||||
event(new MultipleSongsUnliked($playables, $user));
|
event(new MultipleSongsUnliked($playables, $user));
|
||||||
|
|
|
@ -50,7 +50,7 @@ class LastfmService implements MusicEncyclopedia
|
||||||
|
|
||||||
return rescue_if(static::enabled(), function () use ($artist): ?ArtistInformation {
|
return rescue_if(static::enabled(), function () use ($artist): ?ArtistInformation {
|
||||||
return Cache::remember(
|
return Cache::remember(
|
||||||
"lastfm.artist.$artist->id",
|
"lastfm.artist.{$artist->id}",
|
||||||
now()->addWeek(),
|
now()->addWeek(),
|
||||||
fn () => $this->connector->send(new GetArtistInfoRequest($artist))->dto()
|
fn () => $this->connector->send(new GetArtistInfoRequest($artist))->dto()
|
||||||
);
|
);
|
||||||
|
@ -65,7 +65,7 @@ class LastfmService implements MusicEncyclopedia
|
||||||
|
|
||||||
return rescue_if(static::enabled(), function () use ($album): ?AlbumInformation {
|
return rescue_if(static::enabled(), function () use ($album): ?AlbumInformation {
|
||||||
return Cache::remember(
|
return Cache::remember(
|
||||||
"lastfm.album.$album->id",
|
"lastfm.album.{$album->id}",
|
||||||
now()->addWeek(),
|
now()->addWeek(),
|
||||||
fn () => $this->connector->send(new GetAlbumInfoRequest($album))->dto()
|
fn () => $this->connector->send(new GetAlbumInfoRequest($album))->dto()
|
||||||
);
|
);
|
||||||
|
|
|
@ -23,16 +23,20 @@ class MediaInformationService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cache::remember("album.info.$album->id", now()->addWeek(), function () use ($album): AlbumInformation {
|
return Cache::remember(
|
||||||
$info = $this->encyclopedia->getAlbumInformation($album) ?: AlbumInformation::make();
|
"album.info.{$album->id}",
|
||||||
|
now()->addWeek(),
|
||||||
|
function () use ($album): AlbumInformation {
|
||||||
|
$info = $this->encyclopedia->getAlbumInformation($album) ?: AlbumInformation::make();
|
||||||
|
|
||||||
rescue_unless($album->has_cover, function () use ($info, $album): void {
|
rescue_unless($album->has_cover, function () use ($info, $album): void {
|
||||||
$this->mediaMetadataService->tryDownloadAlbumCover($album);
|
$this->mediaMetadataService->tryDownloadAlbumCover($album);
|
||||||
$info->cover = $album->cover;
|
$info->cover = $album->cover;
|
||||||
});
|
});
|
||||||
|
|
||||||
return $info;
|
return $info;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getArtistInformation(Artist $artist): ?ArtistInformation
|
public function getArtistInformation(Artist $artist): ?ArtistInformation
|
||||||
|
@ -42,7 +46,7 @@ class MediaInformationService
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cache::remember(
|
return Cache::remember(
|
||||||
"artist.info.$artist->id",
|
"artist.info.{$artist->id}",
|
||||||
now()->addWeek(),
|
now()->addWeek(),
|
||||||
function () use ($artist): ArtistInformation {
|
function () use ($artist): ArtistInformation {
|
||||||
$info = $this->encyclopedia->getArtistInformation($artist) ?: ArtistInformation::make();
|
$info = $this->encyclopedia->getArtistInformation($artist) ?: ArtistInformation::make();
|
||||||
|
|
|
@ -11,6 +11,7 @@ use App\Models\Song as Playable;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Repositories\SongRepository;
|
use App\Repositories\SongRepository;
|
||||||
use App\Values\SmartPlaylistRuleGroupCollection;
|
use App\Values\SmartPlaylistRuleGroupCollection;
|
||||||
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
@ -85,12 +86,12 @@ class PlaylistService
|
||||||
return $playlist;
|
return $playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Collection<array-key, Playable> */
|
/** @return EloquentCollection<array-key, Playable> */
|
||||||
public function addPlayablesToPlaylist(
|
public function addPlayablesToPlaylist(
|
||||||
Playlist $playlist,
|
Playlist $playlist,
|
||||||
Collection|Playable|array $playables,
|
Collection|Playable|array $playables,
|
||||||
User $user
|
User $user
|
||||||
): Collection {
|
): EloquentCollection {
|
||||||
return DB::transaction(function () use ($playlist, $playables, $user) {
|
return DB::transaction(function () use ($playlist, $playables, $user) {
|
||||||
$playables = Collection::wrap($playables);
|
$playables = Collection::wrap($playables);
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,12 @@ class QueueService
|
||||||
|
|
||||||
public function getQueueState(User $user): QueueStateDTO
|
public function getQueueState(User $user): QueueStateDTO
|
||||||
{
|
{
|
||||||
$state = QueueState::query()->where('user_id', $user->id)->firstOrCreate([
|
$state = QueueState::query()
|
||||||
'user_id' => $user->id,
|
->whereBelongsTo($user)
|
||||||
], [
|
->firstOrCreate(
|
||||||
'song_ids' => [],
|
['user_id' => $user->id],
|
||||||
]);
|
['song_ids' => []],
|
||||||
|
);
|
||||||
|
|
||||||
$currentSong = $state->current_song_id ? $this->songRepository->findOne($state->current_song_id, $user) : null;
|
$currentSong = $state->current_song_id ? $this->songRepository->findOne($state->current_song_id, $user) : null;
|
||||||
|
|
||||||
|
@ -33,11 +34,7 @@ class QueueService
|
||||||
|
|
||||||
public function updateQueueState(User $user, array $songIds): void
|
public function updateQueueState(User $user, array $songIds): void
|
||||||
{
|
{
|
||||||
QueueState::query()->updateOrCreate([
|
QueueState::query()->updateOrCreate(['user_id' => $user->id], ['song_ids' => $songIds]);
|
||||||
'user_id' => $user->id,
|
|
||||||
], [
|
|
||||||
'song_ids' => $songIds,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePlaybackStatus(User $user, Song $song, int $position): void
|
public function updatePlaybackStatus(User $user, Song $song, int $position): void
|
||||||
|
|
|
@ -52,7 +52,7 @@ class SearchService
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $repository->getMany(
|
return $repository->getMany(
|
||||||
ids: $repository->modelClass::search($keywords)->get()->take($count)->pluck('id')->all(), // @phpstan-ignore-line
|
ids: $repository->modelClass::search($keywords)->get()->take($count)->modelKeys(), // @phpstan-ignore-line
|
||||||
preserveOrder: true,
|
preserveOrder: true,
|
||||||
);
|
);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use App\Models\User;
|
||||||
use App\Values\SmartPlaylistRule as Rule;
|
use App\Values\SmartPlaylistRule as Rule;
|
||||||
use App\Values\SmartPlaylistRuleGroup as RuleGroup;
|
use App\Values\SmartPlaylistRuleGroup as RuleGroup;
|
||||||
use App\Values\SmartPlaylistSqlElements as SqlElements;
|
use App\Values\SmartPlaylistSqlElements as SqlElements;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class SmartPlaylistService
|
class SmartPlaylistService
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@ use App\Models\Song;
|
||||||
use App\Repositories\SongRepository;
|
use App\Repositories\SongRepository;
|
||||||
use App\Services\SongStorages\SongStorage;
|
use App\Services\SongStorages\SongStorage;
|
||||||
use App\Values\SongUpdateData;
|
use App\Values\SongUpdateData;
|
||||||
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
@ -97,34 +98,31 @@ class SongService
|
||||||
return $this->songRepository->getOne($song->id);
|
return $this->songRepository->getOne($song->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function markSongsAsPublic(Collection $songs): void
|
public function markSongsAsPublic(EloquentCollection $songs): void
|
||||||
{
|
{
|
||||||
Song::query()->whereIn('id', $songs->pluck('id'))->update(['is_public' => true]);
|
$songs->toQuery()->update(['is_public' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string> IDs of songs that are marked as private */
|
/** @return array<string> IDs of songs that are marked as private */
|
||||||
public function markSongsAsPrivate(Collection $songs): array
|
public function markSongsAsPrivate(EloquentCollection $songs): array
|
||||||
{
|
{
|
||||||
if (License::isPlus()) {
|
License::requirePlus();
|
||||||
// Songs that are in collaborative playlists can't be marked as private.
|
|
||||||
/**
|
|
||||||
* @var Collection<array-key, Song> $collaborativeSongs
|
|
||||||
*/
|
|
||||||
$collaborativeSongs = Song::query()
|
|
||||||
->whereIn('songs.id', $songs->pluck('id'))
|
|
||||||
->join('playlist_song', 'songs.id', '=', 'playlist_song.song_id')
|
|
||||||
->join('playlist_collaborators', 'playlist_song.playlist_id', '=', 'playlist_collaborators.playlist_id')
|
|
||||||
->select('songs.id')
|
|
||||||
->distinct()
|
|
||||||
->pluck('songs.id')
|
|
||||||
->all();
|
|
||||||
|
|
||||||
$applicableSongIds = $songs->whereNotIn('id', $collaborativeSongs)->pluck('id')->all();
|
// Songs that are in collaborative playlists can't be marked as private.
|
||||||
} else {
|
/**
|
||||||
$applicableSongIds = $songs->pluck('id')->all();
|
* @var Collection<array-key, Song> $collaborativeSongs
|
||||||
}
|
*/
|
||||||
|
$collaborativeSongs = $songs->toQuery()
|
||||||
|
->join('playlist_song', 'songs.id', '=', 'playlist_song.song_id')
|
||||||
|
->join('playlist_collaborators', 'playlist_song.playlist_id', '=', 'playlist_collaborators.playlist_id')
|
||||||
|
->select('songs.id')
|
||||||
|
->distinct()
|
||||||
|
->pluck('songs.id')
|
||||||
|
->all();
|
||||||
|
|
||||||
Song::query()->whereIn('id', $applicableSongIds)->update(['is_public' => false]);
|
$applicableSongIds = $songs->whereNotIn('id', $collaborativeSongs)->modelKeys();
|
||||||
|
|
||||||
|
Song::query()->whereKey($applicableSongIds)->update(['is_public' => false]);
|
||||||
|
|
||||||
return $applicableSongIds;
|
return $applicableSongIds;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,9 @@ final class LicenseInstance implements Arrayable, Jsonable
|
||||||
public static function fromJsonObject(object $json): self
|
public static function fromJsonObject(object $json): self
|
||||||
{
|
{
|
||||||
return new self(
|
return new self(
|
||||||
id: $json->id,
|
id: object_get($json, 'id'),
|
||||||
name: $json->name,
|
name: object_get($json, 'name'),
|
||||||
createdAt: Carbon::parse($json->created_at),
|
createdAt: Carbon::parse(object_get($json, 'created_at')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ final class EpisodePlayable implements Arrayable, Jsonable
|
||||||
public static function getForEpisode(Episode $episode): ?self
|
public static function getForEpisode(Episode $episode): ?self
|
||||||
{
|
{
|
||||||
/** @var self|null $cached */
|
/** @var self|null $cached */
|
||||||
$cached = Cache::get("episode-playable.$episode->id");
|
$cached = Cache::get("episode-playable.{$episode->id}");
|
||||||
|
|
||||||
return $cached?->valid() ? $cached : self::createForEpisode($episode);
|
return $cached?->valid() ? $cached : self::createForEpisode($episode);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ final class EpisodePlayable implements Arrayable, Jsonable
|
||||||
}
|
}
|
||||||
|
|
||||||
$playable = new self($file, md5_file($file));
|
$playable = new self($file, md5_file($file));
|
||||||
Cache::forever("episode-playable.$episode->id", $playable);
|
Cache::forever("episode-playable.{$episode->id}", $playable);
|
||||||
|
|
||||||
return $playable;
|
return $playable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class QueueStateFactory extends Factory
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'user_id' => User::factory(),
|
'user_id' => User::factory(),
|
||||||
'song_ids' => Song::factory()->count(3)->create()->pluck('id')->toArray(),
|
'song_ids' => Song::factory()->count(3)->create()->modelKeys(),
|
||||||
'current_song_id' => null,
|
'current_song_id' => null,
|
||||||
'playback_position' => 0,
|
'playback_position' => 0,
|
||||||
];
|
];
|
||||||
|
|
|
@ -26,10 +26,12 @@ parameters:
|
||||||
# Laravel factories allow declaration of dynamic methods as "states"
|
# Laravel factories allow declaration of dynamic methods as "states"
|
||||||
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Factories\\Factory::#'
|
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Factories\\Factory::#'
|
||||||
- '#expects App\\Models\\User\|null, Illuminate\\Database\\Eloquent\\Collection\|Illuminate\\Database\\Eloquent\\Model given#'
|
- '#expects App\\Models\\User\|null, Illuminate\\Database\\Eloquent\\Collection\|Illuminate\\Database\\Eloquent\\Model given#'
|
||||||
|
- '#expects App\\Models\\[a-zA-Z]*, Illuminate\\Database\\Eloquent\\Model\|null given#'
|
||||||
- '#Method App\\Models\\.*::query\(\) should return App\\Builders\\.*Builder but returns Illuminate\\Database\\Eloquent\\Builder<Illuminate\\Database\\Eloquent\\Model>#'
|
- '#Method App\\Models\\.*::query\(\) should return App\\Builders\\.*Builder but returns Illuminate\\Database\\Eloquent\\Builder<Illuminate\\Database\\Eloquent\\Model>#'
|
||||||
- '#Parameter \#1 \$callback of method Illuminate\\Support\\Collection<int,Illuminate\\Database\\Eloquent\\Model>::each\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\)#'
|
- '#Parameter \#1 \$callback of method Illuminate\\Support\\Collection<int,Illuminate\\Database\\Eloquent\\Model>::each\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\)#'
|
||||||
- '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::#'
|
- '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::#'
|
||||||
- '#Unknown parameter \$(type|user) in call to static method App\\Models\\Song::query\(\)#'
|
- '#Unknown parameter \$(type|user) in call to static method App\\Models\\Song::query\(\)#'
|
||||||
|
- "#Called 'modelKeys' on Laravel collection, but could have been retrieved as a query#"
|
||||||
|
|
||||||
|
|
||||||
excludePaths:
|
excludePaths:
|
||||||
|
|
|
@ -33,7 +33,7 @@ class AlbumCoverTest extends TestCase
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static fn (Album $target) => $target->is($album)), 'data:image/jpeg;base64,Rm9v');
|
->with(Mockery::on(static fn (Album $target) => $target->is($album)), 'data:image/jpeg;base64,Rm9v');
|
||||||
|
|
||||||
$this->putAs("api/album/$album->id/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
$this->putAs("api/album/{$album->id}/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class AlbumCoverTest extends TestCase
|
||||||
|
|
||||||
$this->mediaMetadataService->shouldNotReceive('writeAlbumCover');
|
$this->mediaMetadataService->shouldNotReceive('writeAlbumCover');
|
||||||
|
|
||||||
$this->putAs('api/album/' . $album->id . '/cover', ['cover' => 'data:image/jpeg;base64,Rm9v'], create_user())
|
$this->putAs("api/album/{$album->id}/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], create_user())
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ class AlbumInformationTest extends TestCase
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->getAs('api/albums/' . $album->id . '/information')
|
$this->getAs("api/albums/{$album->id}/information")
|
||||||
->assertJsonStructure(AlbumInformation::JSON_STRUCTURE);
|
->assertJsonStructure(AlbumInformation::JSON_STRUCTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,9 @@ class AlbumSongTest extends TestCase
|
||||||
public function index(): void
|
public function index(): void
|
||||||
{
|
{
|
||||||
$album = Album::factory()->create();
|
$album = Album::factory()->create();
|
||||||
|
|
||||||
Song::factory(5)->for($album)->create();
|
Song::factory(5)->for($album)->create();
|
||||||
|
|
||||||
$this->getAs('api/albums/' . $album->id . '/songs')
|
$this->getAs("api/albums/{$album->id}/songs")
|
||||||
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,9 @@ class ArtistAlbumTest extends TestCase
|
||||||
public function index(): void
|
public function index(): void
|
||||||
{
|
{
|
||||||
$artist = Artist::factory()->create();
|
$artist = Artist::factory()->create();
|
||||||
|
|
||||||
Album::factory(5)->for($artist)->create();
|
Album::factory(5)->for($artist)->create();
|
||||||
|
|
||||||
$this->getAs('api/artists/' . $artist->id . '/albums')
|
$this->getAs("api/artists/{$artist->id}/albums")
|
||||||
->assertJsonStructure(['*' => AlbumResource::JSON_STRUCTURE]);
|
->assertJsonStructure(['*' => AlbumResource::JSON_STRUCTURE]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,18 +32,18 @@ class ArtistImageTest extends TestCase
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static fn (Artist $target) => $target->is($artist)), 'data:image/jpeg;base64,Rm9v');
|
->with(Mockery::on(static fn (Artist $target) => $target->is($artist)), 'data:image/jpeg;base64,Rm9v');
|
||||||
|
|
||||||
$this->putAs("api/artist/$artist->id/image", ['image' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
$this->putAs("api/artist/{$artist->id}/image", ['image' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function updateNotAllowedForNormalUsers(): void
|
public function updateNotAllowedForNormalUsers(): void
|
||||||
{
|
{
|
||||||
Artist::factory()->create(['id' => 9999]);
|
$artist = Artist::factory()->create();
|
||||||
|
|
||||||
$this->mediaMetadataService->shouldNotReceive('writeArtistImage');
|
$this->mediaMetadataService->shouldNotReceive('writeArtistImage');
|
||||||
|
|
||||||
$this->putAs('api/artist/9999/image', ['image' => 'data:image/jpeg;base64,Rm9v'])
|
$this->putAs("api/artist/{$artist->id}/image", ['image' => 'data:image/jpeg;base64,Rm9v'])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ArtistInformationTest extends TestCase
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->getAs('api/artists/' . $artist->id . '/information')
|
$this->getAs("api/artists/{$artist->id}/information")
|
||||||
->assertJsonStructure(ArtistInformation::JSON_STRUCTURE);
|
->assertJsonStructure(ArtistInformation::JSON_STRUCTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class ArtistSongTest extends TestCase
|
||||||
|
|
||||||
Song::factory(5)->for($artist)->create();
|
Song::factory(5)->for($artist)->create();
|
||||||
|
|
||||||
$this->getAs('api/artists/' . $artist->id . '/songs')
|
$this->getAs("api/artists/{$artist->id}/songs")
|
||||||
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use App\Models\Interaction;
|
||||||
use App\Models\Playlist;
|
use App\Models\Playlist;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use App\Services\DownloadService;
|
use App\Services\DownloadService;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use Mockery\MockInterface;
|
use Mockery\MockInterface;
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
@ -47,7 +47,7 @@ class DownloadTest extends TestCase
|
||||||
->shouldReceive('getDownloadablePath')
|
->shouldReceive('getDownloadablePath')
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static function (Collection $retrievedSongs) use ($song) {
|
->with(Mockery::on(static function (Collection $retrievedSongs) use ($song) {
|
||||||
return $retrievedSongs->count() === 1 && $retrievedSongs->first()->id === $song->id;
|
return $retrievedSongs->count() === 1 && $retrievedSongs->first()->is($song);
|
||||||
}))
|
}))
|
||||||
->andReturn(test_path('songs/blank.mp3'));
|
->andReturn(test_path('songs/blank.mp3'));
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class DownloadTest extends TestCase
|
||||||
->shouldReceive('getDownloadablePath')
|
->shouldReceive('getDownloadablePath')
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
||||||
self::assertEqualsCanonicalizing($retrievedSongs->pluck('id')->all(), $songs->pluck('id')->all());
|
self::assertEqualsCanonicalizing($retrievedSongs->modelKeys(), $songs->modelKeys());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}))
|
}))
|
||||||
|
@ -89,7 +89,7 @@ class DownloadTest extends TestCase
|
||||||
->shouldReceive('getDownloadablePath')
|
->shouldReceive('getDownloadablePath')
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
||||||
self::assertEqualsCanonicalizing($retrievedSongs->pluck('id')->all(), $songs->pluck('id')->all());
|
self::assertEqualsCanonicalizing($retrievedSongs->modelKeys(), $songs->modelKeys());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}))
|
}))
|
||||||
|
@ -110,7 +110,7 @@ class DownloadTest extends TestCase
|
||||||
->shouldReceive('getDownloadablePath')
|
->shouldReceive('getDownloadablePath')
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
||||||
self::assertEqualsCanonicalizing($retrievedSongs->pluck('id')->all(), $songs->pluck('id')->all());
|
self::assertEqualsCanonicalizing($retrievedSongs->modelKeys(), $songs->modelKeys());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}))
|
}))
|
||||||
|
@ -133,7 +133,7 @@ class DownloadTest extends TestCase
|
||||||
$this->downloadService
|
$this->downloadService
|
||||||
->shouldReceive('getDownloadablePath')
|
->shouldReceive('getDownloadablePath')
|
||||||
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
->with(Mockery::on(static function (Collection $retrievedSongs) use ($songs): bool {
|
||||||
self::assertEqualsCanonicalizing($retrievedSongs->pluck('id')->all(), $songs->pluck('id')->all());
|
self::assertEqualsCanonicalizing($retrievedSongs->modelKeys(), $songs->modelKeys());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}))
|
}))
|
||||||
|
@ -162,7 +162,7 @@ class DownloadTest extends TestCase
|
||||||
$this->downloadService
|
$this->downloadService
|
||||||
->shouldReceive('getDownloadablePath')
|
->shouldReceive('getDownloadablePath')
|
||||||
->with(Mockery::on(static function (Collection $songs) use ($favorites): bool {
|
->with(Mockery::on(static function (Collection $songs) use ($favorites): bool {
|
||||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $favorites->pluck('song_id')->all());
|
self::assertEqualsCanonicalizing($songs->modelKeys(), $favorites->pluck('song_id')->all());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -76,7 +76,7 @@ class InteractionTest extends TestCase
|
||||||
|
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
$songs = Song::factory(2)->create();
|
$songs = Song::factory(2)->create();
|
||||||
$songIds = $songs->pluck('id')->all();
|
$songIds = $songs->modelKeys();
|
||||||
|
|
||||||
$this->postAs('api/interaction/batch/like', ['songs' => $songIds], $user);
|
$this->postAs('api/interaction/batch/like', ['songs' => $songIds], $user);
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class AlbumCoverTest extends PlusTestCase
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static fn (Album $target) => $target->is($album)), 'data:image/jpeg;base64,Rm9v');
|
->with(Mockery::on(static fn (Album $target) => $target->is($album)), 'data:image/jpeg;base64,Rm9v');
|
||||||
|
|
||||||
$this->putAs("api/albums/$album->id/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], $user)
|
$this->putAs("api/albums/{$album->id}/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], $user)
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class AlbumCoverTest extends PlusTestCase
|
||||||
->shouldReceive('writeAlbumCover')
|
->shouldReceive('writeAlbumCover')
|
||||||
->never();
|
->never();
|
||||||
|
|
||||||
$this->putAs("api/albums/$album->id/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], $user)
|
$this->putAs("api/albums/{$album->id}/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], $user)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class AlbumCoverTest extends PlusTestCase
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static fn (Album $target) => $target->is($album)), 'data:image/jpeg;base64,Rm9v');
|
->with(Mockery::on(static fn (Album $target) => $target->is($album)), 'data:image/jpeg;base64,Rm9v');
|
||||||
|
|
||||||
$this->putAs("api/albums/$album->id/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
$this->putAs("api/albums/{$album->id}/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ArtistImageTest extends PlusTestCase
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static fn (Artist $target) => $target->is($artist)), 'data:image/jpeg;base64,Rm9v');
|
->with(Mockery::on(static fn (Artist $target) => $target->is($artist)), 'data:image/jpeg;base64,Rm9v');
|
||||||
|
|
||||||
$this->putAs("api/artists/$artist->id/image", ['image' => 'data:image/jpeg;base64,Rm9v'], $user)
|
$this->putAs("api/artists/{$artist->id}/image", ['image' => 'data:image/jpeg;base64,Rm9v'], $user)
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class ArtistImageTest extends PlusTestCase
|
||||||
->shouldReceive('writeArtistImage')
|
->shouldReceive('writeArtistImage')
|
||||||
->never();
|
->never();
|
||||||
|
|
||||||
$this->putAs("api/artists/$artist->id/image", ['image' => 'data:image/jpeg;base64,Rm9v'], $user)
|
$this->putAs("api/artists/{$artist->id}/image", ['image' => 'data:image/jpeg;base64,Rm9v'], $user)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,11 @@ class ArtistImageTest extends PlusTestCase
|
||||||
->once()
|
->once()
|
||||||
->with(Mockery::on(static fn (Artist $target) => $target->is($artist)), 'data:image/jpeg;base64,Rm9v');
|
->with(Mockery::on(static fn (Artist $target) => $target->is($artist)), 'data:image/jpeg;base64,Rm9v');
|
||||||
|
|
||||||
$this->putAs("api/artists/$artist->id/image", ['image' => 'data:image/jpeg;base64,Rm9v'], create_admin())
|
$this->putAs(
|
||||||
|
"api/artists/{$artist->id}/image",
|
||||||
|
['image' => 'data:image/jpeg;base64,Rm9v'],
|
||||||
|
create_admin()
|
||||||
|
)
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class DownloadTest extends PlusTestCase
|
||||||
// Can't download a private song that doesn't belong to the user
|
// Can't download a private song that doesn't belong to the user
|
||||||
/** @var Song $externalPrivateSong */
|
/** @var Song $externalPrivateSong */
|
||||||
$externalPrivateSong = Song::factory()->private()->create();
|
$externalPrivateSong = Song::factory()->private()->create();
|
||||||
$this->get("download/songs?songs[]=$externalPrivateSong->id&api_token=" . $apiToken)
|
$this->get("download/songs?songs[]={$externalPrivateSong->id}&api_token=" . $apiToken)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// Can download a public song that doesn't belong to the user
|
// Can download a public song that doesn't belong to the user
|
||||||
|
@ -33,7 +33,7 @@ class DownloadTest extends PlusTestCase
|
||||||
->once()
|
->once()
|
||||||
->andReturn(test_path('songs/blank.mp3'));
|
->andReturn(test_path('songs/blank.mp3'));
|
||||||
|
|
||||||
$this->get("download/songs?songs[]=$externalPublicSong->id&api_token=" . $apiToken)
|
$this->get("download/songs?songs[]={$externalPublicSong->id}&api_token=" . $apiToken)
|
||||||
->assertOk();
|
->assertOk();
|
||||||
|
|
||||||
// Can download a private song that belongs to the user
|
// Can download a private song that belongs to the user
|
||||||
|
@ -42,7 +42,7 @@ class DownloadTest extends PlusTestCase
|
||||||
$downloadService->shouldReceive('getDownloadablePath')
|
$downloadService->shouldReceive('getDownloadablePath')
|
||||||
->once()
|
->once()
|
||||||
->andReturn(test_path('songs/blank.mp3'));
|
->andReturn(test_path('songs/blank.mp3'));
|
||||||
$this->get("download/songs?songs[]=$ownSong->id&api_token=" . $apiToken)
|
$this->get("download/songs?songs[]={$ownSong->id}&api_token=" . $apiToken)
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use App\Events\MultipleSongsLiked;
|
||||||
use App\Events\MultipleSongsUnliked;
|
use App\Events\MultipleSongsUnliked;
|
||||||
use App\Events\SongLikeToggled;
|
use App\Events\SongLikeToggled;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\PlusTestCase;
|
use Tests\PlusTestCase;
|
||||||
|
@ -23,7 +22,6 @@ class InteractionTest extends PlusTestCase
|
||||||
$owner = create_user();
|
$owner = create_user();
|
||||||
|
|
||||||
// Can't increase play count of a private song that doesn't belong to the user
|
// Can't increase play count of a private song that doesn't belong to the user
|
||||||
/** @var Song $externalPrivateSong */
|
|
||||||
$externalPrivateSong = Song::factory()->private()->create();
|
$externalPrivateSong = Song::factory()->private()->create();
|
||||||
$this->postAs('api/interaction/play', ['song' => $externalPrivateSong->id], $owner)
|
$this->postAs('api/interaction/play', ['song' => $externalPrivateSong->id], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
@ -75,26 +73,23 @@ class InteractionTest extends PlusTestCase
|
||||||
$owner = create_user();
|
$owner = create_user();
|
||||||
|
|
||||||
// Can't batch like private songs that don't belong to the user
|
// Can't batch like private songs that don't belong to the user
|
||||||
/** @var Collection $externalPrivateSongs */
|
|
||||||
$externalPrivateSongs = Song::factory()->count(3)->private()->create();
|
$externalPrivateSongs = Song::factory()->count(3)->private()->create();
|
||||||
$this->postAs('api/interaction/batch/like', ['songs' => $externalPrivateSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/like', ['songs' => $externalPrivateSongs->modelKeys()], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// Can batch like public songs that don't belong to the user
|
// Can batch like public songs that don't belong to the user
|
||||||
/** @var Collection $externalPublicSongs */
|
|
||||||
$externalPublicSongs = Song::factory()->count(3)->public()->create();
|
$externalPublicSongs = Song::factory()->count(3)->public()->create();
|
||||||
$this->postAs('api/interaction/batch/like', ['songs' => $externalPublicSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/like', ['songs' => $externalPublicSongs->modelKeys()], $owner)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
// Can batch like private songs that belong to the user
|
// Can batch like private songs that belong to the user
|
||||||
/** @var Collection $ownPrivateSongs */
|
|
||||||
$ownPrivateSongs = Song::factory()->count(3)->private()->for($owner, 'owner')->create();
|
$ownPrivateSongs = Song::factory()->count(3)->private()->for($owner, 'owner')->create();
|
||||||
$this->postAs('api/interaction/batch/like', ['songs' => $ownPrivateSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/like', ['songs' => $ownPrivateSongs->modelKeys()], $owner)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
// Can't batch like a mix of inaccessible and accessible songs
|
// Can't batch like a mix of inaccessible and accessible songs
|
||||||
$mixedSongs = $externalPrivateSongs->merge($externalPublicSongs);
|
$mixedSongs = $externalPrivateSongs->merge($externalPublicSongs);
|
||||||
$this->postAs('api/interaction/batch/like', ['songs' => $mixedSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/like', ['songs' => $mixedSongs->modelKeys()], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,26 +101,23 @@ class InteractionTest extends PlusTestCase
|
||||||
$owner = create_user();
|
$owner = create_user();
|
||||||
|
|
||||||
// Can't batch unlike private songs that don't belong to the user
|
// Can't batch unlike private songs that don't belong to the user
|
||||||
/** @var Collection $externalPrivateSongs */
|
|
||||||
$externalPrivateSongs = Song::factory()->count(3)->private()->create();
|
$externalPrivateSongs = Song::factory()->count(3)->private()->create();
|
||||||
$this->postAs('api/interaction/batch/unlike', ['songs' => $externalPrivateSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/unlike', ['songs' => $externalPrivateSongs->modelKeys()], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// Can batch unlike public songs that don't belong to the user
|
// Can batch unlike public songs that don't belong to the user
|
||||||
/** @var Collection $externalPublicSongs */
|
|
||||||
$externalPublicSongs = Song::factory()->count(3)->public()->create();
|
$externalPublicSongs = Song::factory()->count(3)->public()->create();
|
||||||
$this->postAs('api/interaction/batch/unlike', ['songs' => $externalPublicSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/unlike', ['songs' => $externalPublicSongs->modelKeys()], $owner)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
// Can batch unlike private songs that belong to the user
|
// Can batch unlike private songs that belong to the user
|
||||||
/** @var Collection $ownPrivateSongs */
|
|
||||||
$ownPrivateSongs = Song::factory()->count(3)->private()->for($owner, 'owner')->create();
|
$ownPrivateSongs = Song::factory()->count(3)->private()->for($owner, 'owner')->create();
|
||||||
$this->postAs('api/interaction/batch/unlike', ['songs' => $ownPrivateSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/unlike', ['songs' => $ownPrivateSongs->modelKeys()], $owner)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
// Can't batch unlike a mix of inaccessible and accessible songs
|
// Can't batch unlike a mix of inaccessible and accessible songs
|
||||||
$mixedSongs = $externalPrivateSongs->merge($externalPublicSongs);
|
$mixedSongs = $externalPrivateSongs->merge($externalPublicSongs);
|
||||||
$this->postAs('api/interaction/batch/unlike', ['songs' => $mixedSongs->pluck('id')->all()], $owner)
|
$this->postAs('api/interaction/batch/unlike', ['songs' => $mixedSongs->modelKeys()], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ class PlaylistCollaborationTest extends PlusTestCase
|
||||||
/** @var Playlist $playlist */
|
/** @var Playlist $playlist */
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
|
|
||||||
$this->postAs("api/playlists/$playlist->id/collaborators/invite", [], $playlist->user)
|
$this->postAs("api/playlists/{$playlist->id}/collaborators/invite", [], $playlist->user)
|
||||||
->assertJsonStructure(PlaylistCollaborationTokenResource::JSON_STRUCTURE);
|
->assertJsonStructure(PlaylistCollaborationTokenResource::JSON_STRUCTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,11 @@ class PlaylistCoverTest extends PlusTestCase
|
||||||
$collaborator = create_user();
|
$collaborator = create_user();
|
||||||
$playlist->addCollaborator($collaborator);
|
$playlist->addCollaborator($collaborator);
|
||||||
|
|
||||||
$this->putAs("api/playlists/$playlist->id/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], $collaborator)
|
$this->putAs(
|
||||||
|
"api/playlists/{$playlist->id}/cover",
|
||||||
|
['cover' => 'data:image/jpeg;base64,Rm9v'],
|
||||||
|
$collaborator
|
||||||
|
)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +34,7 @@ class PlaylistCoverTest extends PlusTestCase
|
||||||
$collaborator = create_user();
|
$collaborator = create_user();
|
||||||
$playlist->addCollaborator($collaborator);
|
$playlist->addCollaborator($collaborator);
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id/cover", [], $collaborator)
|
$this->deleteAs("api/playlists/{$playlist->id}/cover", [], $collaborator)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ class PlaylistFolderTest extends PlusTestCase
|
||||||
|
|
||||||
/** @var PlaylistFolder $ownerFolder */
|
/** @var PlaylistFolder $ownerFolder */
|
||||||
$ownerFolder = PlaylistFolder::factory()->for($playlist->user)->create();
|
$ownerFolder = PlaylistFolder::factory()->for($playlist->user)->create();
|
||||||
$ownerFolder->playlists()->attach($playlist->id);
|
$ownerFolder->playlists()->attach($playlist);
|
||||||
self::assertTrue($playlist->refresh()->getFolder($playlist->user)?->is($ownerFolder));
|
self::assertTrue($playlist->refresh()->getFolder($playlist->user)?->is($ownerFolder));
|
||||||
|
|
||||||
/** @var PlaylistFolder $collaboratorFolder */
|
/** @var PlaylistFolder $collaboratorFolder */
|
||||||
|
@ -30,7 +30,7 @@ class PlaylistFolderTest extends PlusTestCase
|
||||||
self::assertNull($playlist->getFolder($collaborator));
|
self::assertNull($playlist->getFolder($collaborator));
|
||||||
|
|
||||||
$this->postAs(
|
$this->postAs(
|
||||||
"api/playlist-folders/$collaboratorFolder->id/playlists",
|
"api/playlist-folders/{$collaboratorFolder->id}/playlists",
|
||||||
['playlists' => [$playlist->id]],
|
['playlists' => [$playlist->id]],
|
||||||
$collaborator
|
$collaborator
|
||||||
)
|
)
|
||||||
|
@ -54,17 +54,17 @@ class PlaylistFolderTest extends PlusTestCase
|
||||||
|
|
||||||
/** @var PlaylistFolder $ownerFolder */
|
/** @var PlaylistFolder $ownerFolder */
|
||||||
$ownerFolder = PlaylistFolder::factory()->for($playlist->user)->create();
|
$ownerFolder = PlaylistFolder::factory()->for($playlist->user)->create();
|
||||||
$ownerFolder->playlists()->attach($playlist->id);
|
$ownerFolder->playlists()->attach($playlist);
|
||||||
self::assertTrue($playlist->refresh()->getFolder($playlist->user)?->is($ownerFolder));
|
self::assertTrue($playlist->refresh()->getFolder($playlist->user)?->is($ownerFolder));
|
||||||
|
|
||||||
/** @var PlaylistFolder $collaboratorFolder */
|
/** @var PlaylistFolder $collaboratorFolder */
|
||||||
$collaboratorFolder = PlaylistFolder::factory()->for($collaborator)->create();
|
$collaboratorFolder = PlaylistFolder::factory()->for($collaborator)->create();
|
||||||
|
|
||||||
$collaboratorFolder->playlists()->attach($playlist->id);
|
$collaboratorFolder->playlists()->attach($playlist);
|
||||||
self::assertTrue($playlist->refresh()->getFolder($collaborator)?->is($collaboratorFolder));
|
self::assertTrue($playlist->refresh()->getFolder($collaborator)?->is($collaboratorFolder));
|
||||||
|
|
||||||
$this->deleteAs(
|
$this->deleteAs(
|
||||||
"api/playlist-folders/$collaboratorFolder->id/playlists",
|
"api/playlist-folders/{$collaboratorFolder->id}/playlists",
|
||||||
['playlists' => [$playlist->id]],
|
['playlists' => [$playlist->id]],
|
||||||
$collaborator
|
$collaborator
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,7 +22,7 @@ class PlaylistSongTest extends PlusTestCase
|
||||||
$collaborator = create_user();
|
$collaborator = create_user();
|
||||||
$playlist->addCollaborator($collaborator);
|
$playlist->addCollaborator($collaborator);
|
||||||
|
|
||||||
$this->getAs("api/playlists/$playlist->id/songs", $collaborator)
|
$this->getAs("api/playlists/{$playlist->id}/songs", $collaborator)
|
||||||
->assertSuccessful()
|
->assertSuccessful()
|
||||||
->assertJsonStructure(['*' => CollaborativeSongResource::JSON_STRUCTURE])
|
->assertJsonStructure(['*' => CollaborativeSongResource::JSON_STRUCTURE])
|
||||||
->assertJsonCount(3);
|
->assertJsonCount(3);
|
||||||
|
@ -42,7 +42,7 @@ class PlaylistSongTest extends PlusTestCase
|
||||||
$collaborator = create_user();
|
$collaborator = create_user();
|
||||||
$playlist->addCollaborator($collaborator);
|
$playlist->addCollaborator($collaborator);
|
||||||
|
|
||||||
$this->getAs("api/playlists/$playlist->id/songs", $collaborator)
|
$this->getAs("api/playlists/{$playlist->id}/songs", $collaborator)
|
||||||
->assertSuccessful()
|
->assertSuccessful()
|
||||||
->assertJsonStructure(['*' => CollaborativeSongResource::JSON_STRUCTURE])
|
->assertJsonStructure(['*' => CollaborativeSongResource::JSON_STRUCTURE])
|
||||||
->assertJsonCount(3)
|
->assertJsonCount(3)
|
||||||
|
@ -58,7 +58,7 @@ class PlaylistSongTest extends PlusTestCase
|
||||||
$playlist->addCollaborator($collaborator);
|
$playlist->addCollaborator($collaborator);
|
||||||
$songs = Song::factory()->for($collaborator, 'owner')->count(3)->create();
|
$songs = Song::factory()->for($collaborator, 'owner')->count(3)->create();
|
||||||
|
|
||||||
$this->postAs("api/playlists/$playlist->id/songs", ['songs' => $songs->pluck('id')->all()], $collaborator)
|
$this->postAs("api/playlists/{$playlist->id}/songs", ['songs' => $songs->modelKeys()], $collaborator)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
$playlist->refresh();
|
$playlist->refresh();
|
||||||
|
@ -75,7 +75,7 @@ class PlaylistSongTest extends PlusTestCase
|
||||||
$songs = Song::factory()->for($collaborator, 'owner')->count(3)->create();
|
$songs = Song::factory()->for($collaborator, 'owner')->count(3)->create();
|
||||||
$playlist->addPlayables($songs);
|
$playlist->addPlayables($songs);
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id/songs", ['songs' => $songs->pluck('id')->all()], $collaborator)
|
$this->deleteAs("api/playlists/{$playlist->id}/songs", ['songs' => $songs->modelKeys()], $collaborator)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
$playlist->refresh();
|
$playlist->refresh();
|
||||||
|
|
|
@ -52,7 +52,7 @@ class PlaylistTest extends PlusTestCase
|
||||||
/** @var Playlist $playlist */
|
/** @var Playlist $playlist */
|
||||||
$playlist = Playlist::factory()->smart()->create();
|
$playlist = Playlist::factory()->smart()->create();
|
||||||
|
|
||||||
$this->putAs("api/playlists/$playlist->id", [
|
$this->putAs("api/playlists/{$playlist->id}", [
|
||||||
'name' => 'Foo',
|
'name' => 'Foo',
|
||||||
'own_songs_only' => true,
|
'own_songs_only' => true,
|
||||||
'rules' => $playlist->rules->toArray(),
|
'rules' => $playlist->rules->toArray(),
|
||||||
|
@ -72,7 +72,7 @@ class PlaylistTest extends PlusTestCase
|
||||||
$collaborator = create_user();
|
$collaborator = create_user();
|
||||||
$playlist->addCollaborator($collaborator);
|
$playlist->addCollaborator($collaborator);
|
||||||
|
|
||||||
$this->putAs("api/playlists/$playlist->id", ['name' => 'Nope'], $collaborator)
|
$this->putAs("api/playlists/{$playlist->id}", ['name' => 'Nope'], $collaborator)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ class SongPlayTest extends PlusTestCase
|
||||||
->shouldReceive('stream')
|
->shouldReceive('stream')
|
||||||
->once();
|
->once();
|
||||||
|
|
||||||
$this->get("play/$song->id?t=$token->audioToken")
|
$this->get("play/{$song->id}?t=$token->audioToken")
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class SongPlayTest extends PlusTestCase
|
||||||
->shouldReceive('stream')
|
->shouldReceive('stream')
|
||||||
->once();
|
->once();
|
||||||
|
|
||||||
$this->get("play/$song->id?t=$token->audioToken")
|
$this->get("play/{$song->id}?t=$token->audioToken")
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class SongPlayTest extends PlusTestCase
|
||||||
/** @var CompositeToken $token */
|
/** @var CompositeToken $token */
|
||||||
$token = app(TokenManager::class)->createCompositeToken(create_user());
|
$token = app(TokenManager::class)->createCompositeToken(create_user());
|
||||||
|
|
||||||
$this->get("play/$song->id?t=$token->audioToken")
|
$this->get("play/{$song->id}?t=$token->audioToken")
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace Tests\Feature\KoelPlus;
|
namespace Tests\Feature\KoelPlus;
|
||||||
|
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\PlusTestCase;
|
use Tests\PlusTestCase;
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ class SongTest extends PlusTestCase
|
||||||
|
|
||||||
Song::factory(2)->public()->create();
|
Song::factory(2)->public()->create();
|
||||||
|
|
||||||
/** @var Collection<array-key, Song> $ownSongs */
|
|
||||||
$ownSongs = Song::factory(3)->for($user, 'owner')->create();
|
$ownSongs = Song::factory(3)->for($user, 'owner')->create();
|
||||||
|
|
||||||
$this->getAs('api/songs?own_songs_only=true', $user)
|
$this->getAs('api/songs?own_songs_only=true', $user)
|
||||||
|
@ -55,19 +53,19 @@ class SongTest extends PlusTestCase
|
||||||
$publicSong = Song::factory()->public()->create();
|
$publicSong = Song::factory()->public()->create();
|
||||||
|
|
||||||
// We can access public songs.
|
// We can access public songs.
|
||||||
$this->getAs("api/songs/$publicSong->id", $user)->assertSuccessful();
|
$this->getAs("api/songs/{$publicSong->id}", $user)->assertSuccessful();
|
||||||
|
|
||||||
/** @var Song $ownPrivateSong */
|
/** @var Song $ownPrivateSong */
|
||||||
$ownPrivateSong = Song::factory()->for($user, 'owner')->private()->create();
|
$ownPrivateSong = Song::factory()->for($user, 'owner')->private()->create();
|
||||||
|
|
||||||
// We can access our own private songs.
|
// We can access our own private songs.
|
||||||
$this->getAs('api/songs/' . $ownPrivateSong->id, $user)->assertSuccessful();
|
$this->getAs("api/songs/{$ownPrivateSong->id}", $user)->assertSuccessful();
|
||||||
|
|
||||||
/** @var Song $externalUnownedSong */
|
/** @var Song $externalUnownedSong */
|
||||||
$externalUnownedSong = Song::factory()->private()->create();
|
$externalUnownedSong = Song::factory()->private()->create();
|
||||||
|
|
||||||
// But we can't access private songs that are not ours.
|
// But we can't access private songs that are not ours.
|
||||||
$this->getAs("api/songs/$externalUnownedSong->id", $user)->assertForbidden();
|
$this->getAs("api/songs/{$externalUnownedSong->id}", $user)->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -76,12 +74,11 @@ class SongTest extends PlusTestCase
|
||||||
$currentUser = create_user();
|
$currentUser = create_user();
|
||||||
$anotherUser = create_user();
|
$anotherUser = create_user();
|
||||||
|
|
||||||
/** @var Collection<Song> $externalUnownedSongs */
|
|
||||||
$externalUnownedSongs = Song::factory(3)->for($anotherUser, 'owner')->private()->create();
|
$externalUnownedSongs = Song::factory(3)->for($anotherUser, 'owner')->private()->create();
|
||||||
|
|
||||||
// We can't edit songs that are not ours.
|
// We can't edit songs that are not ours.
|
||||||
$this->putAs('api/songs', [
|
$this->putAs('api/songs', [
|
||||||
'songs' => $externalUnownedSongs->pluck('id')->toArray(),
|
'songs' => $externalUnownedSongs->modelKeys(),
|
||||||
'data' => [
|
'data' => [
|
||||||
'title' => 'New Title',
|
'title' => 'New Title',
|
||||||
],
|
],
|
||||||
|
@ -91,7 +88,7 @@ class SongTest extends PlusTestCase
|
||||||
$mixedSongs = $externalUnownedSongs->merge(Song::factory(2)->for($currentUser, 'owner')->create());
|
$mixedSongs = $externalUnownedSongs->merge(Song::factory(2)->for($currentUser, 'owner')->create());
|
||||||
|
|
||||||
$this->putAs('api/songs', [
|
$this->putAs('api/songs', [
|
||||||
'songs' => $mixedSongs->pluck('id')->toArray(),
|
'songs' => $mixedSongs->modelKeys(),
|
||||||
'data' => [
|
'data' => [
|
||||||
'title' => 'New Title',
|
'title' => 'New Title',
|
||||||
],
|
],
|
||||||
|
@ -101,7 +98,7 @@ class SongTest extends PlusTestCase
|
||||||
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
||||||
|
|
||||||
$this->putAs('api/songs', [
|
$this->putAs('api/songs', [
|
||||||
'songs' => $ownSongs->pluck('id')->toArray(),
|
'songs' => $ownSongs->modelKeys(),
|
||||||
'data' => [
|
'data' => [
|
||||||
'title' => 'New Title',
|
'title' => 'New Title',
|
||||||
],
|
],
|
||||||
|
@ -114,35 +111,33 @@ class SongTest extends PlusTestCase
|
||||||
$currentUser = create_user();
|
$currentUser = create_user();
|
||||||
$anotherUser = create_user();
|
$anotherUser = create_user();
|
||||||
|
|
||||||
/** @var Collection<Song> $externalUnownedSongs */
|
|
||||||
$externalUnownedSongs = Song::factory(3)->for($anotherUser, 'owner')->private()->create();
|
$externalUnownedSongs = Song::factory(3)->for($anotherUser, 'owner')->private()->create();
|
||||||
|
|
||||||
// We can't delete songs that are not ours.
|
// We can't delete songs that are not ours.
|
||||||
$this->deleteAs('api/songs', ['songs' => $externalUnownedSongs->pluck('id')->toArray()], $currentUser)
|
$this->deleteAs('api/songs', ['songs' => $externalUnownedSongs->modelKeys()], $currentUser)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// Even if some of the songs are owned by us, we still can't delete them.
|
// Even if some of the songs are owned by us, we still can't delete them.
|
||||||
$mixedSongs = $externalUnownedSongs->merge(Song::factory(2)->for($currentUser, 'owner')->create());
|
$mixedSongs = $externalUnownedSongs->merge(Song::factory(2)->for($currentUser, 'owner')->create());
|
||||||
|
|
||||||
$this->deleteAs('api/songs', ['songs' => $mixedSongs->pluck('id')->toArray()], $currentUser)
|
$this->deleteAs('api/songs', ['songs' => $mixedSongs->modelKeys()], $currentUser)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// But we can delete our own songs.
|
// But we can delete our own songs.
|
||||||
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
||||||
|
|
||||||
$this->deleteAs('api/songs', ['songs' => $ownSongs->pluck('id')->toArray()], $currentUser)
|
$this->deleteAs('api/songs', ['songs' => $ownSongs->modelKeys()], $currentUser)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function publicizeSongs(): void
|
public function markSongsAsPublic(): void
|
||||||
{
|
{
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
|
|
||||||
/** @var Song $songs */
|
|
||||||
$songs = Song::factory(3)->for($user, 'owner')->private()->create();
|
$songs = Song::factory(3)->for($user, 'owner')->private()->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/publicize', ['songs' => $songs->pluck('id')->toArray()], $user)
|
$this->putAs('api/songs/publicize', ['songs' => $songs->modelKeys()], $user)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
$songs->each(static function (Song $song): void {
|
$songs->each(static function (Song $song): void {
|
||||||
|
@ -152,14 +147,13 @@ class SongTest extends PlusTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function privatizeSongs(): void
|
public function markSongsAsPrivate(): void
|
||||||
{
|
{
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
|
|
||||||
/** @var Song $songs */
|
|
||||||
$songs = Song::factory(3)->for($user, 'owner')->public()->create();
|
$songs = Song::factory(3)->for($user, 'owner')->public()->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/privatize', ['songs' => $songs->pluck('id')->toArray()], $user)
|
$this->putAs('api/songs/privatize', ['songs' => $songs->modelKeys()], $user)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
$songs->each(static function (Song $song): void {
|
$songs->each(static function (Song $song): void {
|
||||||
|
@ -173,12 +167,12 @@ class SongTest extends PlusTestCase
|
||||||
{
|
{
|
||||||
$songs = Song::factory(3)->public()->create();
|
$songs = Song::factory(3)->public()->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/privatize', ['songs' => $songs->pluck('id')->toArray()])
|
$this->putAs('api/songs/privatize', ['songs' => $songs->modelKeys()])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
$otherSongs = Song::factory(3)->private()->create();
|
$otherSongs = Song::factory(3)->private()->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/publicize', ['songs' => $otherSongs->pluck('id')->toArray()])
|
$this->putAs('api/songs/publicize', ['songs' => $otherSongs->modelKeys()])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace Tests\Feature\KoelPlus;
|
namespace Tests\Feature\KoelPlus;
|
||||||
|
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\PlusTestCase;
|
use Tests\PlusTestCase;
|
||||||
|
|
||||||
|
@ -17,17 +16,16 @@ class SongVisibilityTest extends PlusTestCase
|
||||||
$currentUser = create_user();
|
$currentUser = create_user();
|
||||||
$anotherUser = create_user();
|
$anotherUser = create_user();
|
||||||
|
|
||||||
/** @var Collection<Song> $externalSongs */
|
|
||||||
$externalSongs = Song::factory(3)->for($anotherUser, 'owner')->private()->create();
|
$externalSongs = Song::factory(3)->for($anotherUser, 'owner')->private()->create();
|
||||||
|
|
||||||
// We can't make public songs that are not ours.
|
// We can't make public songs that are not ours.
|
||||||
$this->putAs('api/songs/publicize', ['songs' => $externalSongs->pluck('id')->toArray()], $currentUser)
|
$this->putAs('api/songs/publicize', ['songs' => $externalSongs->modelKeys()], $currentUser)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// But we can our own songs.
|
// But we can our own songs.
|
||||||
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/publicize', ['songs' => $ownSongs->pluck('id')->toArray()], $currentUser)
|
$this->putAs('api/songs/publicize', ['songs' => $ownSongs->modelKeys()], $currentUser)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
$ownSongs->each(static fn (Song $song) => self::assertTrue($song->refresh()->is_public));
|
$ownSongs->each(static fn (Song $song) => self::assertTrue($song->refresh()->is_public));
|
||||||
|
@ -39,17 +37,16 @@ class SongVisibilityTest extends PlusTestCase
|
||||||
$currentUser = create_user();
|
$currentUser = create_user();
|
||||||
$anotherUser = create_user();
|
$anotherUser = create_user();
|
||||||
|
|
||||||
/** @var Collection<Song> $externalSongs */
|
|
||||||
$externalSongs = Song::factory(3)->for($anotherUser, 'owner')->public()->create();
|
$externalSongs = Song::factory(3)->for($anotherUser, 'owner')->public()->create();
|
||||||
|
|
||||||
// We can't Mark as Private songs that are not ours.
|
// We can't Mark as Private songs that are not ours.
|
||||||
$this->putAs('api/songs/privatize', ['songs' => $externalSongs->pluck('id')->toArray()], $currentUser)
|
$this->putAs('api/songs/privatize', ['songs' => $externalSongs->modelKeys()], $currentUser)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
// But we can our own songs.
|
// But we can our own songs.
|
||||||
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
$ownSongs = Song::factory(3)->for($currentUser, 'owner')->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/privatize', ['songs' => $ownSongs->pluck('id')->toArray()], $currentUser)
|
$this->putAs('api/songs/privatize', ['songs' => $ownSongs->modelKeys()], $currentUser)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
$ownSongs->each(static fn (Song $song) => self::assertFalse($song->refresh()->is_public));
|
$ownSongs->each(static fn (Song $song) => self::assertFalse($song->refresh()->is_public));
|
||||||
|
|
|
@ -22,7 +22,7 @@ class PlayCountTest extends TestCase
|
||||||
'play_count' => 10,
|
'play_count' => 10,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->postAs('/api/interaction/play', ['song' => $interaction->song->id], $interaction->user)
|
$this->postAs('/api/interaction/play', ['song' => $interaction->song_id], $interaction->user)
|
||||||
->assertJsonStructure([
|
->assertJsonStructure([
|
||||||
'type',
|
'type',
|
||||||
'id',
|
'id',
|
||||||
|
@ -53,8 +53,8 @@ class PlayCountTest extends TestCase
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$interaction = Interaction::query()
|
$interaction = Interaction::query()
|
||||||
->where('song_id', $song->id)
|
->whereBelongsTo($song)
|
||||||
->where('user_id', $user->id)
|
->whereBelongsTo($user)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
self::assertSame(1, $interaction->play_count);
|
self::assertSame(1, $interaction->play_count);
|
||||||
|
|
|
@ -19,7 +19,7 @@ class PlaylistCoverTest extends TestCase
|
||||||
self::assertNull($playlist->cover);
|
self::assertNull($playlist->cover);
|
||||||
|
|
||||||
$this->putAs(
|
$this->putAs(
|
||||||
"api/playlists/$playlist->id/cover",
|
"api/playlists/{$playlist->id}/cover",
|
||||||
['cover' => read_as_data_url(test_path('blobs/cover.png'))],
|
['cover' => read_as_data_url(test_path('blobs/cover.png'))],
|
||||||
$playlist->user
|
$playlist->user
|
||||||
)
|
)
|
||||||
|
@ -33,7 +33,11 @@ class PlaylistCoverTest extends TestCase
|
||||||
{
|
{
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
|
|
||||||
$this->putAs("api/playlists/$playlist->id/cover", ['cover' => 'data:image/jpeg;base64,Rm9v'], create_user())
|
$this->putAs(
|
||||||
|
"api/playlists/{$playlist->id}/cover",
|
||||||
|
['cover' => 'data:image/jpeg;base64,Rm9v'],
|
||||||
|
create_user()
|
||||||
|
)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +46,7 @@ class PlaylistCoverTest extends TestCase
|
||||||
{
|
{
|
||||||
$playlist = Playlist::factory()->create(['cover' => 'cover.jpg']);
|
$playlist = Playlist::factory()->create(['cover' => 'cover.jpg']);
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id/cover", [], $playlist->user)
|
$this->deleteAs("api/playlists/{$playlist->id}/cover", [], $playlist->user)
|
||||||
->assertNoContent();
|
->assertNoContent();
|
||||||
|
|
||||||
self::assertNull($playlist->refresh()->cover);
|
self::assertNull($playlist->refresh()->cover);
|
||||||
|
@ -53,7 +57,7 @@ class PlaylistCoverTest extends TestCase
|
||||||
{
|
{
|
||||||
$playlist = Playlist::factory()->create(['cover' => 'cover.jpg']);
|
$playlist = Playlist::factory()->create(['cover' => 'cover.jpg']);
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id/cover", [], create_user())
|
$this->deleteAs("api/playlists/{$playlist->id}/cover", [], create_user())
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
self::assertSame('cover.jpg', $playlist->refresh()->getRawOriginal('cover'));
|
self::assertSame('cover.jpg', $playlist->refresh()->getRawOriginal('cover'));
|
||||||
|
|
|
@ -39,7 +39,7 @@ class PlaylistFolderTest extends TestCase
|
||||||
{
|
{
|
||||||
$folder = PlaylistFolder::factory()->create(['name' => 'Metal']);
|
$folder = PlaylistFolder::factory()->create(['name' => 'Metal']);
|
||||||
|
|
||||||
$this->patchAs('api/playlist-folders/' . $folder->id, ['name' => 'Classical'], $folder->user)
|
$this->patchAs("api/playlist-folders/{$folder->id}", ['name' => 'Classical'], $folder->user)
|
||||||
->assertJsonStructure(PlaylistFolderResource::JSON_STRUCTURE);
|
->assertJsonStructure(PlaylistFolderResource::JSON_STRUCTURE);
|
||||||
|
|
||||||
self::assertSame('Classical', $folder->fresh()->name);
|
self::assertSame('Classical', $folder->fresh()->name);
|
||||||
|
@ -50,7 +50,7 @@ class PlaylistFolderTest extends TestCase
|
||||||
{
|
{
|
||||||
$folder = PlaylistFolder::factory()->create(['name' => 'Metal']);
|
$folder = PlaylistFolder::factory()->create(['name' => 'Metal']);
|
||||||
|
|
||||||
$this->patchAs('api/playlist-folders/' . $folder->id, ['name' => 'Classical'])
|
$this->patchAs("api/playlist-folders/{$folder->id}", ['name' => 'Classical'])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
self::assertSame('Metal', $folder->fresh()->name);
|
self::assertSame('Metal', $folder->fresh()->name);
|
||||||
|
@ -61,7 +61,7 @@ class PlaylistFolderTest extends TestCase
|
||||||
{
|
{
|
||||||
$folder = PlaylistFolder::factory()->create();
|
$folder = PlaylistFolder::factory()->create();
|
||||||
|
|
||||||
$this->deleteAs('api/playlist-folders/' . $folder->id, ['name' => 'Classical'], $folder->user)
|
$this->deleteAs("api/playlist-folders/{$folder->id}", ['name' => 'Classical'], $folder->user)
|
||||||
->assertNoContent();
|
->assertNoContent();
|
||||||
|
|
||||||
self::assertModelMissing($folder);
|
self::assertModelMissing($folder);
|
||||||
|
@ -73,7 +73,7 @@ class PlaylistFolderTest extends TestCase
|
||||||
/** @var PlaylistFolder $folder */
|
/** @var PlaylistFolder $folder */
|
||||||
$folder = PlaylistFolder::factory()->create();
|
$folder = PlaylistFolder::factory()->create();
|
||||||
|
|
||||||
$this->deleteAs('api/playlist-folders/' . $folder->id, ['name' => 'Classical'])
|
$this->deleteAs("api/playlist-folders/{$folder->id}", ['name' => 'Classical'])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
self::assertModelExists($folder);
|
self::assertModelExists($folder);
|
||||||
|
@ -89,7 +89,11 @@ class PlaylistFolderTest extends TestCase
|
||||||
$playlist = Playlist::factory()->for($folder->user)->create();
|
$playlist = Playlist::factory()->for($folder->user)->create();
|
||||||
self::assertNull($playlist->getFolderId($folder->user));
|
self::assertNull($playlist->getFolderId($folder->user));
|
||||||
|
|
||||||
$this->postAs("api/playlist-folders/$folder->id/playlists", ['playlists' => [$playlist->id]], $folder->user)
|
$this->postAs(
|
||||||
|
"api/playlist-folders/{$folder->id}/playlists",
|
||||||
|
['playlists' => [$playlist->id]],
|
||||||
|
$folder->user
|
||||||
|
)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
self::assertTrue($playlist->fresh()->getFolder($folder->user)->is($folder));
|
self::assertTrue($playlist->fresh()->getFolder($folder->user)->is($folder));
|
||||||
|
@ -105,7 +109,7 @@ class PlaylistFolderTest extends TestCase
|
||||||
$playlist = Playlist::factory()->for($folder->user)->create();
|
$playlist = Playlist::factory()->for($folder->user)->create();
|
||||||
self::assertNull($playlist->getFolderId($folder->user));
|
self::assertNull($playlist->getFolderId($folder->user));
|
||||||
|
|
||||||
$this->postAs("api/playlist-folders/$folder->id/playlists", ['playlists' => [$playlist->id]])
|
$this->postAs("api/playlist-folders/{$folder->id}/playlists", ['playlists' => [$playlist->id]])
|
||||||
->assertUnprocessable();
|
->assertUnprocessable();
|
||||||
|
|
||||||
self::assertNull($playlist->fresh()->getFolder($folder->user));
|
self::assertNull($playlist->fresh()->getFolder($folder->user));
|
||||||
|
@ -120,10 +124,14 @@ class PlaylistFolderTest extends TestCase
|
||||||
/** @var Playlist $playlist */
|
/** @var Playlist $playlist */
|
||||||
$playlist = Playlist::factory()->for($folder->user)->create();
|
$playlist = Playlist::factory()->for($folder->user)->create();
|
||||||
|
|
||||||
$folder->playlists()->attach($playlist->id);
|
$folder->playlists()->attach($playlist);
|
||||||
self::assertTrue($playlist->refresh()->getFolder($folder->user)->is($folder));
|
self::assertTrue($playlist->refresh()->getFolder($folder->user)->is($folder));
|
||||||
|
|
||||||
$this->deleteAs("api/playlist-folders/$folder->id/playlists", ['playlists' => [$playlist->id]], $folder->user)
|
$this->deleteAs(
|
||||||
|
"api/playlist-folders/{$folder->id}/playlists",
|
||||||
|
['playlists' => [$playlist->id]],
|
||||||
|
$folder->user
|
||||||
|
)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
self::assertNull($playlist->fresh()->getFolder($folder->user));
|
self::assertNull($playlist->fresh()->getFolder($folder->user));
|
||||||
|
@ -138,10 +146,10 @@ class PlaylistFolderTest extends TestCase
|
||||||
/** @var Playlist $playlist */
|
/** @var Playlist $playlist */
|
||||||
$playlist = Playlist::factory()->for($folder->user)->create();
|
$playlist = Playlist::factory()->for($folder->user)->create();
|
||||||
|
|
||||||
$folder->playlists()->attach($playlist->id);
|
$folder->playlists()->attach($playlist);
|
||||||
self::assertTrue($playlist->refresh()->getFolder($folder->user)->is($folder));
|
self::assertTrue($playlist->refresh()->getFolder($folder->user)->is($folder));
|
||||||
|
|
||||||
$this->deleteAs("api/playlist-folders/$folder->id/playlists", ['playlists' => [$playlist->id]])
|
$this->deleteAs("api/playlist-folders/{$folder->id}/playlists", ['playlists' => [$playlist->id]])
|
||||||
->assertUnprocessable();
|
->assertUnprocessable();
|
||||||
|
|
||||||
self::assertTrue($playlist->refresh()->getFolder($folder->user)->is($folder));
|
self::assertTrue($playlist->refresh()->getFolder($folder->user)->is($folder));
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace Tests\Feature;
|
||||||
use App\Http\Resources\SongResource;
|
use App\Http\Resources\SongResource;
|
||||||
use App\Models\Playlist;
|
use App\Models\Playlist;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ class PlaylistSongTest extends TestCase
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
$playlist->addPlayables(Song::factory(5)->create());
|
$playlist->addPlayables(Song::factory(5)->create());
|
||||||
|
|
||||||
$this->getAs("api/playlists/$playlist->id/songs", $playlist->user)
|
$this->getAs("api/playlists/{$playlist->id}/songs", $playlist->user)
|
||||||
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ class PlaylistSongTest extends TestCase
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->getAs("api/playlists/$playlist->id/songs", $playlist->user)
|
$this->getAs("api/playlists/{$playlist->id}/songs", $playlist->user)
|
||||||
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
->assertJsonStructure(['*' => SongResource::JSON_STRUCTURE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +56,7 @@ class PlaylistSongTest extends TestCase
|
||||||
$playlist = Playlist::factory()->for(create_user())->create();
|
$playlist = Playlist::factory()->for(create_user())->create();
|
||||||
$playlist->addPlayables(Song::factory(5)->create());
|
$playlist->addPlayables(Song::factory(5)->create());
|
||||||
|
|
||||||
$this->getAs("api/playlists/$playlist->id/songs")
|
$this->getAs("api/playlists/{$playlist->id}/songs")
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,13 +66,12 @@ class PlaylistSongTest extends TestCase
|
||||||
/** @var Playlist $playlist */
|
/** @var Playlist $playlist */
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
|
|
||||||
/** @var Collection<array-key, Song> $songs */
|
|
||||||
$songs = Song::factory(2)->create();
|
$songs = Song::factory(2)->create();
|
||||||
|
|
||||||
$this->postAs("api/playlists/$playlist->id/songs", ['songs' => $songs->pluck('id')->all()], $playlist->user)
|
$this->postAs("api/playlists/{$playlist->id}/songs", ['songs' => $songs->modelKeys()], $playlist->user)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
|
|
||||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->playables->pluck('id')->all());
|
self::assertEqualsCanonicalizing($songs->modelKeys(), $playlist->playables->modelKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -84,7 +82,6 @@ class PlaylistSongTest extends TestCase
|
||||||
|
|
||||||
$toRemainSongs = Song::factory(5)->create();
|
$toRemainSongs = Song::factory(5)->create();
|
||||||
|
|
||||||
/** @var Collection<array-key, Song> $toBeRemovedSongs */
|
|
||||||
$toBeRemovedSongs = Song::factory(2)->create();
|
$toBeRemovedSongs = Song::factory(2)->create();
|
||||||
|
|
||||||
$playlist->addPlayables($toRemainSongs->merge($toBeRemovedSongs));
|
$playlist->addPlayables($toRemainSongs->merge($toBeRemovedSongs));
|
||||||
|
@ -92,15 +89,15 @@ class PlaylistSongTest extends TestCase
|
||||||
self::assertCount(7, $playlist->playables);
|
self::assertCount(7, $playlist->playables);
|
||||||
|
|
||||||
$this->deleteAs(
|
$this->deleteAs(
|
||||||
"api/playlists/$playlist->id/songs",
|
"api/playlists/{$playlist->id}/songs",
|
||||||
['songs' => $toBeRemovedSongs->pluck('id')->all()],
|
['songs' => $toBeRemovedSongs->modelKeys()],
|
||||||
$playlist->user
|
$playlist->user
|
||||||
)
|
)
|
||||||
->assertNoContent();
|
->assertNoContent();
|
||||||
|
|
||||||
$playlist->refresh();
|
$playlist->refresh();
|
||||||
|
|
||||||
self::assertEqualsCanonicalizing($toRemainSongs->pluck('id')->all(), $playlist->playables->pluck('id')->all());
|
self::assertEqualsCanonicalizing($toRemainSongs->modelKeys(), $playlist->playables->modelKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -112,10 +109,10 @@ class PlaylistSongTest extends TestCase
|
||||||
/** @var Song $song */
|
/** @var Song $song */
|
||||||
$song = Song::factory()->create();
|
$song = Song::factory()->create();
|
||||||
|
|
||||||
$this->postAs("api/playlists/$playlist->id/songs", ['songs' => [$song->id]])
|
$this->postAs("api/playlists/{$playlist->id}/songs", ['songs' => [$song->id]])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id/songs", ['songs' => [$song->id]])
|
$this->deleteAs("api/playlists/{$playlist->id}/songs", ['songs' => [$song->id]])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,12 +136,12 @@ class PlaylistSongTest extends TestCase
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$songs = Song::factory(2)->create()->pluck('id')->all();
|
$songs = Song::factory(2)->create()->modelKeys();
|
||||||
|
|
||||||
$this->postAs("api/playlists/$playlist->id/songs", ['songs' => $songs], $playlist->user)
|
$this->postAs("api/playlists/{$playlist->id}/songs", ['songs' => $songs], $playlist->user)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id/songs", ['songs' => $songs], $playlist->user)
|
$this->deleteAs("api/playlists/{$playlist->id}/songs", ['songs' => $songs], $playlist->user)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use App\Http\Resources\PlaylistResource;
|
||||||
use App\Models\Playlist;
|
use App\Models\Playlist;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use App\Values\SmartPlaylistRule;
|
use App\Values\SmartPlaylistRule;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
@ -30,23 +29,21 @@ class PlaylistTest extends TestCase
|
||||||
{
|
{
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
|
|
||||||
/** @var array<Song>|Collection $songs */
|
|
||||||
$songs = Song::factory(4)->create();
|
$songs = Song::factory(4)->create();
|
||||||
|
|
||||||
$this->postAs('api/playlists', [
|
$this->postAs('api/playlists', [
|
||||||
'name' => 'Foo Bar',
|
'name' => 'Foo Bar',
|
||||||
'songs' => $songs->pluck('id')->all(),
|
'songs' => $songs->modelKeys(),
|
||||||
'rules' => [],
|
'rules' => [],
|
||||||
], $user)
|
], $user)
|
||||||
->assertJsonStructure(PlaylistResource::JSON_STRUCTURE);
|
->assertJsonStructure(PlaylistResource::JSON_STRUCTURE);
|
||||||
|
|
||||||
/** @var Playlist $playlist */
|
|
||||||
$playlist = Playlist::query()->latest()->first();
|
$playlist = Playlist::query()->latest()->first();
|
||||||
|
|
||||||
self::assertSame('Foo Bar', $playlist->name);
|
self::assertSame('Foo Bar', $playlist->name);
|
||||||
self::assertTrue($playlist->ownedBy($user));
|
self::assertTrue($playlist->ownedBy($user));
|
||||||
self::assertNull($playlist->getFolder());
|
self::assertNull($playlist->getFolder());
|
||||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->playables->pluck('id')->all());
|
self::assertEqualsCanonicalizing($songs->modelKeys(), $playlist->playables->modelKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -70,7 +67,6 @@ class PlaylistTest extends TestCase
|
||||||
],
|
],
|
||||||
], $user)->assertJsonStructure(PlaylistResource::JSON_STRUCTURE);
|
], $user)->assertJsonStructure(PlaylistResource::JSON_STRUCTURE);
|
||||||
|
|
||||||
/** @var Playlist $playlist */
|
|
||||||
$playlist = Playlist::query()->latest()->first();
|
$playlist = Playlist::query()->latest()->first();
|
||||||
|
|
||||||
self::assertSame('Smart Foo Bar', $playlist->name);
|
self::assertSame('Smart Foo Bar', $playlist->name);
|
||||||
|
@ -98,7 +94,7 @@ class PlaylistTest extends TestCase
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'songs' => Song::factory(3)->create()->pluck('id')->all(),
|
'songs' => Song::factory(3)->create()->modelKeys(),
|
||||||
])->assertUnprocessable();
|
])->assertUnprocessable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +112,9 @@ class PlaylistTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function updatePlaylistName(): void
|
public function updatePlaylistName(): void
|
||||||
{
|
{
|
||||||
/** @var Playlist $playlist */
|
|
||||||
$playlist = Playlist::factory()->create(['name' => 'Foo']);
|
$playlist = Playlist::factory()->create(['name' => 'Foo']);
|
||||||
|
|
||||||
$this->putAs("api/playlists/$playlist->id", ['name' => 'Bar'], $playlist->user)
|
$this->putAs("api/playlists/{$playlist->id}", ['name' => 'Bar'], $playlist->user)
|
||||||
->assertJsonStructure(PlaylistResource::JSON_STRUCTURE);
|
->assertJsonStructure(PlaylistResource::JSON_STRUCTURE);
|
||||||
|
|
||||||
self::assertSame('Bar', $playlist->refresh()->name);
|
self::assertSame('Bar', $playlist->refresh()->name);
|
||||||
|
@ -128,20 +123,18 @@ class PlaylistTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function nonOwnerCannotUpdatePlaylist(): void
|
public function nonOwnerCannotUpdatePlaylist(): void
|
||||||
{
|
{
|
||||||
/** @var Playlist $playlist */
|
|
||||||
$playlist = Playlist::factory()->create(['name' => 'Foo']);
|
$playlist = Playlist::factory()->create(['name' => 'Foo']);
|
||||||
|
|
||||||
$this->putAs("api/playlists/$playlist->id", ['name' => 'Qux'])->assertForbidden();
|
$this->putAs("api/playlists/{$playlist->id}", ['name' => 'Qux'])->assertForbidden();
|
||||||
self::assertSame('Foo', $playlist->refresh()->name);
|
self::assertSame('Foo', $playlist->refresh()->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function deletePlaylist(): void
|
public function deletePlaylist(): void
|
||||||
{
|
{
|
||||||
/** @var Playlist $playlist */
|
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id", [], $playlist->user);
|
$this->deleteAs("api/playlists/{$playlist->id}", [], $playlist->user);
|
||||||
|
|
||||||
self::assertModelMissing($playlist);
|
self::assertModelMissing($playlist);
|
||||||
}
|
}
|
||||||
|
@ -149,10 +142,9 @@ class PlaylistTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function nonOwnerCannotDeletePlaylist(): void
|
public function nonOwnerCannotDeletePlaylist(): void
|
||||||
{
|
{
|
||||||
/** @var Playlist $playlist */
|
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
|
|
||||||
$this->deleteAs("api/playlists/$playlist->id")->assertForbidden();
|
$this->deleteAs("api/playlists/{$playlist->id}")->assertForbidden();
|
||||||
|
|
||||||
self::assertModelExists($playlist);
|
self::assertModelExists($playlist);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,13 +45,13 @@ class QueueTest extends TestCase
|
||||||
|
|
||||||
self::assertDatabaseMissing(QueueState::class, ['user_id' => $user->id]);
|
self::assertDatabaseMissing(QueueState::class, ['user_id' => $user->id]);
|
||||||
|
|
||||||
$songIds = Song::factory(3)->create()->pluck('id')->toArray();
|
$songIds = Song::factory(3)->create()->modelKeys();
|
||||||
|
|
||||||
$this->putAs('api/queue/state', ['songs' => $songIds], $user)
|
$this->putAs('api/queue/state', ['songs' => $songIds], $user)
|
||||||
->assertNoContent();
|
->assertNoContent();
|
||||||
|
|
||||||
/** @var QueueState $queue */
|
/** @var QueueState $queue */
|
||||||
$queue = QueueState::query()->where('user_id', $user->id)->firstOrFail();
|
$queue = QueueState::query()->whereBelongsTo($user)->firstOrFail();
|
||||||
self::assertEqualsCanonicalizing($songIds, $queue->song_ids);
|
self::assertEqualsCanonicalizing($songIds, $queue->song_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ScrobbleTest extends TestCase
|
||||||
)
|
)
|
||||||
->once();
|
->once();
|
||||||
|
|
||||||
$this->postAs("/api/songs/$song->id/scrobble", ['timestamp' => 100], $user)
|
$this->postAs("/api/songs/{$song->id}/scrobble", ['timestamp' => 100], $user)
|
||||||
->assertNoContent();
|
->assertNoContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class SongPlayTest extends TestCase
|
||||||
->shouldReceive('stream')
|
->shouldReceive('stream')
|
||||||
->once();
|
->once();
|
||||||
|
|
||||||
$this->get("play/$song->id?t=$token->audioToken")
|
$this->get("play/{$song->id}?t=$token->audioToken")
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class SongPlayTest extends TestCase
|
||||||
->shouldReceive('stream')
|
->shouldReceive('stream')
|
||||||
->once();
|
->once();
|
||||||
|
|
||||||
$this->get("play/$song->id?t=$token->audioToken")
|
$this->get("play/{$song->id}?t=$token->audioToken")
|
||||||
->assertOk();
|
->assertOk();
|
||||||
|
|
||||||
config(['koel.streaming.transcode_flac' => false]);
|
config(['koel.streaming.transcode_flac' => false]);
|
||||||
|
@ -79,7 +79,7 @@ class SongPlayTest extends TestCase
|
||||||
->shouldReceive('stream')
|
->shouldReceive('stream')
|
||||||
->once();
|
->once();
|
||||||
|
|
||||||
$this->get("play/$song->id/1?t=$token->audioToken")
|
$this->get("play/{$song->id}/1?t=$token->audioToken")
|
||||||
->assertOk();
|
->assertOk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,9 @@ class SongTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function destroy(): void
|
public function destroy(): void
|
||||||
{
|
{
|
||||||
/** @var Collection<array-key, Song> $songs */
|
|
||||||
$songs = Song::factory(3)->create();
|
$songs = Song::factory(3)->create();
|
||||||
|
|
||||||
$this->deleteAs('api/songs', ['songs' => $songs->pluck('id')->all()], create_admin())
|
$this->deleteAs('api/songs', ['songs' => $songs->modelKeys()], create_admin())
|
||||||
->assertNoContent();
|
->assertNoContent();
|
||||||
|
|
||||||
$songs->each(fn (Song $song) => $this->assertModelMissing($song));
|
$songs->each(fn (Song $song) => $this->assertModelMissing($song));
|
||||||
|
@ -47,10 +46,9 @@ class SongTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function unauthorizedDelete(): void
|
public function unauthorizedDelete(): void
|
||||||
{
|
{
|
||||||
/** @var Collection<array-key, Song> $songs */
|
|
||||||
$songs = Song::factory(3)->create();
|
$songs = Song::factory(3)->create();
|
||||||
|
|
||||||
$this->deleteAs('api/songs', ['songs' => $songs->pluck('id')->all()])
|
$this->deleteAs('api/songs', ['songs' => $songs->modelKeys()])
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
$songs->each(fn (Song $song) => $this->assertModelExists($song));
|
$songs->each(fn (Song $song) => $this->assertModelExists($song));
|
||||||
|
@ -122,7 +120,7 @@ class SongTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function multipleUpdateNoCompilation(): void
|
public function multipleUpdateNoCompilation(): void
|
||||||
{
|
{
|
||||||
$songIds = Song::factory(3)->create()->pluck('id')->all();
|
$songIds = Song::factory(3)->create()->modelKeys();
|
||||||
|
|
||||||
$this->putAs('/api/songs', [
|
$this->putAs('/api/songs', [
|
||||||
'songs' => $songIds,
|
'songs' => $songIds,
|
||||||
|
@ -159,9 +157,8 @@ class SongTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function multipleUpdateCreatingNewAlbumsAndArtists(): void
|
public function multipleUpdateCreatingNewAlbumsAndArtists(): void
|
||||||
{
|
{
|
||||||
/** @var Collection<array-key, Song> $originalSongs */
|
|
||||||
$originalSongs = Song::factory(3)->create();
|
$originalSongs = Song::factory(3)->create();
|
||||||
$originalSongIds = $originalSongs->pluck('id')->all();
|
$originalSongIds = $originalSongs->modelKeys();
|
||||||
$originalAlbumNames = $originalSongs->pluck('album.name')->all();
|
$originalAlbumNames = $originalSongs->pluck('album.name')->all();
|
||||||
$originalAlbumIds = $originalSongs->pluck('album_id')->all();
|
$originalAlbumIds = $originalSongs->pluck('album_id')->all();
|
||||||
|
|
||||||
|
@ -177,7 +174,6 @@ class SongTest extends TestCase
|
||||||
], create_admin())
|
], create_admin())
|
||||||
->assertOk();
|
->assertOk();
|
||||||
|
|
||||||
/** @var Collection<array-key, Song> $songs */
|
|
||||||
$songs = Song::query()->whereIn('id', $originalSongIds)->get()->orderByArray($originalSongIds);
|
$songs = Song::query()->whereIn('id', $originalSongIds)->get()->orderByArray($originalSongIds);
|
||||||
|
|
||||||
// Even though the album name doesn't change, a new artist should have been created
|
// Even though the album name doesn't change, a new artist should have been created
|
||||||
|
@ -263,10 +259,7 @@ class SongTest extends TestCase
|
||||||
{
|
{
|
||||||
Song::factory(5)->create();
|
Song::factory(5)->create();
|
||||||
|
|
||||||
self::assertNotSame(0, Song::query()->count());
|
Song::deleteByChunk(Song::query()->get()->modelKeys(), 1);
|
||||||
$ids = Song::query()->select('id')->get()->pluck('id')->all();
|
|
||||||
|
|
||||||
Song::deleteByChunk($ids, 1);
|
|
||||||
|
|
||||||
self::assertSame(0, Song::query()->count());
|
self::assertSame(0, Song::query()->count());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@ class SongVisibilityTest extends TestCase
|
||||||
$owner = create_admin();
|
$owner = create_admin();
|
||||||
Song::factory(3)->create();
|
Song::factory(3)->create();
|
||||||
|
|
||||||
$this->putAs('api/songs/publicize', ['songs' => Song::query()->pluck('id')->all()], $owner)
|
$this->putAs('api/songs/publicize', ['songs' => Song::query()->get()->modelKeys()], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
|
|
||||||
$this->putAs('api/songs/privatize', ['songs' => Song::query()->pluck('id')->all()], $owner)
|
$this->putAs('api/songs/privatize', ['songs' => Song::query()->get()->modelKeys()], $owner)
|
||||||
->assertForbidden();
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ class UserTest extends TestCase
|
||||||
$admin = create_admin();
|
$admin = create_admin();
|
||||||
$user = create_admin(['password' => 'secret']);
|
$user = create_admin(['password' => 'secret']);
|
||||||
|
|
||||||
$this->putAs("api/user/$user->id", [
|
$this->putAs("api/user/{$user->id}", [
|
||||||
'name' => 'Foo',
|
'name' => 'Foo',
|
||||||
'email' => 'bar@baz.com',
|
'email' => 'bar@baz.com',
|
||||||
'password' => 'new-secret',
|
'password' => 'new-secret',
|
||||||
|
@ -72,7 +72,7 @@ class UserTest extends TestCase
|
||||||
{
|
{
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
|
|
||||||
$this->deleteAs("api/user/$user->id", [], create_admin());
|
$this->deleteAs("api/user/{$user->id}", [], create_admin());
|
||||||
self::assertModelMissing($user);
|
self::assertModelMissing($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class UserTest extends TestCase
|
||||||
{
|
{
|
||||||
$admin = create_admin();
|
$admin = create_admin();
|
||||||
|
|
||||||
$this->deleteAs("api/user/$admin->id", [], $admin)->assertForbidden();
|
$this->deleteAs("api/user/{$admin->id}", [], $admin)->assertForbidden();
|
||||||
self::assertModelExists($admin);
|
self::assertModelExists($admin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ class SmartPlaylistServiceTest extends PlusTestCase
|
||||||
]);
|
]);
|
||||||
|
|
||||||
self::assertEqualsCanonicalizing(
|
self::assertEqualsCanonicalizing(
|
||||||
$matches->pluck('id')->all(),
|
$matches->modelKeys(),
|
||||||
$this->service->getSongs($playlist, $owner)->pluck('id')->all()
|
$this->service->getSongs($playlist, $owner)->modelKeys()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,8 @@ class InteractionServiceTest extends TestCase
|
||||||
$songs->each(static function (Song $song) use ($user): void {
|
$songs->each(static function (Song $song) use ($user): void {
|
||||||
/** @var Interaction $interaction */
|
/** @var Interaction $interaction */
|
||||||
$interaction = Interaction::query()
|
$interaction = Interaction::query()
|
||||||
->where('song_id', $song->id)
|
->whereBelongsTo($song)
|
||||||
->where('user_id', $user->id)
|
->whereBelongsTo($user)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
self::assertTrue($interaction->liked);
|
self::assertTrue($interaction->liked);
|
||||||
|
@ -82,10 +82,9 @@ class InteractionServiceTest extends TestCase
|
||||||
Event::fake(MultipleSongsUnliked::class);
|
Event::fake(MultipleSongsUnliked::class);
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
|
|
||||||
/** @var Collection $interactions */
|
|
||||||
$interactions = Interaction::factory(3)->for($user)->create(['liked' => true]);
|
$interactions = Interaction::factory(3)->for($user)->create(['liked' => true]);
|
||||||
|
|
||||||
$this->interactionService->unlikeMany($interactions->map(static fn (Interaction $i) => $i->song), $user);
|
$this->interactionService->unlikeMany($interactions->map(static fn (Interaction $i) => $i->song), $user); // @phpstan-ignore-line
|
||||||
|
|
||||||
$interactions->each(static function (Interaction $interaction): void {
|
$interactions->each(static function (Interaction $interaction): void {
|
||||||
self::assertFalse($interaction->refresh()->liked);
|
self::assertFalse($interaction->refresh()->liked);
|
||||||
|
|
|
@ -8,7 +8,6 @@ use App\Models\Podcast;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use App\Services\PlaylistService;
|
use App\Services\PlaylistService;
|
||||||
use App\Values\SmartPlaylistRuleGroupCollection;
|
use App\Values\SmartPlaylistRuleGroupCollection;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use InvalidArgumentException as BaseInvalidArgumentException;
|
use InvalidArgumentException as BaseInvalidArgumentException;
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\PlusTestCase;
|
use Tests\PlusTestCase;
|
||||||
|
@ -43,17 +42,15 @@ class PlaylistServiceTest extends TestCase
|
||||||
#[Test]
|
#[Test]
|
||||||
public function createPlaylistWithSongs(): void
|
public function createPlaylistWithSongs(): void
|
||||||
{
|
{
|
||||||
/** @var Collection<array-key, Song> $songs */
|
|
||||||
$songs = Song::factory(3)->create();
|
$songs = Song::factory(3)->create();
|
||||||
|
|
||||||
$user = create_user();
|
$user = create_user();
|
||||||
|
|
||||||
$playlist = $this->service->createPlaylist('foo', $user, null, $songs->pluck('id')->all());
|
$playlist = $this->service->createPlaylist('foo', $user, null, $songs->modelKeys());
|
||||||
|
|
||||||
self::assertSame('foo', $playlist->name);
|
self::assertSame('foo', $playlist->name);
|
||||||
self::assertTrue($user->is($playlist->user));
|
self::assertTrue($user->is($playlist->user));
|
||||||
self::assertFalse($playlist->is_smart);
|
self::assertFalse($playlist->is_smart);
|
||||||
self::assertEqualsCanonicalizing($playlist->playables->pluck('id')->all(), $songs->pluck('id')->all());
|
self::assertEqualsCanonicalizing($playlist->playables->modelKeys(), $songs->modelKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -213,7 +210,7 @@ class PlaylistServiceTest extends TestCase
|
||||||
|
|
||||||
self::assertCount(2, $addedSongs);
|
self::assertCount(2, $addedSongs);
|
||||||
self::assertCount(5, $playlist->playables);
|
self::assertCount(5, $playlist->playables);
|
||||||
self::assertEqualsCanonicalizing($addedSongs->pluck('id')->all(), $songs->pluck('id')->all());
|
self::assertEqualsCanonicalizing($addedSongs->modelKeys(), $songs->modelKeys());
|
||||||
$songs->each(static fn (Song $song) => self::assertTrue($playlist->playables->contains($song)));
|
$songs->each(static fn (Song $song) => self::assertTrue($playlist->playables->contains($song)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +232,7 @@ class PlaylistServiceTest extends TestCase
|
||||||
|
|
||||||
self::assertCount(2, $addedEpisodes);
|
self::assertCount(2, $addedEpisodes);
|
||||||
self::assertCount(5, $playlist->playables);
|
self::assertCount(5, $playlist->playables);
|
||||||
self::assertEqualsCanonicalizing($addedEpisodes->pluck('id')->all(), $episodes->pluck('id')->all());
|
self::assertEqualsCanonicalizing($addedEpisodes->modelKeys(), $episodes->modelKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -252,7 +249,7 @@ class PlaylistServiceTest extends TestCase
|
||||||
|
|
||||||
self::assertCount(4, $addedEpisodes);
|
self::assertCount(4, $addedEpisodes);
|
||||||
self::assertCount(7, $playlist->playables);
|
self::assertCount(7, $playlist->playables);
|
||||||
self::assertEqualsCanonicalizing($addedEpisodes->pluck('id')->all(), $playables->pluck('id')->all());
|
self::assertEqualsCanonicalizing($addedEpisodes->modelKeys(), $playables->modelKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -292,23 +289,22 @@ class PlaylistServiceTest extends TestCase
|
||||||
/** @var Playlist $playlist */
|
/** @var Playlist $playlist */
|
||||||
$playlist = Playlist::factory()->create();
|
$playlist = Playlist::factory()->create();
|
||||||
|
|
||||||
/** @var Collection<array-key, Song> $songs */
|
|
||||||
$songs = Song::factory(4)->create();
|
$songs = Song::factory(4)->create();
|
||||||
$ids = $songs->pluck('id')->all();
|
$ids = $songs->modelKeys();
|
||||||
$playlist->addPlayables($songs);
|
$playlist->addPlayables($songs);
|
||||||
|
|
||||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[2], $ids[3]], $ids[0], 'after');
|
$this->service->movePlayablesInPlaylist($playlist, [$ids[2], $ids[3]], $ids[0], 'after');
|
||||||
self::assertSame([$ids[0], $ids[2], $ids[3], $ids[1]], $playlist->refresh()->playables->pluck('id')->all());
|
self::assertSame([$ids[0], $ids[2], $ids[3], $ids[1]], $playlist->refresh()->playables->modelKeys());
|
||||||
|
|
||||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[0]], $ids[3], 'before');
|
$this->service->movePlayablesInPlaylist($playlist, [$ids[0]], $ids[3], 'before');
|
||||||
self::assertSame([$ids[2], $ids[0], $ids[3], $ids[1]], $playlist->refresh()->playables->pluck('id')->all());
|
self::assertSame([$ids[2], $ids[0], $ids[3], $ids[1]], $playlist->refresh()->playables->modelKeys());
|
||||||
|
|
||||||
// move to the first position
|
// move to the first position
|
||||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[0], $ids[1]], $ids[2], 'before');
|
$this->service->movePlayablesInPlaylist($playlist, [$ids[0], $ids[1]], $ids[2], 'before');
|
||||||
self::assertSame([$ids[0], $ids[1], $ids[2], $ids[3]], $playlist->refresh()->playables->pluck('id')->all());
|
self::assertSame([$ids[0], $ids[1], $ids[2], $ids[3]], $playlist->refresh()->playables->modelKeys());
|
||||||
|
|
||||||
// move to the last position
|
// move to the last position
|
||||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[0], $ids[1]], $ids[3], 'after');
|
$this->service->movePlayablesInPlaylist($playlist, [$ids[0], $ids[1]], $ids[3], 'after');
|
||||||
self::assertSame([$ids[2], $ids[3], $ids[0], $ids[1]], $playlist->refresh()->playables->pluck('id')->all());
|
self::assertSame([$ids[2], $ids[3], $ids[0], $ids[1]], $playlist->refresh()->playables->modelKeys());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,11 +49,11 @@ class QueueServiceTest extends TestCase
|
||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$songIds = Song::factory()->count(3)->create()->pluck('id')->toArray();
|
$songIds = Song::factory()->count(3)->create()->modelKeys();
|
||||||
$this->service->updateQueueState($user, $songIds);
|
$this->service->updateQueueState($user, $songIds);
|
||||||
|
|
||||||
/** @var QueueState $queueState */
|
/** @var QueueState $queueState */
|
||||||
$queueState = QueueState::query()->where('user_id', $user->id)->firstOrFail();
|
$queueState = QueueState::query()->whereBelongsTo($user)->firstOrFail();
|
||||||
self::assertEqualsCanonicalizing($songIds, $queueState->song_ids);
|
self::assertEqualsCanonicalizing($songIds, $queueState->song_ids);
|
||||||
self::assertNull($queueState->current_song_id);
|
self::assertNull($queueState->current_song_id);
|
||||||
self::assertSame(0, $queueState->playback_position);
|
self::assertSame(0, $queueState->playback_position);
|
||||||
|
@ -65,7 +65,7 @@ class QueueServiceTest extends TestCase
|
||||||
/** @var QueueState $state */
|
/** @var QueueState $state */
|
||||||
$state = QueueState::factory()->create();
|
$state = QueueState::factory()->create();
|
||||||
|
|
||||||
$songIds = Song::factory()->count(3)->create()->pluck('id')->toArray();
|
$songIds = Song::factory()->count(3)->create()->modelKeys();
|
||||||
$this->service->updateQueueState($state->user, $songIds);
|
$this->service->updateQueueState($state->user, $songIds);
|
||||||
|
|
||||||
$state->refresh();
|
$state->refresh();
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Models\Playlist;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\SmartPlaylistService;
|
use App\Services\SmartPlaylistService;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
@ -564,8 +564,8 @@ class SmartPlaylistServiceTest extends TestCase
|
||||||
$playlist = Playlist::factory()->for($owner ?? create_admin())->create(['rules' => $rules]);
|
$playlist = Playlist::factory()->for($owner ?? create_admin())->create(['rules' => $rules]);
|
||||||
|
|
||||||
self::assertEqualsCanonicalizing(
|
self::assertEqualsCanonicalizing(
|
||||||
$matches->pluck('id')->all(),
|
$matches->modelKeys(),
|
||||||
$this->service->getSongs($playlist)->pluck('id')->all()
|
$this->service->getSongs($playlist)->modelKeys()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class EpisodePlayableTest extends TestCase
|
||||||
Http::assertSentCount(1);
|
Http::assertSentCount(1);
|
||||||
self::assertSame('acbd18db4cc2f85cedef654fccc4a4d8', $playable->checksum);
|
self::assertSame('acbd18db4cc2f85cedef654fccc4a4d8', $playable->checksum);
|
||||||
|
|
||||||
self::assertTrue(Cache::has("episode-playable.$episode->id"));
|
self::assertTrue(Cache::has("episode-playable.{$episode->id}"));
|
||||||
|
|
||||||
$retrieved = EpisodePlayable::getForEpisode($episode);
|
$retrieved = EpisodePlayable::getForEpisode($episode);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class AlbumTest extends TestCase
|
||||||
$artist = Artist::factory()->create();
|
$artist = Artist::factory()->create();
|
||||||
$name = 'Foo';
|
$name = 'Foo';
|
||||||
|
|
||||||
self::assertNull(Album::query()->where('artist_id', $artist->id)->where('name', $name)->first());
|
self::assertNull(Album::query()->whereBelongsTo($artist)->where('name', $name)->first());
|
||||||
|
|
||||||
$album = Album::getOrCreate($artist, $name);
|
$album = Album::getOrCreate($artist, $name);
|
||||||
self::assertSame('Foo', $album->name);
|
self::assertSame('Foo', $album->name);
|
||||||
|
|
|
@ -49,7 +49,7 @@ class MediaInformationServiceTest extends TestCase
|
||||||
->shouldNotReceive('tryDownloadAlbumCover');
|
->shouldNotReceive('tryDownloadAlbumCover');
|
||||||
|
|
||||||
self::assertSame($info, $this->mediaInformationService->getAlbumInformation($album));
|
self::assertSame($info, $this->mediaInformationService->getAlbumInformation($album));
|
||||||
self::assertNotNull(cache()->get('album.info.' . $album->id));
|
self::assertNotNull(cache()->get("album.info.{$album->id}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -93,7 +93,7 @@ class MediaInformationServiceTest extends TestCase
|
||||||
->shouldNotReceive('tryDownloadArtistImage');
|
->shouldNotReceive('tryDownloadArtistImage');
|
||||||
|
|
||||||
self::assertSame($info, $this->mediaInformationService->getArtistInformation($artist));
|
self::assertSame($info, $this->mediaInformationService->getArtistInformation($artist));
|
||||||
self::assertNotNull(cache()->get('artist.info.' . $artist->id));
|
self::assertNotNull(cache()->get("artist.info.{$artist->id}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Tests\Unit\Services;
|
||||||
use App\Models\Playlist;
|
use App\Models\Playlist;
|
||||||
use App\Models\PlaylistFolder;
|
use App\Models\PlaylistFolder;
|
||||||
use App\Services\PlaylistFolderService;
|
use App\Services\PlaylistFolderService;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class PlaylistFolderServiceTest extends TestCase
|
||||||
/** @var PlaylistFolder $folder */
|
/** @var PlaylistFolder $folder */
|
||||||
$folder = PlaylistFolder::factory()->for($user)->create();
|
$folder = PlaylistFolder::factory()->for($user)->create();
|
||||||
|
|
||||||
$this->service->addPlaylistsToFolder($folder, $playlists->pluck('id')->all());
|
$this->service->addPlaylistsToFolder($folder, $playlists->modelKeys());
|
||||||
|
|
||||||
self::assertCount(3, $folder->playlists);
|
self::assertCount(3, $folder->playlists);
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,9 @@ class PlaylistFolderServiceTest extends TestCase
|
||||||
|
|
||||||
/** @var Collection<array-key, Playlist> $playlists */
|
/** @var Collection<array-key, Playlist> $playlists */
|
||||||
$playlists = Playlist::factory()->count(3)->create();
|
$playlists = Playlist::factory()->count(3)->create();
|
||||||
$folder->playlists()->attach($playlists->pluck('id')->all());
|
$folder->playlists()->attach($playlists);
|
||||||
|
|
||||||
$this->service->movePlaylistsToRootLevel($folder, $playlists->pluck('id')->all());
|
$this->service->movePlaylistsToRootLevel($folder, $playlists->modelKeys());
|
||||||
|
|
||||||
self::assertCount(0, $folder->playlists);
|
self::assertCount(0, $folder->playlists);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue