mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
Add a UserPreferenceService
This commit is contained in:
parent
0f9bb32956
commit
373870fefb
19 changed files with 320 additions and 216 deletions
|
@ -13,9 +13,9 @@ class SongLikeToggled extends Event
|
|||
public $interaction;
|
||||
public $user;
|
||||
|
||||
public function __construct(Interaction $interaction, User $user = null)
|
||||
public function __construct(Interaction $interaction, User $user)
|
||||
{
|
||||
$this->interaction = $interaction;
|
||||
$this->user = $user ?: auth()->user();
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,11 @@ class LastfmController extends Controller
|
|||
private $lastfmService;
|
||||
private $jwtAuth;
|
||||
|
||||
public function __construct(Guard $auth, LastfmService $lastfmService, JWTAuth $jwtAuth)
|
||||
public function __construct(
|
||||
Guard $auth,
|
||||
LastfmService $lastfmService,
|
||||
JWTAuth $jwtAuth
|
||||
)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->lastfmService = $lastfmService;
|
||||
|
@ -54,11 +58,11 @@ class LastfmController extends Controller
|
|||
*/
|
||||
public function callback(LastfmCallbackRequest $request)
|
||||
{
|
||||
$sessionKey = $this->lastfmService->getSessionKey($request->token);
|
||||
$sessionKey = $this->lastfmService->fetchSessionKeyUsingToken($request->token);
|
||||
|
||||
abort_unless($sessionKey, 500, 'Invalid token key.');
|
||||
|
||||
$this->auth->user()->savePreference('lastfm_session_key', $sessionKey);
|
||||
$this->lastfmService->setUserSessionKey($this->auth->user(), $sessionKey);
|
||||
|
||||
return view('api.lastfm.callback');
|
||||
}
|
||||
|
@ -72,7 +76,7 @@ class LastfmController extends Controller
|
|||
*/
|
||||
public function setSessionKey(LastfmSetSessionKeyRequest $request)
|
||||
{
|
||||
$this->auth->user()->savePreference('lastfm_session_key', trim($request->key));
|
||||
$this->lastfmService->setUserSessionKey($this->auth->user(), $request->key);
|
||||
|
||||
return response()->json();
|
||||
}
|
||||
|
@ -84,7 +88,7 @@ class LastfmController extends Controller
|
|||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->auth->user()->deletePreference('lastfm_session_key');
|
||||
$this->lastfmService->deleteUserSessionKey($this->auth->user());
|
||||
|
||||
return response()->json();
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@ class ScrobbleController extends Controller
|
|||
*/
|
||||
public function store(Request $request, Song $song, string $timestamp)
|
||||
{
|
||||
if (!$song->artist->is_unknown && $request->user()->connectedToLastfm()) {
|
||||
if (!$song->artist->is_unknown && $this->lastfmService->isUserConnected($request->user())) {
|
||||
$this->lastfmService->scrobble(
|
||||
$song->artist->name,
|
||||
$song->title,
|
||||
(int) $timestamp,
|
||||
$song->album->name === Album::UNKNOWN_NAME ? '' : $song->album->name,
|
||||
$request->user()->lastfm_session_key
|
||||
$this->lastfmService->getUserSessionKey($request->user())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,18 +16,22 @@ class LoveTrackOnLastfm
|
|||
|
||||
public function handle(SongLikeToggled $event): void
|
||||
{
|
||||
if (!$this->lastfm->enabled() ||
|
||||
!($sessionKey = $event->user->lastfm_session_key) ||
|
||||
$event->interaction->song->album->artist->is_unknown
|
||||
) {
|
||||
if (!$this->shouldHandle($event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->lastfm->toggleLoveTrack(
|
||||
$event->interaction->song->title,
|
||||
$event->interaction->song->album->artist->name,
|
||||
$sessionKey,
|
||||
$event->interaction->song->artist->name,
|
||||
$this->lastfm->getUserSessionKey($event->user),
|
||||
$event->interaction->liked
|
||||
);
|
||||
}
|
||||
|
||||
private function shouldHandle(SongLikeToggled $event): bool
|
||||
{
|
||||
return $this->lastfm->enabled()
|
||||
&& $this->lastfm->isUserConnected($event->user)
|
||||
&& !$event->interaction->song->artist->is_unknown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@ class UpdateLastfmNowPlaying
|
|||
|
||||
public function handle(SongStartedPlaying $event): void
|
||||
{
|
||||
if (!$this->lastfm->enabled() ||
|
||||
!($sessionKey = $event->user->lastfm_session_key) ||
|
||||
$event->song->artist->is_unknown
|
||||
) {
|
||||
if (!$this->shouldHandle($event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -29,7 +26,14 @@ class UpdateLastfmNowPlaying
|
|||
$event->song->title,
|
||||
$event->song->album->name === Album::UNKNOWN_NAME ? '' : $event->song->album->name,
|
||||
$event->song->length,
|
||||
$sessionKey
|
||||
$this->lastfm->getUserSessionKey($event->user)
|
||||
);
|
||||
}
|
||||
|
||||
private function shouldHandle(SongStartedPlaying $event): bool
|
||||
{
|
||||
return $this->lastfm->enabled()
|
||||
&& $this->lastfm->isUserConnected($event->user)
|
||||
&& !$event->song->artist->is_unknown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Services\LastfmService;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
@ -10,7 +11,6 @@ use Illuminate\Notifications\Notifiable;
|
|||
* @property array $preferences
|
||||
* @property int $id
|
||||
* @property bool $is_admin
|
||||
* @property string $lastfm_session_key
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ class User extends Authenticatable
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
private const HIDDEN_PREFERENCES = ['lastfm_session_key'];
|
||||
private const HIDDEN_PREFERENCES = [LastfmService::SESSION_KEY_PREFERENCE_KEY];
|
||||
|
||||
protected $guarded = ['id'];
|
||||
protected $casts = [
|
||||
|
@ -40,66 +40,6 @@ class User extends Authenticatable
|
|||
return $this->hasMany(Interaction::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getPreference(string $key)
|
||||
{
|
||||
// We can't use $this->preferences directly, since the data has been tampered
|
||||
// by getPreferencesAttribute().
|
||||
return array_get((array) unserialize($this->attributes['preferences']), $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function savePreference(string $key, $val): void
|
||||
{
|
||||
$preferences = $this->preferences;
|
||||
$preferences[$key] = $val;
|
||||
$this->preferences = $preferences;
|
||||
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* An alias to savePreference().
|
||||
*
|
||||
* @param mixed $val
|
||||
*
|
||||
* @see self::savePreference
|
||||
*/
|
||||
public function setPreference(string $key, $val): void
|
||||
{
|
||||
$this->savePreference($key, $val);
|
||||
}
|
||||
|
||||
public function deletePreference(string $key): void
|
||||
{
|
||||
$preferences = $this->preferences;
|
||||
array_forget($preferences, $key);
|
||||
|
||||
$this->update(compact('preferences'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is connected to Last.fm.
|
||||
*/
|
||||
public function connectedToLastfm(): bool
|
||||
{
|
||||
return (bool) $this->lastfm_session_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's Last.fm session key.
|
||||
*
|
||||
* @return string|null The key if found, or null if user isn't connected to Last.fm
|
||||
*/
|
||||
public function getLastfmSessionKeyAttribute(): ?string
|
||||
{
|
||||
return $this->getPreference('lastfm_session_key');
|
||||
}
|
||||
|
||||
/**
|
||||
* User preferences are stored as a serialized associative array.
|
||||
*
|
||||
|
|
|
@ -70,9 +70,9 @@ abstract class ApiClient
|
|||
return $body;
|
||||
} catch (ClientException $e) {
|
||||
$this->logger->error($e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,11 +45,11 @@ class InteractionService
|
|||
return tap($this->interaction->firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), static function (Interaction $interaction): void {
|
||||
]), static function (Interaction $interaction) use ($user): void {
|
||||
$interaction->liked = !$interaction->liked;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
event(new SongLikeToggled($interaction, $user));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ class InteractionService
|
|||
return tap($this->interaction->firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), static function (Interaction $interaction): void {
|
||||
]), static function (Interaction $interaction) use ($user): void {
|
||||
if (!$interaction->exists) {
|
||||
$interaction->play_count = 0;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class InteractionService
|
|||
$interaction->liked = true;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
event(new SongLikeToggled($interaction, $user));
|
||||
});
|
||||
})->all();
|
||||
}
|
||||
|
@ -90,11 +90,11 @@ class InteractionService
|
|||
->whereIn('song_id', $songIds)
|
||||
->where('user_id', $user->id)
|
||||
->get()
|
||||
->each(static function (Interaction $interaction): void {
|
||||
->each(static function (Interaction $interaction) use ($user): void {
|
||||
$interaction->liked = false;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
event(new SongLikeToggled($interaction, $user));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||
use Illuminate\Log\Logger;
|
||||
|
||||
class LastfmService extends ApiClient implements ApiConsumerInterface
|
||||
{
|
||||
public const SESSION_KEY_PREFERENCE_KEY = 'lastfm_session_key';
|
||||
|
||||
/**
|
||||
* Specify the response format, since Last.fm only returns XML.
|
||||
*
|
||||
|
@ -20,6 +26,19 @@ class LastfmService extends ApiClient implements ApiConsumerInterface
|
|||
*/
|
||||
protected $keyParam = 'api_key';
|
||||
|
||||
private $userPreferenceService;
|
||||
|
||||
public function __construct(
|
||||
Client $client,
|
||||
Cache $cache,
|
||||
Logger $logger,
|
||||
UserPreferenceService $userPreferenceService
|
||||
)
|
||||
{
|
||||
parent::__construct($client, $cache, $logger);
|
||||
$this->userPreferenceService = $userPreferenceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if our application is using Last.fm.
|
||||
*/
|
||||
|
@ -167,7 +186,7 @@ class LastfmService extends ApiClient implements ApiConsumerInterface
|
|||
*
|
||||
* @link http://www.last.fm/api/webauth#4
|
||||
*/
|
||||
public function getSessionKey(string $token): ?string
|
||||
public function fetchSessionKeyUsingToken(string $token): ?string
|
||||
{
|
||||
$query = $this->buildAuthCallParams([
|
||||
'method' => 'auth.getSession',
|
||||
|
@ -307,6 +326,26 @@ class LastfmService extends ApiClient implements ApiConsumerInterface
|
|||
return trim(str_replace('Read more on Last.fm', '', nl2br(strip_tags(html_entity_decode($str)))));
|
||||
}
|
||||
|
||||
public function getUserSessionKey(User $user): ?string
|
||||
{
|
||||
return $this->userPreferenceService->get($user, self::SESSION_KEY_PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
public function setUserSessionKey(User $user, string $sessionKey): void
|
||||
{
|
||||
$this->userPreferenceService->set($user, self::SESSION_KEY_PREFERENCE_KEY, $sessionKey);
|
||||
}
|
||||
|
||||
public function deleteUserSessionKey(User $user): void
|
||||
{
|
||||
$this->userPreferenceService->delete($user, self::SESSION_KEY_PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
public function isUserConnected(User $user): bool
|
||||
{
|
||||
return (bool) $this->getUserSessionKey($user);
|
||||
}
|
||||
|
||||
public function getKey(): ?string
|
||||
{
|
||||
return config('koel.lastfm.key');
|
||||
|
|
36
app/Services/UserPreferenceService.php
Normal file
36
app/Services/UserPreferenceService.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class UserPreferenceService
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(User $user, string $key)
|
||||
{
|
||||
return array_get((array) unserialize($user->getOriginal('preferences')), $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function set(User $user, string $key, $val): void
|
||||
{
|
||||
$preferences = $user->preferences;
|
||||
$preferences[$key] = $val;
|
||||
$user->preferences = $preferences;
|
||||
|
||||
$user->save();
|
||||
}
|
||||
|
||||
public function delete(User $user, string $key): void
|
||||
{
|
||||
$preferences = $user->preferences;
|
||||
array_forget($preferences, $key);
|
||||
|
||||
$user->update(compact('preferences'));
|
||||
}
|
||||
}
|
|
@ -4,34 +4,33 @@ namespace Tests\Feature;
|
|||
|
||||
use App\Models\User;
|
||||
use App\Services\LastfmService;
|
||||
use App\Services\UserPreferenceService;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||
use Illuminate\Log\Logger;
|
||||
use Mockery;
|
||||
use Tymon\JWTAuth\JWTAuth;
|
||||
|
||||
class LastfmTest extends TestCase
|
||||
{
|
||||
public function testGetSessionKey(): void
|
||||
{
|
||||
/** @var Client $client */
|
||||
$client = Mockery::mock(Client::class, [
|
||||
'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/lastfm/session-key.xml')),
|
||||
]);
|
||||
/** @var UserPreferenceService */
|
||||
private $userPreferenceService;
|
||||
|
||||
$service = new LastfmService($client, app(Cache::class), app(Logger::class));
|
||||
self::assertEquals('foo', $service->getSessionKey('bar'));
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->userPreferenceService = app(UserPreferenceService::class);
|
||||
}
|
||||
|
||||
public function testSetSessionKey(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create();
|
||||
$this->postAsUser('api/lastfm/session-key', ['key' => 'foo'], $user)
|
||||
->assertResponseOk();
|
||||
|
||||
$user = User::find($user->id);
|
||||
self::assertEquals('foo', $user->lastfm_session_key);
|
||||
$user->refresh();
|
||||
|
||||
self::assertEquals('foo', app(LastfmService::class)->getUserSessionKey($user));
|
||||
}
|
||||
|
||||
public function testConnectToLastfm(): void
|
||||
|
@ -47,18 +46,19 @@ class LastfmTest extends TestCase
|
|||
|
||||
public function testRetrieveAndStoreSessionKey(): void
|
||||
{
|
||||
$lastfm = $this->mockIocDependency(LastfmService::class);
|
||||
$lastfm->shouldReceive('getSessionKey')
|
||||
->once()
|
||||
->with('foo')
|
||||
->andReturn('bar');
|
||||
/** @var Client $client */
|
||||
$client = Mockery::mock(Client::class, [
|
||||
'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/lastfm/session-key.xml')),
|
||||
]);
|
||||
|
||||
app()->instance(Client::class, $client);
|
||||
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create();
|
||||
$this->getAsUser('api/lastfm/callback?token=foo', $user);
|
||||
$user->refresh();
|
||||
|
||||
$this->assertEquals('bar', $user->lastfm_session_key);
|
||||
self::assertSame('foo', app(LastfmService::class)->getUserSessionKey($user));
|
||||
}
|
||||
|
||||
public function testDisconnectUser(): void
|
||||
|
@ -68,6 +68,6 @@ class LastfmTest extends TestCase
|
|||
$this->deleteAsUser('api/lastfm/disconnect', [], $user);
|
||||
$user->refresh();
|
||||
|
||||
$this->assertNull($user->lastfm_session_key);
|
||||
$this->assertNull(app(LastfmService::class)->getUserSessionKey($user));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,30 +5,26 @@ namespace Tests\Feature;
|
|||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\LastfmService;
|
||||
use Exception;
|
||||
use Mockery;
|
||||
|
||||
class ScrobbleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testLastfmScrobble()
|
||||
{
|
||||
$this->withoutEvents();
|
||||
$this->createSampleMediaSet();
|
||||
|
||||
$song = Song::first();
|
||||
/** @var User $user */
|
||||
$song = factory(Song::class)->create();
|
||||
$user = factory(User::class)->create();
|
||||
$user->setPreference('lastfm_session_key', 'foo');
|
||||
|
||||
$ts = time();
|
||||
|
||||
$this->mockIocDependency(LastfmService::class)
|
||||
->shouldReceive('scrobble')
|
||||
$lastfm = Mockery::mock(LastfmService::class)->makePartial();
|
||||
$lastfm->shouldReceive('enabled')->andReturn(true);
|
||||
$lastfm->shouldReceive('getUserSessionKey')->andReturn('foo');
|
||||
$lastfm->shouldReceive('scrobble')
|
||||
->with($song->album->artist->name, $song->title, $ts, $song->album->name, 'foo')
|
||||
->once();
|
||||
|
||||
app()->instance(LastfmService::class, $lastfm);
|
||||
|
||||
$this->postAsUser("/api/{$song->id}/scrobble/$ts", [], $user)
|
||||
->assertResponseOk();
|
||||
}
|
||||
|
|
|
@ -94,16 +94,4 @@ class UserTest extends TestCase
|
|||
->seeStatusCode(403)
|
||||
->seeInDatabase('users', ['id' => $admin->id]);
|
||||
}
|
||||
|
||||
public function testUpdateUserProfile()
|
||||
{
|
||||
$user = factory(User::class)->create();
|
||||
$this->assertNull($user->getPreference('foo'));
|
||||
|
||||
$user->setPreference('foo', 'bar');
|
||||
$this->assertEquals('bar', $user->getPreference('foo'));
|
||||
|
||||
$user->deletePreference('foo');
|
||||
$this->assertNull($user->getPreference('foo'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,33 +8,31 @@ use App\Models\Interaction;
|
|||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\LastfmService;
|
||||
use Exception;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
use Tests\Feature\TestCase;
|
||||
|
||||
class LoveTrackOnLastfmTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testHandle()
|
||||
{
|
||||
$this->withoutEvents();
|
||||
$this->createSampleMediaSet();
|
||||
|
||||
$user = factory(User::class)->create(['preferences' => ['lastfm_session_key' => 'bar']]);
|
||||
$user = factory(User::class)->create();
|
||||
$song = factory(Song::class)->create();
|
||||
|
||||
$interaction = Interaction::create([
|
||||
'user_id' => $user->id,
|
||||
'song_id' => Song::first()->id,
|
||||
'song_id' => $song->id,
|
||||
]);
|
||||
|
||||
/** @var LastfmService|MockInterface $lastfm */
|
||||
$lastfm = Mockery::mock(LastfmService::class, ['enabled' => true]);
|
||||
$lastfm = Mockery::mock(LastfmService::class);
|
||||
$lastfm->shouldReceive('enabled')->andReturn(true);
|
||||
$lastfm->shouldReceive('getUserSessionKey')->andReturn('foo');
|
||||
$lastfm->shouldReceive('isUserConnected')->andReturn(true);
|
||||
|
||||
$lastfm->shouldReceive('toggleLoveTrack')
|
||||
->once()
|
||||
->with($interaction->song->title, $interaction->song->album->artist->name, 'bar', false);
|
||||
->with($interaction->song->title, $interaction->song->album->artist->name, 'foo', false)
|
||||
->once();
|
||||
|
||||
(new LoveTrackOnLastfm($lastfm))->handle(new SongLikeToggled($interaction, $user));
|
||||
}
|
||||
|
|
|
@ -7,29 +7,26 @@ use App\Listeners\UpdateLastfmNowPlaying;
|
|||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\LastfmService;
|
||||
use Exception;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
use Tests\Feature\TestCase;
|
||||
|
||||
class UpdateLastfmNowPlayingTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateNowPlayingStatus()
|
||||
{
|
||||
$this->withoutEvents();
|
||||
$this->createSampleMediaSet();
|
||||
|
||||
$user = factory(User::class)->create(['preferences' => ['lastfm_session_key' => 'bar']]);
|
||||
$song = Song::first();
|
||||
$user = factory(User::class)->make();
|
||||
$song = factory(Song::class)->make();
|
||||
|
||||
/** @var LastfmService|MockInterface $lastfm */
|
||||
$lastfm = Mockery::mock(LastfmService::class, ['enabled' => true]);
|
||||
$lastfm = Mockery::mock(LastfmService::class);
|
||||
$lastfm->shouldReceive('enabled')->andReturn(true);
|
||||
$lastfm->shouldReceive('getUserSessionKey')->andReturn('foo');
|
||||
$lastfm->shouldReceive('isUserConnected')->andReturn(true);
|
||||
|
||||
$lastfm->shouldReceive('updateNowPlaying')
|
||||
->once()
|
||||
->with($song->album->artist->name, $song->title, $song->album->name, $song->length, 'bar');
|
||||
->with($song->album->artist->name, $song->title, $song->album->name, $song->length, 'foo');
|
||||
|
||||
(new UpdateLastfmNowPlaying($lastfm))->handle(new SongStartedPlaying($song, $user));
|
||||
}
|
||||
|
|
|
@ -7,65 +7,15 @@ use Tests\TestCase;
|
|||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function user_preferences_can_be_set()
|
||||
{
|
||||
// Given a user
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create();
|
||||
|
||||
// When I see the user's preference
|
||||
$user->setPreference('foo', 'bar');
|
||||
|
||||
// Then I see the preference properly set
|
||||
$this->assertArraySubset(['foo' => 'bar'], $user->preferences);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_preferences_can_be_retrieved()
|
||||
{
|
||||
// Given a user with some preferences
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => ['foo' => 'bar'],
|
||||
]);
|
||||
|
||||
// When I get a preference by its key
|
||||
$value = $user->getPreference('foo');
|
||||
|
||||
// Then I retrieve the preference value
|
||||
$this->assertEquals('bar', $value);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_preferences_can_be_deleted()
|
||||
{
|
||||
// Given a user with some preferences
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => ['foo' => 'bar'],
|
||||
]);
|
||||
|
||||
// When I delete the preference by its key
|
||||
$user->deletePreference('foo');
|
||||
|
||||
// Then I see the preference gets deleted
|
||||
$this->assertArrayNotHasKey('foo', $user->preferences);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sensitive_preferences_are_hidden()
|
||||
{
|
||||
// Given a user with sensitive preferences
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => ['lastfm_session_key' => 'foo'],
|
||||
]);
|
||||
|
||||
// When I try to access the sensitive preferences
|
||||
$value = $user->preferences['lastfm_session_key'];
|
||||
|
||||
// Then the sensitive preferences are replaced with "hidden"
|
||||
$this->assertEquals('hidden', $value);
|
||||
self::assertEquals('hidden', $value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ namespace Tests\Integration\Services;
|
|||
|
||||
use App\Models\Album;
|
||||
use App\Models\Artist;
|
||||
use App\Models\User;
|
||||
use App\Services\LastfmService;
|
||||
use App\Services\UserPreferenceService;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
@ -28,8 +30,7 @@ class LastfmServiceTest extends TestCase
|
|||
'get' => new Response(200, [], file_get_contents(__DIR__.'../../../blobs/lastfm/artist.xml')),
|
||||
]);
|
||||
|
||||
$api = new LastfmService($client, app(Cache::class), app(Logger::class));
|
||||
$info = $api->getArtistInformation($artist->name);
|
||||
$info = $this->createServiceWithMockedClient($client)->getArtistInformation($artist->name);
|
||||
|
||||
$this->assertEquals([
|
||||
'url' => 'http://www.last.fm/music/Kamelot',
|
||||
|
@ -53,9 +54,7 @@ class LastfmServiceTest extends TestCase
|
|||
'get' => new Response(400, [], file_get_contents(__DIR__.'../../../blobs/lastfm/artist-notfound.xml')),
|
||||
]);
|
||||
|
||||
$api = new LastfmService($client, app(Cache::class), app(Logger::class));
|
||||
|
||||
self::assertNull($api->getArtistInformation($artist->name));
|
||||
self::assertNull($this->createServiceWithMockedClient($client)->getArtistInformation($artist->name));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,8 +73,7 @@ class LastfmServiceTest extends TestCase
|
|||
'get' => new Response(200, [], file_get_contents(__DIR__.'../../../blobs/lastfm/album.xml')),
|
||||
]);
|
||||
|
||||
$api = new LastfmService($client, app(Cache::class), app(Logger::class));
|
||||
$info = $api->getAlbumInformation($album->name, $album->artist->name);
|
||||
$info = $this->createServiceWithMockedClient($client)->getAlbumInformation($album->name, $album->artist->name);
|
||||
|
||||
// Then I get the album's info
|
||||
$this->assertEquals([
|
||||
|
@ -112,8 +110,38 @@ class LastfmServiceTest extends TestCase
|
|||
'get' => new Response(400, [], file_get_contents(__DIR__.'../../../blobs/lastfm/album-notfound.xml')),
|
||||
]);
|
||||
|
||||
$api = new LastfmService($client, app(Cache::class), app(Logger::class));
|
||||
$api = $this->createServiceWithMockedClient($client);
|
||||
|
||||
self::assertNull($api->getAlbumInformation($album->name, $album->artist->name));
|
||||
}
|
||||
|
||||
public function testFetchSessionKeyUsingToken(): void
|
||||
{
|
||||
/** @var Client $client */
|
||||
$client = Mockery::mock(Client::class, [
|
||||
'get' => new Response(200, [], file_get_contents(__DIR__.'../../../blobs/lastfm/session-key.xml')),
|
||||
]);
|
||||
|
||||
self::assertEquals('foo', $this->createServiceWithMockedClient($client)->fetchSessionKeyUsingToken('bar'));
|
||||
}
|
||||
|
||||
public function testIsUserConnected(): void
|
||||
{
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => ['lastfm_session_key' => 'foo'],
|
||||
]);
|
||||
|
||||
self::assertTrue(app(LastfmService::class)->isUserConnected($user));
|
||||
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => [],
|
||||
]);
|
||||
|
||||
self::assertFalse(app(LastfmService::class)->isUserConnected($user));
|
||||
}
|
||||
|
||||
private function createServiceWithMockedClient(Client $client): LastfmService
|
||||
{
|
||||
return new LastfmService($client, app(Cache::class), app(Logger::class), app(UserPreferenceService::class));
|
||||
}
|
||||
}
|
||||
|
|
49
tests/Integration/Services/UserPreferenceServiceTest.php
Normal file
49
tests/Integration/Services/UserPreferenceServiceTest.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Integration\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\UserPreferenceService;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserPreferenceServiceTest extends TestCase
|
||||
{
|
||||
/** @var UserPreferenceService */
|
||||
private $userPreferenceService;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->userPreferenceService = new UserPreferenceService();
|
||||
}
|
||||
|
||||
public function testGet(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => ['foo' => 'bar'],
|
||||
]);
|
||||
|
||||
self::assertEquals('bar', $this->userPreferenceService->get($user, 'foo'));
|
||||
}
|
||||
|
||||
public function testSet(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create();
|
||||
|
||||
$this->userPreferenceService->set($user, 'foo', 'bar');
|
||||
self::assertArraySubset(['foo' => 'bar'], $user->preferences);
|
||||
}
|
||||
|
||||
public function testDelete(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = factory(User::class)->create([
|
||||
'preferences' => ['foo' => 'bar'],
|
||||
]);
|
||||
|
||||
$this->userPreferenceService->delete($user, 'foo');
|
||||
self::assertArrayNotHasKey('foo', $user->preferences);
|
||||
}
|
||||
}
|
|
@ -2,13 +2,50 @@
|
|||
|
||||
namespace Tests\Unit\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\LastfmService;
|
||||
use App\Services\UserPreferenceService;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||
use Illuminate\Log\Logger;
|
||||
use Mockery;
|
||||
use Mockery\Mock;
|
||||
use Mockery\MockInterface;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LastfmServiceTest extends TestCase
|
||||
{
|
||||
/** @var Client */
|
||||
private $client;
|
||||
|
||||
/** @var Cache */
|
||||
private $cache;
|
||||
|
||||
/** @var Logger */
|
||||
private $logger;
|
||||
|
||||
/** @var UserPreferenceService|MockInterface */
|
||||
private $userPreferenceService;
|
||||
|
||||
/** @var LastfmService */
|
||||
private $lastfmService;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->client = Mockery::mock(Client::class);
|
||||
$this->cache = Mockery::mock(Cache::class);
|
||||
$this->logger = Mockery::mock(Logger::class);
|
||||
$this->userPreferenceService = Mockery::mock(UserPreferenceService::class);
|
||||
$this->lastfmService = new LastfmService(
|
||||
$this->client,
|
||||
$this->cache,
|
||||
$this->logger,
|
||||
$this->userPreferenceService
|
||||
);
|
||||
}
|
||||
|
||||
public function testBuildAuthCallParams(): void
|
||||
{
|
||||
/** @var Mock|LastfmService $lastfm */
|
||||
|
@ -39,4 +76,38 @@ class LastfmServiceTest extends TestCase
|
|||
$builtParamsAsString
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetUserSessionKey(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = Mockery::mock(User::class);
|
||||
|
||||
$this->userPreferenceService->shouldReceive('get')
|
||||
->with($user, 'lastfm_session_key')
|
||||
->andReturn('foo');
|
||||
|
||||
self::assertSame('foo', $this->lastfmService->getUserSessionKey($user));
|
||||
}
|
||||
|
||||
public function testSetUserSessionKey(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = Mockery::mock(User::class);
|
||||
|
||||
$this->userPreferenceService->shouldReceive('set')
|
||||
->with($user, 'lastfm_session_key', 'foo');
|
||||
|
||||
$this->lastfmService->setUserSessionKey($user, 'foo');
|
||||
}
|
||||
|
||||
public function testDeleteUserSessionKey(): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = Mockery::mock(User::class);
|
||||
|
||||
$this->userPreferenceService->shouldReceive('delete')
|
||||
->with($user, 'lastfm_session_key');
|
||||
|
||||
$this->lastfmService->deleteUserSessionKey($user);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue