fix(build): fixing build errors

This commit is contained in:
Phan An 2024-07-07 15:29:37 +02:00
parent 781af8dc27
commit e3086422c7
14 changed files with 40 additions and 39 deletions

View file

@ -8,12 +8,15 @@ use App\Models\Song;
use App\Repositories\SongRepository; use App\Repositories\SongRepository;
use App\Services\DownloadService; use App\Services\DownloadService;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Support\Collection;
class DownloadSongsController extends Controller class DownloadSongsController extends Controller
{ {
public function __invoke(DownloadSongsRequest $request, DownloadService $service, SongRepository $repository) public function __invoke(DownloadSongsRequest $request, DownloadService $service, SongRepository $repository)
{ {
// Don't use SongRepository::findMany() because it'd have been already catered to the current user. // Don't use SongRepository::findMany() because it'd have been already catered to the current user.
/** @var Array<Song>|Collection<array-key, Song> $songs */
$songs = Song::query()->findMany($request->songs); $songs = Song::query()->findMany($request->songs);
$songs->each(fn ($song) => $this->authorize('download', $song)); $songs->each(fn ($song) => $this->authorize('download', $song));

View file

@ -18,7 +18,7 @@ use PhanAn\Poddle\Values\CategoryCollection;
use PhanAn\Poddle\Values\ChannelMetadata; use PhanAn\Poddle\Values\ChannelMetadata;
/** /**
* @property-read string $id * @property string $id
* @property string $url * @property string $url
* @property string $title * @property string $title
* @property string $description * @property string $description

View file

@ -17,6 +17,7 @@ use App\Values\SongStorageMetadata\S3LambdaMetadata;
use App\Values\SongStorageMetadata\SftpMetadata; use App\Values\SongStorageMetadata\SftpMetadata;
use App\Values\SongStorageMetadata\SongStorageMetadata; use App\Values\SongStorageMetadata\SongStorageMetadata;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -31,7 +32,7 @@ use Throwable;
/** /**
* @property string $path * @property string $path
* @property string $title * @property string $title
* @property Album $album * @property ?Album $album
* @property User $uploader * @property User $uploader
* @property ?Artist $artist * @property ?Artist $artist
* @property ?Artist $album_artist * @property ?Artist $album_artist
@ -105,13 +106,12 @@ class Song extends Model
public static function query(?PlayableType $type = null, ?User $user = null): SongBuilder public static function query(?PlayableType $type = null, ?User $user = null): SongBuilder
{ {
return parent::query() return parent::query()
->when($type, static function (SongBuilder $query) use ($type): void { ->when($type, static fn (Builder $query) => match ($type) { // @phpstan-ignore-line phpcs:ignore
match ($type) { PlayableType::SONG => $query->whereNull('songs.podcast_id'),
PlayableType::SONG => $query->whereNull('songs.podcast_id'), PlayableType::PODCAST_EPISODE => $query->whereNotNull('songs.podcast_id'),
PlayableType::PODCAST_EPISODE => $query->whereNotNull('songs.podcast_id'), default => $query,
};
}) })
->when($user, static fn (SongBuilder $query) => $query->forUser($user)); ->when($user, static fn (SongBuilder $query) => $query->forUser($user)); // @phpstan-ignore-line
} }
public function owner(): BelongsTo public function owner(): BelongsTo

View file

@ -1,14 +0,0 @@
<?php
namespace App\Policies;
use App\Models\Podcast\Song;
use App\Models\User;
class EpisodePolicy
{
public function access(User $user, Song $episode): bool
{
return $user->subscribedToPodcast($episode->podcast);
}
}

View file

@ -21,8 +21,9 @@ use Throwable;
class LicenseService implements LicenseServiceInterface class LicenseService implements LicenseServiceInterface
{ {
public function __construct(private readonly LemonSqueezyConnector $connector, private readonly string $hashSalt) public function __construct(private readonly LemonSqueezyConnector $connector, private ?string $hashSalt = null)
{ {
$this->hashSalt ??= config('app.key');
} }
public function activate(string $key): License public function activate(string $key): License

View file

@ -13,6 +13,7 @@ use App\Repositories\SongRepository;
use Carbon\Carbon; use Carbon\Carbon;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\RedirectMiddleware; use GuzzleHttp\RedirectMiddleware;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
@ -56,6 +57,7 @@ class PodcastService
$channel = $parser->getChannel(); $channel = $parser->getChannel();
return DB::transaction(function () use ($url, $podcast, $parser, $channel, $user) { return DB::transaction(function () use ($url, $podcast, $parser, $channel, $user) {
/** @var Podcast $podcast */
$podcast = Podcast::query()->create([ $podcast = Podcast::query()->create([
'url' => $url, 'url' => $url,
'title' => $channel->title, 'title' => $channel->title,
@ -102,8 +104,8 @@ class PodcastService
'last_synced_at' => now(), 'last_synced_at' => now(),
]); ]);
$pubDate = $parser->xmlReader->value('rss.channel.pubDate')?->first() $pubDate = $parser->xmlReader->value('rss.channel.pubDate')->first()
?? $parser->xmlReader->value('rss.channel.lastBuildDate')?->first(); ?? $parser->xmlReader->value('rss.channel.lastBuildDate')->first();
if ($pubDate && Carbon::createFromFormat(Carbon::RFC1123, $pubDate)->isBefore($podcast->last_synced_at)) { if ($pubDate && Carbon::createFromFormat(Carbon::RFC1123, $pubDate)->isBefore($podcast->last_synced_at)) {
// The pubDate/lastBuildDate value indicates that there's no new content since last check. // The pubDate/lastBuildDate value indicates that there's no new content since last check.
@ -150,7 +152,7 @@ class PodcastService
// Since insert() doesn't trigger model events, Scout operations will not be called. // Since insert() doesn't trigger model events, Scout operations will not be called.
// We have to manually update the search index. // We have to manually update the search index.
Episode::query()->whereIn('id', $ids)->searchable(); Episode::query()->whereIn('id', $ids)->searchable(); // @phpstan-ignore-line
} }
private function subscribeUserToPodcast(User $user, Podcast $podcast): void private function subscribeUserToPodcast(User $user, Podcast $podcast): void
@ -206,16 +208,16 @@ class PodcastService
$url = $url->path; $url = $url->path;
} }
$client ??= $this->client ?? new Client(); $client ??= new Client();
try { try {
$response = $client->request($method, $url, [ $response = $client->request($method, $url, [
'headers' => [ RequestOptions::HEADERS => [
'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15', // @phpcs-ignore-line 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15', // @phpcs-ignore-line
'Origin' => '*', 'Origin' => '*',
], ],
'http_errors' => false, RequestOptions::HTTP_ERRORS => false,
'allow_redirects' => ['track_redirects' => true], RequestOptions::ALLOW_REDIRECTS => ['track_redirects' => true],
]); ]);
$redirects = Arr::wrap($response->getHeader(RedirectMiddleware::HISTORY_HEADER)); $redirects = Arr::wrap($response->getHeader(RedirectMiddleware::HISTORY_HEADER));

View file

@ -52,7 +52,7 @@ class SearchService
{ {
try { try {
return $repository->getMany( return $repository->getMany(
ids: $repository->model::search($keywords)->get()->take($count)->pluck('id')->all(), ids: $repository->model::search($keywords)->get()->take($count)->pluck('id')->all(), // @phpstan-ignore-line
preserveOrder: true, preserveOrder: true,
); );
} catch (Throwable $e) { } catch (Throwable $e) {

View file

@ -41,7 +41,7 @@ class SongService
return collect($ids)->reduce(function (Collection $updated, string $id) use ($data): Collection { return collect($ids)->reduce(function (Collection $updated, string $id) use ($data): Collection {
optional( optional(
Song::query()->with('album.artist')->find($id), Song::query()->with('album.artist')->find($id),
fn (Song $song) => $updated->push($this->updateSong($song, clone $data)) fn (Song $song) => $updated->push($this->updateSong($song, clone $data)) // @phpstan-ignore-line
); );
return $updated; return $updated;

View file

@ -29,6 +29,7 @@ parameters:
- '#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\(\)#'
excludePaths: excludePaths:

View file

@ -1,7 +1,5 @@
<?php <?php
use Illuminate\Support\Facades\Broadcast;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Broadcast Channels | Broadcast Channels
@ -12,4 +10,3 @@ use Illuminate\Support\Facades\Broadcast;
| used to check if an authenticated user can listen to the channel. | used to check if an authenticated user can listen to the channel.
| |
*/ */
Broadcast::channel('App.User.{id}', static fn ($user, $id) => (int) $user->id === (int) $id);

View file

@ -28,7 +28,9 @@ class ExcerptSearchTest extends TestCase
Album::factory(4)->create(); Album::factory(4)->create();
$user = create_user(); $user = create_user();
$user->subscribeToPodcast(Podcast::factory()->create(['title' => 'Foo Podcast'])); /** @var Podcast $podcast */
$podcast = Podcast::factory()->create(['title' => 'Foo Podcast']);
$user->subscribeToPodcast($podcast);
$this->getAs('api/search?q=foo', $user) $this->getAs('api/search?q=foo', $user)
->assertJsonStructure([ ->assertJsonStructure([

View file

@ -212,6 +212,7 @@ class PlaylistServiceTest extends TestCase
$playlist = Playlist::factory()->create(); $playlist = Playlist::factory()->create();
$playlist->addPlayables(Song::factory(3)->create()); $playlist->addPlayables(Song::factory(3)->create());
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create(); $podcast = Podcast::factory()->create();
$episodes = Song::factory(2)->asEpisode()->for($podcast)->create(); $episodes = Song::factory(2)->asEpisode()->for($podcast)->create();

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Integration\Services; namespace Tests\Integration\Services;
use App\Exceptions\UserAlreadySubscribedToPodcast; use App\Exceptions\UserAlreadySubscribedToPodcast;
use App\Models\Podcast; use App\Models\Podcast;
@ -8,11 +8,11 @@ use App\Models\PodcastUserPivot;
use App\Models\Song; use App\Models\Song;
use App\Services\PodcastService; use App\Services\PodcastService;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack; use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Response;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Psr\Http\Client\ClientInterface;
use Tests\TestCase; use Tests\TestCase;
use function Tests\create_user; use function Tests\create_user;
@ -59,6 +59,7 @@ class PodcastServiceTest extends TestCase
public function testSubscribeUserToPodcast(): void public function testSubscribeUserToPodcast(): void
{ {
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create([ $podcast = Podcast::factory()->create([
'url' => 'https://example.com/feed.xml', 'url' => 'https://example.com/feed.xml',
'title' => 'My Cool Podcast', 'title' => 'My Cool Podcast',
@ -79,6 +80,7 @@ class PodcastServiceTest extends TestCase
{ {
self::expectException(UserAlreadySubscribedToPodcast::class); self::expectException(UserAlreadySubscribedToPodcast::class);
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create([ $podcast = Podcast::factory()->create([
'url' => 'https://example.com/feed.xml', 'url' => 'https://example.com/feed.xml',
]); ]);
@ -97,6 +99,7 @@ class PodcastServiceTest extends TestCase
'https://example.com/feed.xml' => Http::response(headers: ['Last-Modified' => now()->toRfc1123String()]), 'https://example.com/feed.xml' => Http::response(headers: ['Last-Modified' => now()->toRfc1123String()]),
]); ]);
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create([ $podcast = Podcast::factory()->create([
'url' => 'https://example.com/feed.xml', 'url' => 'https://example.com/feed.xml',
'title' => 'Shall be changed very sad', 'title' => 'Shall be changed very sad',
@ -116,6 +119,7 @@ class PodcastServiceTest extends TestCase
public function testUnsubscribeUserFromPodcast(): void public function testUnsubscribeUserFromPodcast(): void
{ {
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create(); $podcast = Podcast::factory()->create();
$user = create_user(); $user = create_user();
$user->subscribeToPodcast($podcast); $user->subscribeToPodcast($podcast);
@ -127,6 +131,7 @@ class PodcastServiceTest extends TestCase
public function testPodcastNotObsoleteIfSyncedRecently(): void public function testPodcastNotObsoleteIfSyncedRecently(): void
{ {
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create([ $podcast = Podcast::factory()->create([
'last_synced_at' => now()->subHours(6), 'last_synced_at' => now()->subHours(6),
]); ]);
@ -140,6 +145,7 @@ class PodcastServiceTest extends TestCase
'https://example.com/feed.xml' => Http::response(headers: ['Last-Modified' => now()->toRfc1123String()]), 'https://example.com/feed.xml' => Http::response(headers: ['Last-Modified' => now()->toRfc1123String()]),
]); ]);
/** @var Podcast $podcast */
$podcast = Podcast::factory()->create([ $podcast = Podcast::factory()->create([
'url' => 'https://example.com/feed.xml', 'url' => 'https://example.com/feed.xml',
'last_synced_at' => now()->subDays(1), 'last_synced_at' => now()->subDays(1),
@ -150,6 +156,7 @@ class PodcastServiceTest extends TestCase
public function testUpdateEpisodeProgress(): void public function testUpdateEpisodeProgress(): void
{ {
/** @var Song $episode */
$episode = Song::factory()->asEpisode()->create(); $episode = Song::factory()->asEpisode()->create();
$user = create_user(); $user = create_user();
$user->subscribeToPodcast($episode->podcast); $user->subscribeToPodcast($episode->podcast);

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Integration\Values; namespace Tests\Integration\Values;
use App\Models\Song; use App\Models\Song;
use App\Values\Podcast\EpisodePlayable; use App\Values\Podcast\EpisodePlayable;
@ -16,6 +16,7 @@ class EpisodePlayableTest extends TestCase
'https://example.com/episode.mp3' => Http::response('foo'), 'https://example.com/episode.mp3' => Http::response('foo'),
]); ]);
/** @var Song $episode */
$episode = Song::factory()->asEpisode()->create([ $episode = Song::factory()->asEpisode()->create([
'path' => 'https://example.com/episode.mp3', 'path' => 'https://example.com/episode.mp3',
]); ]);